@cloudcli-ai/cloudcli 1.37.1 → 1.37.3

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 (402) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/abnfDiagram-N423BO3Z-CJntskwA.js +1 -0
  3. package/dist/assets/arc-CIfH4uMN.js +1 -0
  4. package/dist/assets/architectureDiagram-T3A2C74G-_IpEkukg.js +36 -0
  5. package/dist/assets/blockDiagram-VBNYF7ZC-BttxrpgZ.js +132 -0
  6. package/dist/assets/c4Diagram-5PPSVZJV-g51dSRr1.js +10 -0
  7. package/dist/assets/channel-C5xU9jMw.js +1 -0
  8. package/dist/assets/chunk-2GRJ4B5K-D_-LbQUa.js +1 -0
  9. package/dist/assets/chunk-2Q5K7J3B-BtlHzwaO.js +1 -0
  10. package/dist/assets/chunk-5RXB4S5H-UzkpvpAT.js +231 -0
  11. package/dist/assets/chunk-5VM5RSS4-BKwx5Gag.js +15 -0
  12. package/dist/assets/chunk-6Q2QTUOP-D_KEBH5f.js +88 -0
  13. package/dist/assets/chunk-GF5L2VYU-rK2DGyto.js +206 -0
  14. package/dist/assets/chunk-JWPE2WC7-CeBl_N9i.js +1 -0
  15. package/dist/assets/chunk-KBJHAD2P-BiQLWVIr.js +1 -0
  16. package/dist/assets/chunk-RYQCIY6F-C1knVGV5.js +1 -0
  17. package/dist/assets/chunk-XXDRQBXY-CtKbJkvF.js +1 -0
  18. package/dist/assets/classDiagram-JCYQIIEL-CRrL3vp7.js +1 -0
  19. package/dist/assets/classDiagram-v2-OCEON4UE-CRrL3vp7.js +1 -0
  20. package/dist/assets/cose-bilkent-JH36ORCC-DjX8y40Z.js +1 -0
  21. package/dist/assets/cynefin-VYW2F7L2-DM6YeRba.js +178 -0
  22. package/dist/assets/cynefinDiagram-MW4NZA55-wZJ-vy5B.js +62 -0
  23. package/dist/assets/cytoscape.esm-C10L9Icf.js +331 -0
  24. package/dist/assets/dagre-VZM6K2ZE-BzP0ejkH.js +4 -0
  25. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  26. package/dist/assets/diagram-7IWD3JNH-BTL_j23J.js +30 -0
  27. package/dist/assets/diagram-B4RE2ZJO-Cf1Norgu.js +3 -0
  28. package/dist/assets/diagram-LBJQPF4R-DPiUEKr-.js +24 -0
  29. package/dist/assets/diagram-Q27KOJAE-CTcTpiz5.js +24 -0
  30. package/dist/assets/diagram-UB23O5K3-DPMSdYm0.js +41 -0
  31. package/dist/assets/ebnfDiagram-BXEA7PRR-7yvD6uiF.js +1 -0
  32. package/dist/assets/erDiagram-JOGREHBK-CfgeDoV6.js +85 -0
  33. package/dist/assets/flowDiagram-UKHOOZJN-B27ng5zu.js +156 -0
  34. package/dist/assets/ganttDiagram-PKOTCBZU-CcC6b_7t.js +292 -0
  35. package/dist/assets/gitGraphDiagram-DS77QQ5N-BX5kPGrO.js +106 -0
  36. package/dist/assets/graph-Cx-EqisW.js +1 -0
  37. package/dist/assets/index-BTDHQ6Id.css +32 -0
  38. package/dist/assets/index-sFfz8iBR.js +4931 -0
  39. package/dist/assets/infoDiagram-6WML65LV-CUP-SlN4.js +2 -0
  40. package/dist/assets/init-Gi6I4Gst.js +1 -0
  41. package/dist/assets/ishikawaDiagram-WSZJBQD7-BTTDhOpX.js +70 -0
  42. package/dist/assets/journeyDiagram-NVQOT4AX-ARXcc61m.js +139 -0
  43. package/dist/assets/kanban-definition-27J2QSJJ-BieMpqMA.js +89 -0
  44. package/dist/assets/layout-D6BstSzF.js +1 -0
  45. package/dist/assets/linear-61vxjRnP.js +1 -0
  46. package/dist/assets/map-CV9uif0g.js +1 -0
  47. package/dist/assets/mermaid.core-nhnwkfQx.js +312 -0
  48. package/dist/assets/mindmap-definition-FAOFIHXS-Cm6x5vT1.js +96 -0
  49. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  50. package/dist/assets/pegDiagram-VL7TDLO6-CcYBq_9H.js +1 -0
  51. package/dist/assets/pieDiagram-7S7Q4E2Y-CfvIjfzo.js +39 -0
  52. package/dist/assets/quadrantDiagram-CIZ2JOQS-SgYoWPNb.js +7 -0
  53. package/dist/assets/railroadDiagram-AXF67PYL-D2Mu5E_f.js +1 -0
  54. package/dist/assets/requirementDiagram-LRYGKXZP-Azwe_k4Q.js +84 -0
  55. package/dist/assets/sankeyDiagram-W5VNT64P-DN1Ju3PA.js +40 -0
  56. package/dist/assets/sequenceDiagram-SI44F4Z6-Bj4qC34S.js +162 -0
  57. package/dist/assets/server.browser-CtX3Hdl5.js +27 -0
  58. package/dist/assets/sizeCapture-X5ZJPWSS-Co4PdklG.js +1 -0
  59. package/dist/assets/stateDiagram-OKZ733FA-nOvL9dRC.js +1 -0
  60. package/dist/assets/stateDiagram-v2-UEYNNEHI-DNv8ppw7.js +1 -0
  61. package/dist/assets/swimlanes-SLNWSIFB-CCK3wMid.js +2 -0
  62. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DnfbNQEp.js +8 -0
  63. package/dist/assets/timeline-definition-Z64GVDOM-BC29RNFm.js +120 -0
  64. package/dist/assets/{vendor-codemirror-OwyKSvPE.js → vendor-codemirror-CYrSt7-U.js} +18 -18
  65. package/dist/assets/vennDiagram-T6HMQDX7-pZlZCtEo.js +34 -0
  66. package/dist/assets/wardleyDiagram-T6FBY63Y-De8k2-zM.js +78 -0
  67. package/dist/assets/xychartDiagram-ELKLHX3M-Bk8ykH0w.js +7 -0
  68. package/dist/index.html +3 -3
  69. package/dist-server/server/index.js +8 -5
  70. package/dist-server/server/index.js.map +1 -1
  71. package/dist-server/server/modules/agent/agent.module.js +2 -1
  72. package/dist-server/server/modules/agent/agent.module.js.map +1 -1
  73. package/dist-server/server/modules/agent/agent.routes.js +2 -2
  74. package/dist-server/server/modules/agent/agent.routes.js.map +1 -1
  75. package/dist-server/server/modules/agent/tests/agent.routes.test.js +30 -1
  76. package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -1
  77. package/dist-server/server/modules/auth/auth.middleware.js +1 -1
  78. package/dist-server/server/modules/auth/auth.middleware.js.map +1 -1
  79. package/dist-server/server/modules/browser-use/browser-use-runtime.js +10 -0
  80. package/dist-server/server/modules/browser-use/browser-use-runtime.js.map +1 -0
  81. package/dist-server/server/modules/browser-use/browser-use.routes.js +39 -33
  82. package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -1
  83. package/dist-server/server/modules/browser-use/browser-use.service.js +3 -6
  84. package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
  85. package/dist-server/server/modules/browser-use/index.js +2 -0
  86. package/dist-server/server/modules/browser-use/index.js.map +1 -1
  87. package/dist-server/server/modules/cli/cli.js +9 -3
  88. package/dist-server/server/modules/cli/cli.js.map +1 -1
  89. package/dist-server/server/modules/cli/cli.module.js +0 -1
  90. package/dist-server/server/modules/cli/cli.module.js.map +1 -1
  91. package/dist-server/server/modules/cli/cli.service.js +0 -18
  92. package/dist-server/server/modules/cli/cli.service.js.map +1 -1
  93. package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +154 -0
  94. package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js.map +1 -0
  95. package/dist-server/server/modules/cli/tests/cli.service.test.js +0 -3
  96. package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -1
  97. package/dist-server/server/modules/database/connection.js +1 -1
  98. package/dist-server/server/modules/database/connection.js.map +1 -1
  99. package/dist-server/server/modules/database/index.js +5 -0
  100. package/dist-server/server/modules/database/index.js.map +1 -1
  101. package/dist-server/server/modules/database/migrations.js +32 -1
  102. package/dist-server/server/modules/database/migrations.js.map +1 -1
  103. package/dist-server/server/modules/database/repositories/scheduled-messages.db.js +71 -0
  104. package/dist-server/server/modules/database/repositories/scheduled-messages.db.js.map +1 -0
  105. package/dist-server/server/modules/database/repositories/session-drafts.db.js +105 -0
  106. package/dist-server/server/modules/database/repositories/session-drafts.db.js.map +1 -0
  107. package/dist-server/server/modules/database/repositories/sessions.db.js +137 -5
  108. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  109. package/dist-server/server/modules/database/repositories/user-preferences.db.js +65 -0
  110. package/dist-server/server/modules/database/repositories/user-preferences.db.js.map +1 -0
  111. package/dist-server/server/modules/database/schema.js +92 -0
  112. package/dist-server/server/modules/database/schema.js.map +1 -1
  113. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +39 -0
  114. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
  115. package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js +105 -0
  116. package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js.map +1 -0
  117. package/dist-server/server/modules/file-tree/file-tree.service.js +18 -10
  118. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -1
  119. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +62 -11
  120. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -1
  121. package/dist-server/server/modules/git/git-branch.service.js +15 -0
  122. package/dist-server/server/modules/git/git-branch.service.js.map +1 -0
  123. package/dist-server/server/modules/git/git.routes.js +15 -7
  124. package/dist-server/server/modules/git/git.routes.js.map +1 -1
  125. package/dist-server/server/modules/git/tests/git-branch.service.test.js +52 -0
  126. package/dist-server/server/modules/git/tests/git-branch.service.test.js.map +1 -0
  127. package/dist-server/server/modules/git/tests/git-init.routes.test.js +84 -0
  128. package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -1
  129. package/dist-server/server/modules/notifications/index.js +3 -1
  130. package/dist-server/server/modules/notifications/index.js.map +1 -1
  131. package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +22 -1
  132. package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -1
  133. package/dist-server/server/modules/projects/services/project-delete.service.js +12 -1
  134. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -1
  135. package/dist-server/server/modules/projects/services/project-star.service.js +2 -2
  136. package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -1
  137. package/dist-server/server/modules/providers/index.js +3 -0
  138. package/dist-server/server/modules/providers/index.js.map +1 -1
  139. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +20 -1
  140. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  141. package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js +46 -0
  142. package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js.map +1 -0
  143. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +35 -6
  144. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  145. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +422 -86
  146. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -1
  147. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +388 -50
  148. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  149. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +4 -1
  150. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -1
  151. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  152. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  153. package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +204 -0
  154. package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -0
  155. package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js +32 -0
  156. package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js.map +1 -0
  157. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +16 -0
  158. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
  159. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +60 -49
  160. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -1
  161. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +8 -0
  162. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  163. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +1565 -432
  164. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  165. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  166. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  167. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js +8 -6
  168. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -1
  169. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
  170. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +258 -6
  171. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
  172. package/dist-server/server/modules/providers/provider.routes.js +29 -0
  173. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  174. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +14 -0
  175. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
  176. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +139 -35
  177. package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -1
  178. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +63 -7
  179. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
  180. package/dist-server/server/modules/providers/services/session-history-cache.service.js +87 -0
  181. package/dist-server/server/modules/providers/services/session-history-cache.service.js.map +1 -0
  182. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +105 -32
  183. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
  184. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +3 -60
  185. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  186. package/dist-server/server/modules/providers/services/sessions.service.js +179 -9
  187. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  188. package/dist-server/server/modules/providers/tests/claude-auth.test.js +52 -0
  189. package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -1
  190. package/dist-server/server/modules/providers/tests/claude-models.test.js +39 -0
  191. package/dist-server/server/modules/providers/tests/claude-models.test.js.map +1 -0
  192. package/dist-server/server/modules/providers/tests/claude-sessions.test.js +465 -39
  193. package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -1
  194. package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js +16 -0
  195. package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js.map +1 -0
  196. package/dist-server/server/modules/providers/tests/claude-token-budget.test.js +85 -0
  197. package/dist-server/server/modules/providers/tests/claude-token-budget.test.js.map +1 -0
  198. package/dist-server/server/modules/providers/tests/codex-message-editing.test.js +338 -0
  199. package/dist-server/server/modules/providers/tests/codex-message-editing.test.js.map +1 -0
  200. package/dist-server/server/modules/providers/tests/codex-runtime.test.js +51 -0
  201. package/dist-server/server/modules/providers/tests/codex-runtime.test.js.map +1 -0
  202. package/dist-server/server/modules/providers/tests/codex-session-fork.test.js +54 -0
  203. package/dist-server/server/modules/providers/tests/codex-session-fork.test.js.map +1 -0
  204. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +304 -15
  205. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
  206. package/dist-server/server/modules/providers/tests/opencode-models.test.js +117 -4
  207. package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
  208. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +164 -1
  209. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -1
  210. package/dist-server/server/modules/providers/tests/provider.routes.test.js +35 -0
  211. package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -1
  212. package/dist-server/server/modules/providers/tests/session-fork.test.js +113 -0
  213. package/dist-server/server/modules/providers/tests/session-fork.test.js.map +1 -0
  214. package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js +120 -0
  215. package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js.map +1 -0
  216. package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js +90 -0
  217. package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js.map +1 -0
  218. package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js +122 -0
  219. package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js.map +1 -0
  220. package/dist-server/server/modules/providers/tests/sessions.service.test.js +45 -1
  221. package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -1
  222. package/dist-server/server/modules/providers/tests/skills.test.js +15 -3
  223. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  224. package/dist-server/server/modules/scheduled-messages/index.js +5 -0
  225. package/dist-server/server/modules/scheduled-messages/index.js.map +1 -0
  226. package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js +47 -0
  227. package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js.map +1 -0
  228. package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js +163 -0
  229. package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js.map +1 -0
  230. package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js +95 -0
  231. package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js.map +1 -0
  232. package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js +255 -0
  233. package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js.map +1 -0
  234. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +23 -23
  235. package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -1
  236. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +48 -0
  237. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -1
  238. package/dist-server/server/modules/user/tests/user.service.test.js +70 -0
  239. package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -1
  240. package/dist-server/server/modules/user/user.module.js +10 -1
  241. package/dist-server/server/modules/user/user.module.js.map +1 -1
  242. package/dist-server/server/modules/user/user.routes.js +44 -0
  243. package/dist-server/server/modules/user/user.routes.js.map +1 -1
  244. package/dist-server/server/modules/user/user.service.js +75 -0
  245. package/dist-server/server/modules/user/user.service.js.map +1 -1
  246. package/dist-server/server/modules/voice/tests/voice.service.test.js +3 -2
  247. package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -1
  248. package/dist-server/server/modules/websocket/index.js +7 -0
  249. package/dist-server/server/modules/websocket/index.js.map +1 -1
  250. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +10 -44
  251. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -1
  252. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +35 -5
  253. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -1
  254. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +166 -9
  255. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  256. package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js +94 -0
  257. package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js.map +1 -0
  258. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +9 -3
  259. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  260. package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js +263 -0
  261. package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js.map +1 -0
  262. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +29 -3
  263. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -1
  264. package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js +106 -0
  265. package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js.map +1 -0
  266. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +80 -0
  267. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -1
  268. package/dist-server/server/shared/claude-cli-path.js +22 -5
  269. package/dist-server/server/shared/claude-cli-path.js.map +1 -1
  270. package/dist-server/server/shared/index.js +3 -0
  271. package/dist-server/server/shared/index.js.map +1 -0
  272. package/dist-server/server/shared/message-unification.js +376 -0
  273. package/dist-server/server/shared/message-unification.js.map +1 -0
  274. package/dist-server/server/shared/tests/claude-cli-path.test.js +45 -1
  275. package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -1
  276. package/dist-server/server/shared/tests/message-unification.test.js +174 -0
  277. package/dist-server/server/shared/tests/message-unification.test.js.map +1 -0
  278. package/dist-server/server/shared/utils.js +42 -0
  279. package/dist-server/server/shared/utils.js.map +1 -1
  280. package/package.json +23 -16
  281. package/scripts/promote-dist-server.mjs +50 -0
  282. package/server/index.ts +12 -6
  283. package/server/modules/agent/agent.module.ts +2 -1
  284. package/server/modules/agent/agent.routes.ts +2 -2
  285. package/server/modules/agent/tests/agent.routes.test.ts +33 -1
  286. package/server/modules/auth/auth.middleware.ts +2 -2
  287. package/server/modules/browser-use/browser-use-runtime.ts +10 -0
  288. package/server/modules/browser-use/browser-use.routes.ts +96 -33
  289. package/server/modules/browser-use/browser-use.service.ts +5 -8
  290. package/server/modules/browser-use/index.ts +3 -0
  291. package/server/modules/cli/cli.module.ts +0 -1
  292. package/server/modules/cli/cli.service.ts +0 -20
  293. package/server/modules/cli/cli.ts +9 -3
  294. package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +186 -0
  295. package/server/modules/cli/tests/cli.service.test.ts +0 -3
  296. package/server/modules/database/connection.ts +2 -1
  297. package/server/modules/database/index.ts +10 -0
  298. package/server/modules/database/migrations.ts +37 -0
  299. package/server/modules/database/repositories/scheduled-messages.db.ts +127 -0
  300. package/server/modules/database/repositories/session-drafts.db.ts +171 -0
  301. package/server/modules/database/repositories/sessions.db.ts +196 -3
  302. package/server/modules/database/repositories/user-preferences.db.ts +80 -0
  303. package/server/modules/database/schema.ts +96 -0
  304. package/server/modules/database/tests/sessions.db.integration.test.ts +52 -0
  305. package/server/modules/database/tests/user-preferences.db.integration.test.ts +135 -0
  306. package/server/modules/file-tree/file-tree.service.ts +21 -10
  307. package/server/modules/file-tree/tests/file-tree.service.test.ts +65 -11
  308. package/server/modules/git/git-branch.service.ts +43 -0
  309. package/server/modules/git/git.routes.ts +16 -9
  310. package/server/modules/git/tests/git-branch.service.test.ts +60 -0
  311. package/server/modules/git/tests/git-init.routes.test.ts +83 -0
  312. package/server/modules/notifications/index.ts +2 -0
  313. package/server/modules/notifications/services/notification-orchestrator.service.js +24 -1
  314. package/server/modules/projects/services/project-delete.service.ts +13 -1
  315. package/server/modules/projects/services/project-star.service.ts +2 -2
  316. package/server/modules/providers/index.ts +4 -0
  317. package/server/modules/providers/list/claude/claude-auth.provider.ts +21 -1
  318. package/server/modules/providers/list/claude/claude-fork.provider.ts +57 -0
  319. package/server/modules/providers/list/claude/claude-models.provider.ts +38 -6
  320. package/server/modules/providers/list/claude/claude-runtime.provider.js +463 -93
  321. package/server/modules/providers/list/claude/claude-sessions.provider.ts +478 -54
  322. package/server/modules/providers/list/claude/claude-skills.provider.ts +4 -1
  323. package/server/modules/providers/list/claude/claude.provider.ts +3 -0
  324. package/server/modules/providers/list/codex/codex-app-server.client.ts +243 -0
  325. package/server/modules/providers/list/codex/codex-fork.provider.ts +40 -0
  326. package/server/modules/providers/list/codex/codex-models.provider.ts +16 -0
  327. package/server/modules/providers/list/codex/{codex-runtime.provider.js → codex-runtime.provider.ts} +93 -66
  328. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +9 -0
  329. package/server/modules/providers/list/codex/codex-sessions.provider.ts +1806 -477
  330. package/server/modules/providers/list/codex/codex.provider.ts +3 -0
  331. package/server/modules/providers/list/cursor/cursor-runtime.provider.js +8 -6
  332. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +0 -1
  333. package/server/modules/providers/list/opencode/opencode-models.provider.ts +279 -6
  334. package/server/modules/providers/provider.routes.ts +36 -0
  335. package/server/modules/providers/services/provider-capabilities.service.ts +23 -0
  336. package/server/modules/providers/services/provider-token-usage.service.ts +166 -39
  337. package/server/modules/providers/services/session-conversations-search.service.ts +94 -7
  338. package/server/modules/providers/services/session-history-cache.service.ts +139 -0
  339. package/server/modules/providers/services/session-synchronizer.service.ts +125 -38
  340. package/server/modules/providers/services/sessions-watcher.service.ts +3 -64
  341. package/server/modules/providers/services/sessions.service.ts +201 -9
  342. package/server/modules/providers/tests/claude-auth.test.ts +58 -0
  343. package/server/modules/providers/tests/claude-models.test.ts +87 -0
  344. package/server/modules/providers/tests/claude-sessions.test.ts +552 -40
  345. package/server/modules/providers/tests/claude-subagent-echo.test.ts +25 -0
  346. package/server/modules/providers/tests/claude-token-budget.test.ts +104 -0
  347. package/server/modules/providers/tests/codex-message-editing.test.ts +419 -0
  348. package/server/modules/providers/tests/codex-runtime.test.ts +58 -0
  349. package/server/modules/providers/tests/codex-session-fork.test.ts +59 -0
  350. package/server/modules/providers/tests/codex-sessions.test.ts +337 -15
  351. package/server/modules/providers/tests/opencode-models.test.ts +166 -8
  352. package/server/modules/providers/tests/provider-token-usage.service.test.ts +188 -1
  353. package/server/modules/providers/tests/provider.routes.test.ts +61 -0
  354. package/server/modules/providers/tests/session-fork.test.ts +173 -0
  355. package/server/modules/providers/tests/session-history-cache.service.test.ts +143 -0
  356. package/server/modules/providers/tests/session-orphan-prune.test.ts +107 -0
  357. package/server/modules/providers/tests/session-synchronizer-coalescing.test.ts +136 -0
  358. package/server/modules/providers/tests/sessions.service.test.ts +67 -1
  359. package/server/modules/providers/tests/skills.test.ts +21 -5
  360. package/server/modules/scheduled-messages/index.ts +8 -0
  361. package/server/modules/scheduled-messages/scheduled-messages.routes.ts +68 -0
  362. package/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.ts +203 -0
  363. package/server/modules/scheduled-messages/services/scheduled-messages.service.ts +121 -0
  364. package/server/modules/scheduled-messages/tests/scheduled-messages.test.ts +310 -0
  365. package/server/modules/taskmaster/taskmaster.routes.ts +23 -33
  366. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +57 -0
  367. package/server/modules/user/tests/user.service.test.ts +90 -0
  368. package/server/modules/user/user.module.ts +10 -1
  369. package/server/modules/user/user.routes.ts +44 -0
  370. package/server/modules/user/user.service.ts +105 -0
  371. package/server/modules/voice/tests/voice.service.test.ts +3 -2
  372. package/server/modules/websocket/index.ts +8 -0
  373. package/server/modules/websocket/services/chat-run-registry.service.ts +17 -50
  374. package/server/modules/websocket/services/chat-session-writer.service.ts +36 -6
  375. package/server/modules/websocket/services/chat-websocket.service.ts +244 -15
  376. package/server/modules/websocket/services/session-upsert-broadcast.service.ts +108 -0
  377. package/server/modules/websocket/services/shell-websocket.service.ts +10 -3
  378. package/server/modules/websocket/tests/chat-edit-send.test.ts +309 -0
  379. package/server/modules/websocket/tests/chat-run-registry.test.ts +34 -3
  380. package/server/modules/websocket/tests/session-upsert-broadcast.test.ts +138 -0
  381. package/server/modules/websocket/tests/shell-websocket.service.test.ts +108 -0
  382. package/server/shared/claude-cli-path.ts +24 -6
  383. package/server/shared/index.ts +3 -0
  384. package/server/shared/interfaces.ts +62 -0
  385. package/server/shared/message-unification.ts +449 -0
  386. package/server/shared/tests/claude-cli-path.test.ts +58 -1
  387. package/server/shared/tests/message-unification.test.ts +218 -0
  388. package/server/shared/types.ts +123 -3
  389. package/server/shared/utils.ts +50 -0
  390. package/server/tsconfig.json +6 -2
  391. package/README.de.md +0 -257
  392. package/README.ja.md +0 -249
  393. package/README.ko.md +0 -249
  394. package/README.ru.md +0 -257
  395. package/README.tr.md +0 -258
  396. package/README.zh-CN.md +0 -249
  397. package/README.zh-TW.md +0 -249
  398. package/dist/assets/index-D3jfzuKN.css +0 -32
  399. package/dist/assets/index-DTMWjJj8.js +0 -1550
  400. package/dist-server/server/constants/config.js +0 -6
  401. package/dist-server/server/constants/config.js.map +0 -1
  402. package/server/constants/config.ts +0 -5
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import type { WebSocket } from 'ws';
4
4
 
5
5
  import { sessionsDb } from '@/modules/database/index.js';
6
- import { providerModelsService } from '@/modules/providers/index.js';
6
+ import { providerModelsService, sessionsService } from '@/modules/providers/index.js';
7
7
  import { chatRunRegistry } from '@/modules/websocket/services/chat-run-registry.service.js';
8
8
  import { connectedClients, WS_OPEN_STATE } from '@/modules/websocket/services/websocket-state.service.js';
9
9
  import {
@@ -64,7 +64,7 @@ export function filterImagesToUploadStore(
64
64
  }
65
65
 
66
66
  /** Application boundary for dispatching provider runs and approvals. */
67
- type ProviderRuntimeGateway = {
67
+ export type ProviderRuntimeGateway = {
68
68
  hasRuntime(provider: string): boolean;
69
69
  run(
70
70
  provider: LLMProvider,
@@ -149,10 +149,34 @@ async function handleChatSend(
149
149
  data: AnyRecord,
150
150
  dependencies: ChatWebSocketDependencies
151
151
  ): Promise<void> {
152
+ const resolved = resolveSendTarget(ws, data, dependencies, 'chat.send');
153
+ if (!resolved) {
154
+ return;
155
+ }
156
+
157
+ await dispatchRun(ws, userId, resolved.sessionId, resolved.session, data, dependencies);
158
+ }
159
+
160
+ type ResolvedSendTarget = {
161
+ sessionId: string;
162
+ session: NonNullable<ReturnType<typeof sessionsDb.getSessionById>>;
163
+ provider: LLMProvider;
164
+ };
165
+
166
+ /**
167
+ * Shared front half of `chat.send` and `chat.edit-send`: the session row and
168
+ * provider come from the database, never from the client.
169
+ */
170
+ function resolveSendTarget(
171
+ ws: WebSocket,
172
+ data: AnyRecord,
173
+ dependencies: ChatWebSocketDependencies,
174
+ frameName: string,
175
+ ): ResolvedSendTarget | null {
152
176
  const sessionId = readRequiredSessionId(data);
153
177
  if (!sessionId) {
154
- sendProtocolError(ws, 'SESSION_ID_REQUIRED', 'chat.send requires a sessionId.');
155
- return;
178
+ sendProtocolError(ws, 'SESSION_ID_REQUIRED', `${frameName} requires a sessionId.`);
179
+ return null;
156
180
  }
157
181
 
158
182
  const session = sessionsDb.getSessionById(sessionId);
@@ -163,15 +187,36 @@ async function handleChatSend(
163
187
  `Session "${sessionId}" was not found. Create it via POST /api/providers/sessions first.`,
164
188
  sessionId
165
189
  );
166
- return;
190
+ return null;
167
191
  }
168
192
 
169
193
  const provider = session.provider as LLMProvider;
170
194
  if (!dependencies.runtime.hasRuntime(provider)) {
171
195
  sendProtocolError(ws, 'UNSUPPORTED_PROVIDER', `Provider "${provider}" is not available.`, sessionId);
172
- return;
196
+ return null;
173
197
  }
174
198
 
199
+ return { sessionId, session, provider };
200
+ }
201
+
202
+ /**
203
+ * Registers the run and hands the turn to the provider runtime.
204
+ *
205
+ * `extraRuntimeOptions` is how an edited message asks the provider to resume
206
+ * partway instead of continuing from the tip; a normal send passes nothing.
207
+ */
208
+ async function dispatchRun(
209
+ ws: WebSocket | null,
210
+ userId: string | number | null,
211
+ sessionId: string,
212
+ session: NonNullable<ReturnType<typeof sessionsDb.getSessionById>>,
213
+ data: AnyRecord,
214
+ dependencies: ChatWebSocketDependencies,
215
+ extraRuntimeOptions: AnyRecord = {},
216
+ beforeRun?: (run: NonNullable<ReturnType<typeof chatRunRegistry.startRun>>) => void | Promise<void>,
217
+ ): Promise<{ started: boolean; error: string | null }> {
218
+ const provider = session.provider as LLMProvider;
219
+
175
220
  const run = chatRunRegistry.startRun({
176
221
  appSessionId: sessionId,
177
222
  provider,
@@ -181,13 +226,15 @@ async function handleChatSend(
181
226
  });
182
227
 
183
228
  if (!run) {
184
- sendProtocolError(
185
- ws,
186
- 'RUN_IN_PROGRESS',
187
- `Session "${sessionId}" already has a run in progress.`,
188
- sessionId
189
- );
190
- return;
229
+ if (ws) {
230
+ sendProtocolError(
231
+ ws,
232
+ 'RUN_IN_PROGRESS',
233
+ `Session "${sessionId}" already has a run in progress.`,
234
+ sessionId
235
+ );
236
+ }
237
+ return { started: false, error: 'A run is already in progress for this session.' };
191
238
  }
192
239
 
193
240
  const clientOptions = (data.options ?? {}) as AnyRecord;
@@ -221,6 +268,7 @@ async function handleChatSend(
221
268
  // app session id.
222
269
  const runtimeOptions: AnyRecord = {
223
270
  ...clientOptions,
271
+ ...extraRuntimeOptions,
224
272
  // Attachments are re-validated server-side: only direct children of the
225
273
  // global upload store may reach provider runtimes or their file tools.
226
274
  attachments: uniqueAttachments,
@@ -231,11 +279,17 @@ async function handleChatSend(
231
279
  projectPath: session.project_path ?? clientOptions.projectPath,
232
280
  };
233
281
 
282
+ let failure: string | null = null;
234
283
  try {
284
+ // Runs only now that the session is reserved, because an edit rewinds the
285
+ // conversation here and a rewind for a run that was never admitted cannot
286
+ // be taken back. Inside the try so a rewind that throws still releases the
287
+ // run instead of leaving the session processing forever.
288
+ await beforeRun?.(run);
235
289
  await dependencies.runtime.run(provider, command, runtimeOptions, run.writer);
236
290
  } catch (error) {
237
- const message = error instanceof Error ? error.message : String(error);
238
- console.error(`[Chat] Provider runtime "${provider}" failed`, { sessionId, error: message });
291
+ failure = error instanceof Error ? error.message : String(error);
292
+ console.error(`[Chat] Provider runtime "${provider}" failed`, { sessionId, error: failure });
239
293
  } finally {
240
294
  // Safety net: a runtime that crashed (or resolved) without emitting its
241
295
  // terminal `complete` would otherwise leave the session stuck in
@@ -244,6 +298,113 @@ async function handleChatSend(
244
298
  // settles, and the session-keyed completeRun would kill that new run.
245
299
  chatRunRegistry.completeRunIfCurrent(run, { exitCode: 1 });
246
300
  }
301
+
302
+ return { started: true, error: failure };
303
+ }
304
+
305
+ /**
306
+ * Handles `chat.edit-send`: replaces an already-sent message and everything
307
+ * after it with a new turn.
308
+ *
309
+ * Nothing is deleted. The provider resumes the conversation partway and
310
+ * appends the replacement, so the abandoned attempt stays in the transcript
311
+ * file and is simply no longer part of the live conversation — the same shape
312
+ * Claude Code's rewind and Codex's fork-with-cut-point produce.
313
+ */
314
+ async function handleChatEditSend(
315
+ ws: WebSocket,
316
+ userId: string | number | null,
317
+ data: AnyRecord,
318
+ dependencies: ChatWebSocketDependencies
319
+ ): Promise<void> {
320
+ const resolved = resolveSendTarget(ws, data, dependencies, 'chat.edit-send');
321
+ if (!resolved) {
322
+ return;
323
+ }
324
+
325
+ const { sessionId, session, provider } = resolved;
326
+ const anchorId = typeof data.anchorId === 'string' ? data.anchorId.trim() : '';
327
+ if (!anchorId) {
328
+ sendProtocolError(ws, 'ANCHOR_REQUIRED', 'chat.edit-send requires the anchorId of the message being replaced.', sessionId);
329
+ return;
330
+ }
331
+
332
+ let resumeThroughId: string | null;
333
+ try {
334
+ const anchor = await sessionsService.resolveEditAnchor(sessionId, anchorId);
335
+ if (!anchor) {
336
+ sendProtocolError(
337
+ ws,
338
+ 'EDIT_NOT_SUPPORTED',
339
+ `Provider "${provider}" cannot replace an already-sent message.`,
340
+ sessionId
341
+ );
342
+ return;
343
+ }
344
+ if (!anchor.found) {
345
+ sendProtocolError(ws, 'ANCHOR_NOT_FOUND', 'That message is no longer in the transcript.', sessionId);
346
+ return;
347
+ }
348
+ resumeThroughId = anchor.resumeThroughId;
349
+ } catch (error) {
350
+ const message = error instanceof Error ? error.message : String(error);
351
+ sendProtocolError(ws, 'ANCHOR_LOOKUP_FAILED', `Could not read the transcript: ${message}`, sessionId);
352
+ return;
353
+ }
354
+
355
+ // Providers split here on what their runtime can do. Claude resumes its
356
+ // transcript partway, so the anchor rides along as a run option. Codex
357
+ // cannot — a thread only grows — so the conversation is rewound on disk and
358
+ // the run that follows is an ordinary resume of whatever the session then
359
+ // points at. Which of the two applies is decided here; the rewind itself
360
+ // waits until the run has actually been admitted.
361
+ const rewinds = sessionsService.providerRewindsForEdit(sessionId);
362
+
363
+ await dispatchRun(
364
+ ws,
365
+ userId,
366
+ sessionId,
367
+ session,
368
+ data,
369
+ dependencies,
370
+ // `null` is meaningful: the edited turn was the first prompt, so the
371
+ // conversation starts over instead of resuming.
372
+ rewinds
373
+ ? {}
374
+ : { resumeAnchorId: resumeThroughId ?? undefined, resumeFromScratch: resumeThroughId === null },
375
+ async (run) => {
376
+ // Emitted through the run's writer so it is sequenced and replayed like
377
+ // any other event — a second tab watching this session has to truncate
378
+ // too.
379
+ //
380
+ // Before the rewind, not after it. A rewind that has to branch spawns a
381
+ // process and waits on a JSON-RPC round trip, and holding the frame
382
+ // until that came back left the message the user had just edited away
383
+ // sitting on screen for about a second — the very flicker this feature
384
+ // exists to avoid. Announcing first is safe because a rewind that fails
385
+ // still ends the run, and the terminal `complete` makes every client
386
+ // re-read the transcript, which puts back anything that turned out not
387
+ // to have been replaced after all.
388
+ run.writer.send({
389
+ kind: 'history_truncated',
390
+ provider,
391
+ sessionId,
392
+ anchorId,
393
+ });
394
+
395
+ if (rewinds) {
396
+ try {
397
+ await sessionsService.rewindSessionForEdit(sessionId, resumeThroughId);
398
+ } catch (error) {
399
+ const message = error instanceof Error ? error.message : String(error);
400
+ sendProtocolError(ws, 'EDIT_REWIND_FAILED', `Could not rewind the conversation: ${message}`, sessionId);
401
+ // Ends the run before the provider is asked to continue a
402
+ // conversation that was not rewound after all.
403
+ throw error;
404
+ }
405
+ }
406
+ },
407
+ );
247
408
  }
248
409
 
249
410
  /**
@@ -374,6 +535,71 @@ function handlePermissionResponse(data: AnyRecord, dependencies: ChatWebSocketDe
374
535
  * (`chat_subscribed`, `session_upserted`, `loading_progress`,
375
536
  * `protocol_error`).
376
537
  */
538
+ /**
539
+ * Runs a turn for a session with no client attached.
540
+ *
541
+ * Used by scheduled messages, which fire from a timer: there is no socket to
542
+ * report errors to and no audience to stream to. The run is registered exactly
543
+ * like an interactive one, so anyone who opens the session while it is going
544
+ * subscribes and replays it from the start, and the session shows as busy
545
+ * everywhere in the meantime.
546
+ *
547
+ * Resolves when the provider run settles. Returns false when the session has
548
+ * gone away or is busy without `interruptActiveRun`, which the caller reports
549
+ * on the schedule.
550
+ */
551
+ export async function runDetachedChatTurn(
552
+ input: {
553
+ sessionId: string;
554
+ userId: string | number | null;
555
+ content: string;
556
+ options?: AnyRecord;
557
+ /**
558
+ * Aborts a run already in progress instead of refusing to start. A
559
+ * scheduled message sets this: the user picked the time knowing it might
560
+ * land mid-run, so the timer outranks whatever is running.
561
+ */
562
+ interruptActiveRun?: boolean;
563
+ },
564
+ dependencies: ChatWebSocketDependencies,
565
+ ): Promise<{ started: boolean; error: string | null }> {
566
+ const session = sessionsDb.getSessionById(input.sessionId);
567
+ if (!session) {
568
+ return { started: false, error: 'The session no longer exists.' };
569
+ }
570
+
571
+ const provider = session.provider as LLMProvider;
572
+ if (!dependencies.runtime.hasRuntime(provider)) {
573
+ return { started: false, error: `Provider "${provider}" is not available.` };
574
+ }
575
+
576
+ const activeRun = chatRunRegistry.getRun(input.sessionId);
577
+ if (activeRun && activeRun.status === 'running') {
578
+ if (!input.interruptActiveRun) {
579
+ return { started: false, error: 'A run was already in progress for this session.' };
580
+ }
581
+ // Same shape as `chat.abort`: cancel the provider run and emit the
582
+ // terminal `complete` on its behalf, so every watching client sees the
583
+ // interrupted run end before this turn's stream begins. The interrupted
584
+ // run's own dispatch settles later through completeRunIfCurrent, which is
585
+ // scoped to that run and cannot touch the one started here.
586
+ const aborted = await dependencies.runtime.abort(activeRun.provider, input.sessionId);
587
+ chatRunRegistry.completeRun(input.sessionId, {
588
+ exitCode: aborted ? 0 : 1,
589
+ aborted: true,
590
+ });
591
+ }
592
+
593
+ return dispatchRun(
594
+ null,
595
+ input.userId,
596
+ input.sessionId,
597
+ session,
598
+ { sessionId: input.sessionId, content: input.content, options: input.options ?? {} },
599
+ dependencies,
600
+ );
601
+ }
602
+
377
603
  export function handleChatConnection(
378
604
  ws: WebSocket,
379
605
  request: AuthenticatedWebSocketRequest,
@@ -395,6 +621,9 @@ export function handleChatConnection(
395
621
  const messageType = typeof data.type === 'string' ? data.type : '';
396
622
 
397
623
  switch (messageType) {
624
+ case 'chat.edit-send':
625
+ await handleChatEditSend(ws, userId, data, dependencies);
626
+ return;
398
627
  case 'chat.send':
399
628
  await handleChatSend(ws, userId, data, dependencies);
400
629
  return;
@@ -0,0 +1,108 @@
1
+ import path from 'node:path';
2
+
3
+ import { projectsDb, sessionsDb } from '@/modules/database/index.js';
4
+ import { generateDisplayName } from '@/modules/projects/index.js';
5
+ import { connectedClients, WS_OPEN_STATE } from '@/modules/websocket/services/websocket-state.service.js';
6
+ import type { SessionUpsertedEvent } from '@/shared/types.js';
7
+
8
+ /**
9
+ * The single producer of the `session_upserted` delta.
10
+ *
11
+ * The event carries everything a sidebar needs to upsert a session in place
12
+ * (its summary plus the owning project's metadata), so clients never refetch
13
+ * the whole project list because one transcript changed on disk.
14
+ *
15
+ * It used to be built in two places — the on-disk sessions watcher and the
16
+ * chat run registry — and only the registry's copy set `providerSessionId`.
17
+ * That field is how the client notices a row it is showing has been merged
18
+ * into its canonical app-session row, so a merge announced by any other path
19
+ * left a stale duplicate in the sidebar. One builder, one shape.
20
+ */
21
+ async function buildSessionUpsertedEvent(
22
+ sessionIdOrProviderSessionId: string,
23
+ ): Promise<SessionUpsertedEvent | null> {
24
+ // Resolving by provider id first covers the watcher, which only ever sees
25
+ // the id written in the transcript. For a row where the two ids are equal
26
+ // — legacy rows, and any session indexed from disk before its mapping
27
+ // existed — both lookups land on the same row anyway.
28
+ const row = sessionsDb.getSessionByProviderSessionId(sessionIdOrProviderSessionId)
29
+ ?? sessionsDb.getSessionById(sessionIdOrProviderSessionId);
30
+ if (!row || row.isArchived) {
31
+ return null;
32
+ }
33
+
34
+ const projectPath = row.project_path;
35
+ const project = projectPath ? projectsDb.getProjectPath(projectPath) : null;
36
+ const displayName = project?.custom_project_name?.trim()
37
+ ? project.custom_project_name
38
+ : await generateDisplayName(path.basename(projectPath ?? '') || (projectPath ?? ''), projectPath);
39
+
40
+ return {
41
+ kind: 'session_upserted',
42
+ sessionId: row.session_id,
43
+ providerSessionId: row.provider_session_id ?? null,
44
+ // The column is a plain TEXT and typed as `string` on the row, but only
45
+ // provider adapters ever write it.
46
+ provider: row.provider as SessionUpsertedEvent['provider'],
47
+ session: {
48
+ id: row.session_id,
49
+ summary: row.custom_name || '',
50
+ messageCount: 0,
51
+ lastActivity: row.updated_at ?? row.created_at ?? new Date().toISOString(),
52
+ },
53
+ project: project
54
+ ? {
55
+ projectId: project.project_id,
56
+ path: project.project_path,
57
+ fullPath: project.project_path,
58
+ displayName,
59
+ isStarred: Boolean(project.isStarred),
60
+ }
61
+ : null,
62
+ timestamp: new Date().toISOString(),
63
+ };
64
+ }
65
+
66
+ function sendToConnectedClients(payloads: string[]): void {
67
+ if (payloads.length === 0) {
68
+ return;
69
+ }
70
+
71
+ connectedClients.forEach((client) => {
72
+ if (client.readyState === WS_OPEN_STATE) {
73
+ for (const payload of payloads) {
74
+ client.send(payload);
75
+ }
76
+ }
77
+ });
78
+ }
79
+
80
+ /** Announces one session. Used by the chat run registry when a run reports its provider-native id. */
81
+ export async function broadcastSessionUpserted(sessionIdOrProviderSessionId: string): Promise<void> {
82
+ const event = await buildSessionUpsertedEvent(sessionIdOrProviderSessionId);
83
+ if (event) {
84
+ sendToConnectedClients([JSON.stringify(event)]);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Announces a batch of sessions. Used by the providers module's sessions
90
+ * watcher, whose debounced flush can carry dozens of ids at once — the client
91
+ * set is walked once for the whole batch rather than once per session.
92
+ */
93
+ export async function broadcastSessionUpsertedBatch(
94
+ sessionIds: Iterable<string>,
95
+ ): Promise<void> {
96
+ const payloads: string[] = [];
97
+ for (const sessionId of sessionIds) {
98
+ const event = await buildSessionUpsertedEvent(sessionId);
99
+ if (event) {
100
+ payloads.push(JSON.stringify(event));
101
+ }
102
+ }
103
+
104
+ sendToConnectedClients(payloads);
105
+ }
106
+
107
+ /** @internal Exported for the broadcast tests, which assert the payload shape directly. */
108
+ export { buildSessionUpsertedEvent };
@@ -19,6 +19,7 @@ type ShellIncomingMessage = {
19
19
  initialCommand?: string;
20
20
  isPlainShell?: boolean;
21
21
  forceRestart?: boolean;
22
+ bypassPermissions?: boolean;
22
23
  };
23
24
 
24
25
  type PtySessionEntry = {
@@ -216,12 +217,18 @@ function buildShellCommand(
216
217
  return initialCommand || 'opencode';
217
218
  }
218
219
 
219
- const command = initialCommand || 'claude';
220
+ // Launching with the flag is what unlocks "bypass permissions" in the CLI's
221
+ // shift+tab permission-mode cycle; it cannot be enabled from inside a
222
+ // session started without it.
223
+ const bypassFlag = readBoolean(message.bypassPermissions)
224
+ ? ' --dangerously-skip-permissions'
225
+ : '';
226
+ const command = initialCommand || `claude${bypassFlag}`;
220
227
  if (resumeSessionId) {
221
228
  if (os.platform() === 'win32') {
222
- return `claude --resume "${resumeSessionId}"; if ($LASTEXITCODE -ne 0) { claude }`;
229
+ return `claude --resume "${resumeSessionId}"${bypassFlag}; if ($LASTEXITCODE -ne 0) { claude${bypassFlag} }`;
223
230
  }
224
- return `claude --resume "${resumeSessionId}" || claude`;
231
+ return `claude --resume "${resumeSessionId}"${bypassFlag} || claude${bypassFlag}`;
225
232
  }
226
233
  return command;
227
234
  }