@cloudcli-ai/cloudcli 1.37.2 → 1.37.4

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 (453) hide show
  1. package/README.md +269 -0
  2. package/dist/assets/{abnfDiagram-N423BO3Z-C4UAoHJb.js → abnfDiagram-N423BO3Z-Dmkwx38H.js} +1 -1
  3. package/dist/assets/{arc-B8jF-ja9.js → arc-DLe9AYuO.js} +1 -1
  4. package/dist/assets/{architectureDiagram-T3A2C74G-C_Wur_CU.js → architectureDiagram-T3A2C74G-CBbbbNUW.js} +1 -1
  5. package/dist/assets/{blockDiagram-VBNYF7ZC-Cq4P1i8t.js → blockDiagram-VBNYF7ZC-CaMEaWu4.js} +1 -1
  6. package/dist/assets/{c4Diagram-5PPSVZJV-C1wG4eUj.js → c4Diagram-5PPSVZJV-DhjMgNnR.js} +1 -1
  7. package/dist/assets/channel-CWrmwsir.js +1 -0
  8. package/dist/assets/{chunk-2GRJ4B5K-B8fnBG6E.js → chunk-2GRJ4B5K-yjl3-F-i.js} +1 -1
  9. package/dist/assets/{chunk-2Q5K7J3B-WdfPooPJ.js → chunk-2Q5K7J3B-DsAYaWEP.js} +1 -1
  10. package/dist/assets/{chunk-5RXB4S5H-DhZJuG2E.js → chunk-5RXB4S5H-Bt5qmqOX.js} +1 -1
  11. package/dist/assets/{chunk-5VM5RSS4-B0rjslal.js → chunk-5VM5RSS4-yWrWVvUt.js} +1 -1
  12. package/dist/assets/{chunk-6Q2QTUOP-CG2Oj4jL.js → chunk-6Q2QTUOP-Dt66K5xb.js} +1 -1
  13. package/dist/assets/{chunk-GF5L2VYU-rrl2lRxY.js → chunk-GF5L2VYU-DA0vzaj4.js} +1 -1
  14. package/dist/assets/{chunk-JWPE2WC7-CjVbrVMA.js → chunk-JWPE2WC7-CUkbx96V.js} +1 -1
  15. package/dist/assets/{chunk-KBJHAD2P-CRzKgU8S.js → chunk-KBJHAD2P-DWKxx1WH.js} +1 -1
  16. package/dist/assets/{chunk-RYQCIY6F-DBz4GTZF.js → chunk-RYQCIY6F-BqluplN0.js} +1 -1
  17. package/dist/assets/{chunk-XXDRQBXY-wHxalsXk.js → chunk-XXDRQBXY-DelKg3Xf.js} +1 -1
  18. package/dist/assets/classDiagram-JCYQIIEL-COAGCC6w.js +1 -0
  19. package/dist/assets/classDiagram-v2-OCEON4UE-COAGCC6w.js +1 -0
  20. package/dist/assets/{cose-bilkent-JH36ORCC-s1hygY8e.js → cose-bilkent-JH36ORCC-DHV93-Em.js} +1 -1
  21. package/dist/assets/{cynefin-VYW2F7L2-C4LGV15i.js → cynefin-VYW2F7L2-B9HZgoGX.js} +1 -1
  22. package/dist/assets/{cynefinDiagram-MW4NZA55-C5uhu7B3.js → cynefinDiagram-MW4NZA55-hFjjEQg8.js} +1 -1
  23. package/dist/assets/{dagre-VZM6K2ZE-B-OBTewm.js → dagre-VZM6K2ZE-CpeVOC7V.js} +1 -1
  24. package/dist/assets/{diagram-7IWD3JNH-BjGKQxih.js → diagram-7IWD3JNH-D0H1UoRA.js} +1 -1
  25. package/dist/assets/{diagram-B4RE2ZJO-BMKz1X2L.js → diagram-B4RE2ZJO-6Y7BQUup.js} +1 -1
  26. package/dist/assets/{diagram-LBJQPF4R-DNh-GhKC.js → diagram-LBJQPF4R-C0nNOwht.js} +1 -1
  27. package/dist/assets/{diagram-Q27KOJAE-BaTG9jPT.js → diagram-Q27KOJAE-En6QlOVX.js} +1 -1
  28. package/dist/assets/{diagram-UB23O5K3-BUwo2OvJ.js → diagram-UB23O5K3-CmPiNeGD.js} +1 -1
  29. package/dist/assets/{ebnfDiagram-BXEA7PRR-DAZgfzX2.js → ebnfDiagram-BXEA7PRR-Bygzp1Qt.js} +1 -1
  30. package/dist/assets/{erDiagram-JOGREHBK-1w1CcGEb.js → erDiagram-JOGREHBK-CwScRfzl.js} +1 -1
  31. package/dist/assets/{flowDiagram-UKHOOZJN-D4EII8Jj.js → flowDiagram-UKHOOZJN-bKX-0xP6.js} +1 -1
  32. package/dist/assets/{ganttDiagram-PKOTCBZU-ChvJZAgB.js → ganttDiagram-PKOTCBZU-DtZPKXGd.js} +1 -1
  33. package/dist/assets/{gitGraphDiagram-DS77QQ5N-DtOn41S8.js → gitGraphDiagram-DS77QQ5N-CUOtdL1o.js} +1 -1
  34. package/dist/assets/index-CdjIFxM2.js +5004 -0
  35. package/dist/assets/index-DgafhGTF.css +32 -0
  36. package/dist/assets/{infoDiagram-6WML65LV-DN_PVEJZ.js → infoDiagram-6WML65LV-ciRQTS0h.js} +1 -1
  37. package/dist/assets/{ishikawaDiagram-WSZJBQD7-DbkF1kXb.js → ishikawaDiagram-WSZJBQD7-CgjhQZ84.js} +1 -1
  38. package/dist/assets/{journeyDiagram-NVQOT4AX-pJwmhddE.js → journeyDiagram-NVQOT4AX-BsbQSeIW.js} +1 -1
  39. package/dist/assets/{kanban-definition-27J2QSJJ-PPAPgNp5.js → kanban-definition-27J2QSJJ-CrwzY9Jw.js} +1 -1
  40. package/dist/assets/{linear-iPR-J9f7.js → linear-BUaCDr6l.js} +1 -1
  41. package/dist/assets/{mermaid.core-BEUL86Z6.js → mermaid.core-ClgdUU0j.js} +5 -5
  42. package/dist/assets/{mindmap-definition-FAOFIHXS-BvZoBib7.js → mindmap-definition-FAOFIHXS-BictljY1.js} +1 -1
  43. package/dist/assets/{pegDiagram-VL7TDLO6-DhYreaUd.js → pegDiagram-VL7TDLO6-BXdByy_U.js} +1 -1
  44. package/dist/assets/{pieDiagram-7S7Q4E2Y-CrOHlyD0.js → pieDiagram-7S7Q4E2Y-uZsMfkRX.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-CIZ2JOQS-D4g5yH3t.js → quadrantDiagram-CIZ2JOQS-7lCv4QIj.js} +1 -1
  46. package/dist/assets/{railroadDiagram-AXF67PYL-Dj39lHlf.js → railroadDiagram-AXF67PYL-07dxIWbi.js} +1 -1
  47. package/dist/assets/{requirementDiagram-LRYGKXZP-1AS4Zgm_.js → requirementDiagram-LRYGKXZP-Cb31Yv1_.js} +1 -1
  48. package/dist/assets/{sankeyDiagram-W5VNT64P-CKlMn19P.js → sankeyDiagram-W5VNT64P-X0YPSyF9.js} +1 -1
  49. package/dist/assets/{sequenceDiagram-SI44F4Z6-B_j3qyvo.js → sequenceDiagram-SI44F4Z6-BdBxSIlP.js} +1 -1
  50. package/dist/assets/server.browser-CtX3Hdl5.js +27 -0
  51. package/dist/assets/{sizeCapture-X5ZJPWSS-Bp2Op16v.js → sizeCapture-X5ZJPWSS-DQM5xAyD.js} +1 -1
  52. package/dist/assets/{stateDiagram-OKZ733FA-C0cN6DoY.js → stateDiagram-OKZ733FA-DJ3xkLUF.js} +1 -1
  53. package/dist/assets/stateDiagram-v2-UEYNNEHI-vAaE4zNo.js +1 -0
  54. package/dist/assets/{swimlanes-SLNWSIFB-BEvXOV9b.js → swimlanes-SLNWSIFB-rjfYdW0w.js} +2 -2
  55. package/dist/assets/swimlanesDiagram-ULZ7WXOC-TV2IF4Nq.js +8 -0
  56. package/dist/assets/{timeline-definition-Z64GVDOM-zdJQinvZ.js → timeline-definition-Z64GVDOM-DZMra5do.js} +1 -1
  57. package/dist/assets/{vendor-codemirror-OwyKSvPE.js → vendor-codemirror-CYrSt7-U.js} +18 -18
  58. package/dist/assets/{vennDiagram-T6HMQDX7-DuF1uZMY.js → vennDiagram-T6HMQDX7-BevD8uu0.js} +1 -1
  59. package/dist/assets/{wardleyDiagram-T6FBY63Y-B9AlLQup.js → wardleyDiagram-T6FBY63Y-DsIyXB7z.js} +1 -1
  60. package/dist/assets/{xychartDiagram-ELKLHX3M-DTJX48Qg.js → xychartDiagram-ELKLHX3M-G3PlF3ko.js} +1 -1
  61. package/dist/index.html +3 -3
  62. package/dist-server/server/index.js +11 -4
  63. package/dist-server/server/index.js.map +1 -1
  64. package/dist-server/server/modules/agent/agent.module.js +9 -2
  65. package/dist-server/server/modules/agent/agent.module.js.map +1 -1
  66. package/dist-server/server/modules/agent/agent.routes.js +177 -130
  67. package/dist-server/server/modules/agent/agent.routes.js.map +1 -1
  68. package/dist-server/server/modules/agent/tests/agent-run-registration.test.js +306 -0
  69. package/dist-server/server/modules/agent/tests/agent-run-registration.test.js.map +1 -0
  70. package/dist-server/server/modules/agent/tests/agent.routes.test.js +48 -2
  71. package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -1
  72. package/dist-server/server/modules/browser-use/browser-use.routes.js +39 -33
  73. package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -1
  74. package/dist-server/server/modules/database/connection.js +1 -1
  75. package/dist-server/server/modules/database/connection.js.map +1 -1
  76. package/dist-server/server/modules/database/index.js +5 -0
  77. package/dist-server/server/modules/database/index.js.map +1 -1
  78. package/dist-server/server/modules/database/migrations.js +45 -1
  79. package/dist-server/server/modules/database/migrations.js.map +1 -1
  80. package/dist-server/server/modules/database/repositories/provider-models.js +60 -6
  81. package/dist-server/server/modules/database/repositories/provider-models.js.map +1 -1
  82. package/dist-server/server/modules/database/repositories/scheduled-messages.db.js +71 -0
  83. package/dist-server/server/modules/database/repositories/scheduled-messages.db.js.map +1 -0
  84. package/dist-server/server/modules/database/repositories/session-drafts.db.js +105 -0
  85. package/dist-server/server/modules/database/repositories/session-drafts.db.js.map +1 -0
  86. package/dist-server/server/modules/database/repositories/sessions.db.js +144 -5
  87. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  88. package/dist-server/server/modules/database/repositories/user-preferences.db.js +65 -0
  89. package/dist-server/server/modules/database/repositories/user-preferences.db.js.map +1 -0
  90. package/dist-server/server/modules/database/schema.js +99 -0
  91. package/dist-server/server/modules/database/schema.js.map +1 -1
  92. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +99 -0
  93. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js.map +1 -1
  94. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +39 -0
  95. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
  96. package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js +105 -0
  97. package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js.map +1 -0
  98. package/dist-server/server/modules/file-tree/file-tree.module.js +2 -1
  99. package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -1
  100. package/dist-server/server/modules/file-tree/file-tree.service.js +44 -7
  101. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -1
  102. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +126 -1
  103. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -1
  104. package/dist-server/server/modules/git/git-branch-diff.service.js +142 -0
  105. package/dist-server/server/modules/git/git-branch-diff.service.js.map +1 -0
  106. package/dist-server/server/modules/git/git-branch.service.js.map +1 -1
  107. package/dist-server/server/modules/git/git.routes.js +92 -5
  108. package/dist-server/server/modules/git/git.routes.js.map +1 -1
  109. package/dist-server/server/modules/git/tests/git-branch-diff.service.test.js +160 -0
  110. package/dist-server/server/modules/git/tests/git-branch-diff.service.test.js.map +1 -0
  111. package/dist-server/server/modules/projects/project-clone.routes.js +108 -0
  112. package/dist-server/server/modules/projects/project-clone.routes.js.map +1 -0
  113. package/dist-server/server/modules/projects/projects.routes.js +13 -66
  114. package/dist-server/server/modules/projects/projects.routes.js.map +1 -1
  115. package/dist-server/server/modules/projects/services/project-clone-request.service.js +36 -0
  116. package/dist-server/server/modules/projects/services/project-clone-request.service.js.map +1 -0
  117. package/dist-server/server/modules/projects/services/project-clone.service.js +86 -32
  118. package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -1
  119. package/dist-server/server/modules/projects/services/project-delete.service.js +12 -1
  120. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -1
  121. package/dist-server/server/modules/projects/services/project-star.service.js +2 -2
  122. package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -1
  123. package/dist-server/server/modules/projects/tests/project-clone.routes.test.js +191 -0
  124. package/dist-server/server/modules/projects/tests/project-clone.routes.test.js.map +1 -0
  125. package/dist-server/server/modules/projects/tests/project-clone.service.test.js +275 -0
  126. package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -1
  127. package/dist-server/server/modules/providers/index.js +3 -0
  128. package/dist-server/server/modules/providers/index.js.map +1 -1
  129. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +62 -9
  130. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  131. package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js +46 -0
  132. package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js.map +1 -0
  133. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +31 -12
  134. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  135. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +472 -53
  136. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -1
  137. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +38 -11
  138. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  139. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +1007 -60
  140. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  141. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +4 -1
  142. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -1
  143. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  144. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  145. package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +204 -0
  146. package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -0
  147. package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js +32 -0
  148. package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js.map +1 -0
  149. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +47 -0
  150. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
  151. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +71 -53
  152. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -1
  153. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +8 -0
  154. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  155. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +1621 -431
  156. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  157. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  158. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  159. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +9 -2
  160. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -1
  161. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js +16 -8
  162. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -1
  163. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
  164. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +274 -9
  165. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
  166. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js +5 -2
  167. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -1
  168. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +19 -2
  169. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
  170. package/dist-server/server/modules/providers/provider.routes.js +134 -2
  171. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  172. package/dist-server/server/modules/providers/services/claude-cli-liveness.service.js +100 -0
  173. package/dist-server/server/modules/providers/services/claude-cli-liveness.service.js.map +1 -0
  174. package/dist-server/server/modules/providers/services/claude-settings-permissions.service.js +97 -0
  175. package/dist-server/server/modules/providers/services/claude-settings-permissions.service.js.map +1 -0
  176. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +23 -1
  177. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
  178. package/dist-server/server/modules/providers/services/provider-models.service.js +59 -5
  179. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  180. package/dist-server/server/modules/providers/services/provider-runtime.service.js +8 -0
  181. package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -1
  182. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +139 -35
  183. package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -1
  184. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +2 -4
  185. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
  186. package/dist-server/server/modules/providers/services/session-history-cache.service.js +91 -0
  187. package/dist-server/server/modules/providers/services/session-history-cache.service.js.map +1 -0
  188. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +105 -32
  189. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
  190. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +3 -60
  191. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  192. package/dist-server/server/modules/providers/services/sessions.service.js +252 -12
  193. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  194. package/dist-server/server/modules/providers/tests/claude-auth.test.js +183 -0
  195. package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -1
  196. package/dist-server/server/modules/providers/tests/claude-background-work.test.js +172 -0
  197. package/dist-server/server/modules/providers/tests/claude-background-work.test.js.map +1 -0
  198. package/dist-server/server/modules/providers/tests/claude-compaction.test.js +84 -0
  199. package/dist-server/server/modules/providers/tests/claude-compaction.test.js.map +1 -0
  200. package/dist-server/server/modules/providers/tests/claude-message-model.test.js +123 -0
  201. package/dist-server/server/modules/providers/tests/claude-message-model.test.js.map +1 -0
  202. package/dist-server/server/modules/providers/tests/claude-models.test.js +39 -0
  203. package/dist-server/server/modules/providers/tests/claude-models.test.js.map +1 -0
  204. package/dist-server/server/modules/providers/tests/claude-runtime-hold.test.js +265 -0
  205. package/dist-server/server/modules/providers/tests/claude-runtime-hold.test.js.map +1 -0
  206. package/dist-server/server/modules/providers/tests/claude-sessions.test.js +1815 -33
  207. package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -1
  208. package/dist-server/server/modules/providers/tests/claude-settings-permissions.test.js +228 -0
  209. package/dist-server/server/modules/providers/tests/claude-settings-permissions.test.js.map +1 -0
  210. package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js +16 -0
  211. package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js.map +1 -0
  212. package/dist-server/server/modules/providers/tests/claude-token-budget.test.js +85 -0
  213. package/dist-server/server/modules/providers/tests/claude-token-budget.test.js.map +1 -0
  214. package/dist-server/server/modules/providers/tests/codex-message-editing.test.js +338 -0
  215. package/dist-server/server/modules/providers/tests/codex-message-editing.test.js.map +1 -0
  216. package/dist-server/server/modules/providers/tests/codex-models.test.js +25 -0
  217. package/dist-server/server/modules/providers/tests/codex-models.test.js.map +1 -0
  218. package/dist-server/server/modules/providers/tests/codex-runtime.test.js +83 -0
  219. package/dist-server/server/modules/providers/tests/codex-runtime.test.js.map +1 -0
  220. package/dist-server/server/modules/providers/tests/codex-session-fork.test.js +54 -0
  221. package/dist-server/server/modules/providers/tests/codex-session-fork.test.js.map +1 -0
  222. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +354 -15
  223. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
  224. package/dist-server/server/modules/providers/tests/cursor-auth.test.js +167 -0
  225. package/dist-server/server/modules/providers/tests/cursor-auth.test.js.map +1 -0
  226. package/dist-server/server/modules/providers/tests/opencode-models.test.js +196 -4
  227. package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
  228. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +19 -1
  229. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
  230. package/dist-server/server/modules/providers/tests/provider-capabilities.service.test.js +30 -0
  231. package/dist-server/server/modules/providers/tests/provider-capabilities.service.test.js.map +1 -0
  232. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +79 -1
  233. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
  234. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +164 -1
  235. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -1
  236. package/dist-server/server/modules/providers/tests/provider.routes.test.js +190 -1
  237. package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -1
  238. package/dist-server/server/modules/providers/tests/session-fork.test.js +113 -0
  239. package/dist-server/server/modules/providers/tests/session-fork.test.js.map +1 -0
  240. package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js +139 -0
  241. package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js.map +1 -0
  242. package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js +90 -0
  243. package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js.map +1 -0
  244. package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js +122 -0
  245. package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js.map +1 -0
  246. package/dist-server/server/modules/providers/tests/sessions.service.test.js +219 -1
  247. package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -1
  248. package/dist-server/server/modules/providers/tests/skills.test.js +15 -3
  249. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  250. package/dist-server/server/modules/scheduled-messages/index.js +5 -0
  251. package/dist-server/server/modules/scheduled-messages/index.js.map +1 -0
  252. package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js +47 -0
  253. package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js.map +1 -0
  254. package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js +175 -0
  255. package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js.map +1 -0
  256. package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js +95 -0
  257. package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js.map +1 -0
  258. package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js +290 -0
  259. package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js.map +1 -0
  260. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +23 -23
  261. package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -1
  262. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +48 -0
  263. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -1
  264. package/dist-server/server/modules/user/tests/user.service.test.js +70 -0
  265. package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -1
  266. package/dist-server/server/modules/user/user.module.js +10 -1
  267. package/dist-server/server/modules/user/user.module.js.map +1 -1
  268. package/dist-server/server/modules/user/user.routes.js +44 -0
  269. package/dist-server/server/modules/user/user.routes.js.map +1 -1
  270. package/dist-server/server/modules/user/user.service.js +75 -0
  271. package/dist-server/server/modules/user/user.service.js.map +1 -1
  272. package/dist-server/server/modules/voice/tests/voice.service.test.js +3 -2
  273. package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -1
  274. package/dist-server/server/modules/websocket/index.js +7 -0
  275. package/dist-server/server/modules/websocket/index.js.map +1 -1
  276. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +37 -49
  277. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -1
  278. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +35 -5
  279. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -1
  280. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +204 -10
  281. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  282. package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js +94 -0
  283. package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js.map +1 -0
  284. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +236 -20
  285. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  286. package/dist-server/server/modules/websocket/tests/chat-background-subscribe.test.js +137 -0
  287. package/dist-server/server/modules/websocket/tests/chat-background-subscribe.test.js.map +1 -0
  288. package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js +263 -0
  289. package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js.map +1 -0
  290. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +29 -3
  291. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -1
  292. package/dist-server/server/modules/websocket/tests/chat-stop-task.test.js +96 -0
  293. package/dist-server/server/modules/websocket/tests/chat-stop-task.test.js.map +1 -0
  294. package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js +106 -0
  295. package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js.map +1 -0
  296. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +500 -0
  297. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -1
  298. package/dist-server/server/shared/claude-cli-path.js +22 -5
  299. package/dist-server/server/shared/claude-cli-path.js.map +1 -1
  300. package/dist-server/server/shared/index.js +3 -0
  301. package/dist-server/server/shared/index.js.map +1 -0
  302. package/dist-server/server/shared/message-unification.js +376 -0
  303. package/dist-server/server/shared/message-unification.js.map +1 -0
  304. package/dist-server/server/shared/tests/claude-cli-path.test.js +45 -1
  305. package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -1
  306. package/dist-server/server/shared/tests/message-unification.test.js +174 -0
  307. package/dist-server/server/shared/tests/message-unification.test.js.map +1 -0
  308. package/dist-server/server/shared/tests/read-only-roots.test.js +124 -0
  309. package/dist-server/server/shared/tests/read-only-roots.test.js.map +1 -0
  310. package/dist-server/server/shared/tests/strip-ansi-sequences.test.js +31 -0
  311. package/dist-server/server/shared/tests/strip-ansi-sequences.test.js.map +1 -0
  312. package/dist-server/server/shared/utils.js +160 -0
  313. package/dist-server/server/shared/utils.js.map +1 -1
  314. package/electron/desktopWindow.js +6 -0
  315. package/electron/viewHost.js +25 -2
  316. package/package.json +20 -17
  317. package/server/index.ts +16 -5
  318. package/server/modules/agent/agent.module.ts +11 -1
  319. package/server/modules/agent/agent.routes.ts +200 -142
  320. package/server/modules/agent/tests/agent-run-registration.test.ts +348 -0
  321. package/server/modules/agent/tests/agent.routes.test.ts +51 -2
  322. package/server/modules/browser-use/browser-use.routes.ts +96 -33
  323. package/server/modules/database/connection.ts +2 -1
  324. package/server/modules/database/index.ts +10 -0
  325. package/server/modules/database/migrations.ts +51 -0
  326. package/server/modules/database/repositories/provider-models.ts +79 -6
  327. package/server/modules/database/repositories/scheduled-messages.db.ts +127 -0
  328. package/server/modules/database/repositories/session-drafts.db.ts +171 -0
  329. package/server/modules/database/repositories/sessions.db.ts +204 -3
  330. package/server/modules/database/repositories/user-preferences.db.ts +80 -0
  331. package/server/modules/database/schema.ts +103 -0
  332. package/server/modules/database/tests/provider-models.db.integration.test.ts +113 -0
  333. package/server/modules/database/tests/sessions.db.integration.test.ts +52 -0
  334. package/server/modules/database/tests/user-preferences.db.integration.test.ts +135 -0
  335. package/server/modules/file-tree/file-tree.module.ts +2 -1
  336. package/server/modules/file-tree/file-tree.service.ts +49 -7
  337. package/server/modules/file-tree/tests/file-tree.service.test.ts +163 -1
  338. package/server/modules/git/git-branch-diff.service.ts +204 -0
  339. package/server/modules/git/git-branch.service.ts +2 -12
  340. package/server/modules/git/git.routes.ts +100 -6
  341. package/server/modules/git/tests/git-branch-diff.service.test.ts +210 -0
  342. package/server/modules/projects/project-clone.routes.ts +142 -0
  343. package/server/modules/projects/projects.routes.ts +16 -81
  344. package/server/modules/projects/services/project-clone-request.service.ts +56 -0
  345. package/server/modules/projects/services/project-clone.service.ts +102 -34
  346. package/server/modules/projects/services/project-delete.service.ts +13 -1
  347. package/server/modules/projects/services/project-star.service.ts +2 -2
  348. package/server/modules/projects/tests/project-clone.routes.test.ts +246 -0
  349. package/server/modules/projects/tests/project-clone.service.test.ts +376 -0
  350. package/server/modules/providers/index.ts +4 -0
  351. package/server/modules/providers/list/claude/claude-auth.provider.ts +81 -11
  352. package/server/modules/providers/list/claude/claude-fork.provider.ts +57 -0
  353. package/server/modules/providers/list/claude/claude-models.provider.ts +37 -17
  354. package/server/modules/providers/list/claude/claude-runtime.provider.js +510 -54
  355. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +40 -14
  356. package/server/modules/providers/list/claude/claude-sessions.provider.ts +1195 -63
  357. package/server/modules/providers/list/claude/claude-skills.provider.ts +4 -1
  358. package/server/modules/providers/list/claude/claude.provider.ts +3 -0
  359. package/server/modules/providers/list/codex/codex-app-server.client.ts +243 -0
  360. package/server/modules/providers/list/codex/codex-fork.provider.ts +40 -0
  361. package/server/modules/providers/list/codex/codex-models.provider.ts +47 -0
  362. package/server/modules/providers/list/codex/{codex-runtime.provider.js → codex-runtime.provider.ts} +105 -70
  363. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +9 -0
  364. package/server/modules/providers/list/codex/codex-sessions.provider.ts +1847 -455
  365. package/server/modules/providers/list/codex/codex.provider.ts +3 -0
  366. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +10 -2
  367. package/server/modules/providers/list/cursor/cursor-runtime.provider.js +17 -8
  368. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +0 -1
  369. package/server/modules/providers/list/opencode/opencode-models.provider.ts +297 -9
  370. package/server/modules/providers/list/opencode/opencode-runtime.provider.js +5 -2
  371. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +30 -2
  372. package/server/modules/providers/provider.routes.ts +162 -2
  373. package/server/modules/providers/services/claude-cli-liveness.service.ts +121 -0
  374. package/server/modules/providers/services/claude-settings-permissions.service.ts +127 -0
  375. package/server/modules/providers/services/provider-capabilities.service.ts +40 -1
  376. package/server/modules/providers/services/provider-models.service.ts +71 -4
  377. package/server/modules/providers/services/provider-runtime.service.ts +11 -0
  378. package/server/modules/providers/services/provider-token-usage.service.ts +166 -39
  379. package/server/modules/providers/services/session-conversations-search.service.ts +2 -5
  380. package/server/modules/providers/services/session-history-cache.service.ts +150 -0
  381. package/server/modules/providers/services/session-synchronizer.service.ts +125 -38
  382. package/server/modules/providers/services/sessions-watcher.service.ts +3 -64
  383. package/server/modules/providers/services/sessions.service.ts +309 -17
  384. package/server/modules/providers/tests/claude-auth.test.ts +208 -0
  385. package/server/modules/providers/tests/claude-background-work.test.ts +213 -0
  386. package/server/modules/providers/tests/claude-compaction.test.ts +101 -0
  387. package/server/modules/providers/tests/claude-message-model.test.ts +160 -0
  388. package/server/modules/providers/tests/claude-models.test.ts +87 -0
  389. package/server/modules/providers/tests/claude-runtime-hold.test.ts +309 -0
  390. package/server/modules/providers/tests/claude-sessions.test.ts +2167 -37
  391. package/server/modules/providers/tests/claude-settings-permissions.test.ts +271 -0
  392. package/server/modules/providers/tests/claude-subagent-echo.test.ts +25 -0
  393. package/server/modules/providers/tests/claude-token-budget.test.ts +104 -0
  394. package/server/modules/providers/tests/codex-message-editing.test.ts +419 -0
  395. package/server/modules/providers/tests/codex-models.test.ts +37 -0
  396. package/server/modules/providers/tests/codex-runtime.test.ts +94 -0
  397. package/server/modules/providers/tests/codex-session-fork.test.ts +59 -0
  398. package/server/modules/providers/tests/codex-sessions.test.ts +396 -15
  399. package/server/modules/providers/tests/cursor-auth.test.ts +187 -0
  400. package/server/modules/providers/tests/opencode-models.test.ts +266 -8
  401. package/server/modules/providers/tests/opencode-sessions.test.ts +40 -1
  402. package/server/modules/providers/tests/provider-capabilities.service.test.ts +37 -0
  403. package/server/modules/providers/tests/provider-models.service.test.ts +99 -1
  404. package/server/modules/providers/tests/provider-token-usage.service.test.ts +188 -1
  405. package/server/modules/providers/tests/provider.routes.test.ts +230 -1
  406. package/server/modules/providers/tests/session-fork.test.ts +173 -0
  407. package/server/modules/providers/tests/session-history-cache.service.test.ts +165 -0
  408. package/server/modules/providers/tests/session-orphan-prune.test.ts +107 -0
  409. package/server/modules/providers/tests/session-synchronizer-coalescing.test.ts +136 -0
  410. package/server/modules/providers/tests/sessions.service.test.ts +303 -1
  411. package/server/modules/providers/tests/skills.test.ts +21 -5
  412. package/server/modules/scheduled-messages/index.ts +8 -0
  413. package/server/modules/scheduled-messages/scheduled-messages.routes.ts +68 -0
  414. package/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.ts +216 -0
  415. package/server/modules/scheduled-messages/services/scheduled-messages.service.ts +121 -0
  416. package/server/modules/scheduled-messages/tests/scheduled-messages.test.ts +354 -0
  417. package/server/modules/taskmaster/taskmaster.routes.ts +23 -33
  418. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +57 -0
  419. package/server/modules/user/tests/user.service.test.ts +90 -0
  420. package/server/modules/user/user.module.ts +10 -1
  421. package/server/modules/user/user.routes.ts +44 -0
  422. package/server/modules/user/user.service.ts +105 -0
  423. package/server/modules/voice/tests/voice.service.test.ts +3 -2
  424. package/server/modules/websocket/README.md +4 -2
  425. package/server/modules/websocket/index.ts +8 -0
  426. package/server/modules/websocket/services/chat-run-registry.service.ts +45 -54
  427. package/server/modules/websocket/services/chat-session-writer.service.ts +36 -6
  428. package/server/modules/websocket/services/chat-websocket.service.ts +302 -16
  429. package/server/modules/websocket/services/session-upsert-broadcast.service.ts +108 -0
  430. package/server/modules/websocket/services/shell-websocket.service.ts +276 -22
  431. package/server/modules/websocket/tests/chat-background-subscribe.test.ts +167 -0
  432. package/server/modules/websocket/tests/chat-edit-send.test.ts +309 -0
  433. package/server/modules/websocket/tests/chat-run-registry.test.ts +34 -3
  434. package/server/modules/websocket/tests/chat-stop-task.test.ts +127 -0
  435. package/server/modules/websocket/tests/session-upsert-broadcast.test.ts +138 -0
  436. package/server/modules/websocket/tests/shell-websocket.service.test.ts +629 -0
  437. package/server/shared/claude-cli-path.ts +24 -6
  438. package/server/shared/index.ts +3 -0
  439. package/server/shared/interfaces.ts +91 -0
  440. package/server/shared/message-unification.ts +449 -0
  441. package/server/shared/tests/claude-cli-path.test.ts +58 -1
  442. package/server/shared/tests/message-unification.test.ts +218 -0
  443. package/server/shared/tests/read-only-roots.test.ts +139 -0
  444. package/server/shared/tests/strip-ansi-sequences.test.ts +42 -0
  445. package/server/shared/types.ts +382 -7
  446. package/server/shared/utils.ts +176 -0
  447. package/dist/assets/channel-_falYbU1.js +0 -1
  448. package/dist/assets/classDiagram-JCYQIIEL-Dn-3CfpR.js +0 -1
  449. package/dist/assets/classDiagram-v2-OCEON4UE-Dn-3CfpR.js +0 -1
  450. package/dist/assets/index-CzPLBvXT.css +0 -32
  451. package/dist/assets/index-DFkBBuSA.js +0 -1549
  452. package/dist/assets/stateDiagram-v2-UEYNNEHI-BvBxUUrZ.js +0 -1
  453. package/dist/assets/swimlanesDiagram-ULZ7WXOC-CsE-x4YK.js +0 -8
@@ -1,6 +1,7 @@
1
1
  import express, { type Request, type Response } from 'express';
2
2
 
3
3
  import { providerAuthService } from '@/modules/providers/services/provider-auth.service.js';
4
+ import { claudeSettingsPermissionsService } from '@/modules/providers/services/claude-settings-permissions.service.js';
4
5
  import { providerCapabilitiesService } from '@/modules/providers/services/provider-capabilities.service.js';
5
6
  import { providerMcpService } from '@/modules/providers/services/mcp.service.js';
6
7
  import { providerModelsService } from '@/modules/providers/services/provider-models.service.js';
@@ -9,6 +10,7 @@ import { providerSkillsService } from '@/modules/providers/services/skills.servi
9
10
  import { sessionConversationsSearchService } from '@/modules/providers/services/session-conversations-search.service.js';
10
11
  import { sessionsService } from '@/modules/providers/services/sessions.service.js';
11
12
  import type {
13
+ CustomProviderModelEffort,
12
14
  CustomProviderModelInput,
13
15
  LLMProvider,
14
16
  McpScope,
@@ -53,6 +55,35 @@ const parseSessionId = (value: unknown): string => {
53
55
  return sessionId;
54
56
  };
55
57
 
58
+ /** A workflow run id as the harness mints one (`wf_16fbf852-274`). */
59
+ const WORKFLOW_RUN_ID_PATTERN = /^wf_[A-Za-z0-9-]+$/;
60
+ /** A workflow agent id as the CLI mints one: `a` and sixteen hex digits. */
61
+ const WORKFLOW_AGENT_ID_PATTERN = /^a[0-9a-f]{16}$/;
62
+
63
+ // Both ids name a file under the session's transcript directory, so nothing
64
+ // outside these shapes may reach the filesystem.
65
+ const parseWorkflowRunId = (value: unknown): string => {
66
+ const runId = readPathParam(value, 'runId');
67
+ if (!WORKFLOW_RUN_ID_PATTERN.test(runId)) {
68
+ throw new AppError('Invalid workflow run id.', {
69
+ code: 'INVALID_WORKFLOW_RUN_ID',
70
+ statusCode: 400,
71
+ });
72
+ }
73
+ return runId;
74
+ };
75
+
76
+ const parseWorkflowAgentId = (value: unknown): string => {
77
+ const agentId = readPathParam(value, 'agentId');
78
+ if (!WORKFLOW_AGENT_ID_PATTERN.test(agentId)) {
79
+ throw new AppError('Invalid workflow agent id.', {
80
+ code: 'INVALID_WORKFLOW_AGENT_ID',
81
+ statusCode: 400,
82
+ });
83
+ }
84
+ return agentId;
85
+ };
86
+
56
87
  const readOptionalQueryString = (value: unknown): string | undefined => {
57
88
  if (typeof value !== 'string') {
58
89
  return undefined;
@@ -297,6 +328,28 @@ const parseProvider = (value: unknown): LLMProvider => {
297
328
  });
298
329
  };
299
330
 
331
+ /** Both fields are optional: an empty body forks the whole conversation. */
332
+ const parseSessionForkPayload = (payload: unknown): { upToAnchorId?: string; title?: string } => {
333
+ if (payload === undefined || payload === null) {
334
+ return {};
335
+ }
336
+ if (typeof payload !== 'object') {
337
+ throw new AppError('Request body must be an object.', {
338
+ code: 'INVALID_REQUEST_BODY',
339
+ statusCode: 400,
340
+ });
341
+ }
342
+
343
+ const body = payload as Record<string, unknown>;
344
+ const upToAnchorId = typeof body.upToAnchorId === 'string' ? body.upToAnchorId.trim() : '';
345
+ const title = typeof body.title === 'string' ? body.title.trim() : '';
346
+
347
+ return {
348
+ ...(upToAnchorId ? { upToAnchorId } : {}),
349
+ ...(title ? { title } : {}),
350
+ };
351
+ };
352
+
300
353
  const parseSessionRenameSummary = (payload: unknown): string => {
301
354
  if (!payload || typeof payload !== 'object') {
302
355
  throw new AppError('Request body must be an object.', {
@@ -443,6 +496,78 @@ const parseModelRecordId = (value: unknown): number => {
443
496
  return recordId;
444
497
  };
445
498
 
499
+ const invalidModelEffort = (message: string): AppError => new AppError(message, {
500
+ code: 'INVALID_MODEL_EFFORT',
501
+ statusCode: 400,
502
+ });
503
+
504
+ /**
505
+ * Upper bound on declared effort levels, far above any provider's level set.
506
+ * Checked before the per-entry loop so an oversized body (the JSON parser
507
+ * accepts up to 50 MB) is rejected at once instead of being walked in full.
508
+ */
509
+ const MAX_MODEL_EFFORT_LEVELS = 32;
510
+
511
+ /**
512
+ * Parses the optional `effort` field of a custom-model payload.
513
+ *
514
+ * Only the shape is checked here (unique, trimmed, non-empty level ids and a
515
+ * default drawn from them); which levels a provider accepts is decided by the
516
+ * Providers service. `undefined` means "not sent" and `null` or an empty
517
+ * `values` list means "no effort levels".
518
+ */
519
+ const parseCustomProviderModelEffort = (
520
+ value: unknown,
521
+ ): CustomProviderModelEffort | null | undefined => {
522
+ if (value === undefined) {
523
+ return undefined;
524
+ }
525
+ if (value === null) {
526
+ return null;
527
+ }
528
+ if (typeof value !== 'object' || Array.isArray(value)) {
529
+ throw invalidModelEffort('effort must be an object with a values array.');
530
+ }
531
+
532
+ const effort = value as Record<string, unknown>;
533
+ if (!Array.isArray(effort.values)) {
534
+ throw invalidModelEffort('effort.values must be an array of effort levels.');
535
+ }
536
+ if (effort.values.length > MAX_MODEL_EFFORT_LEVELS) {
537
+ throw invalidModelEffort(`effort.values can list at most ${MAX_MODEL_EFFORT_LEVELS} effort levels.`);
538
+ }
539
+
540
+ const values: string[] = [];
541
+ const seenLevels = new Set<string>();
542
+ for (const entry of effort.values) {
543
+ const level = typeof entry === 'string' ? entry.trim() : '';
544
+ if (!level || level.length > 40) {
545
+ throw invalidModelEffort('effort.values must contain non-empty strings of 40 characters or fewer.');
546
+ }
547
+ if (seenLevels.has(level)) {
548
+ throw invalidModelEffort(`effort.values contains "${level}" more than once.`);
549
+ }
550
+ seenLevels.add(level);
551
+ values.push(level);
552
+ }
553
+
554
+ if (effort.default !== undefined && effort.default !== null && typeof effort.default !== 'string') {
555
+ throw invalidModelEffort('effort.default must be a string.');
556
+ }
557
+ const defaultLevel = readOptionalQueryString(effort.default);
558
+ if (values.length === 0) {
559
+ if (defaultLevel) {
560
+ throw invalidModelEffort('effort.default requires at least one effort level.');
561
+ }
562
+ return null;
563
+ }
564
+ if (defaultLevel && !values.includes(defaultLevel)) {
565
+ throw invalidModelEffort('effort.default must be one of effort.values.');
566
+ }
567
+
568
+ return defaultLevel ? { values, default: defaultLevel } : { values };
569
+ };
570
+
446
571
  const parseCustomProviderModelPayload = (payload: unknown): CustomProviderModelInput => {
447
572
  if (!payload || typeof payload !== 'object') {
448
573
  throw new AppError('Request body must be an object.', {
@@ -479,7 +604,8 @@ const parseCustomProviderModelPayload = (payload: unknown): CustomProviderModelI
479
604
  });
480
605
  }
481
606
 
482
- return { model, id };
607
+ const effort = parseCustomProviderModelEffort(body.effort);
608
+ return effort === undefined ? { model, id } : { model, id, effort };
483
609
  };
484
610
 
485
611
  router.get(
@@ -695,6 +821,15 @@ router.get(
695
821
  }),
696
822
  );
697
823
 
824
+ // Read-only: the rules Claude's own settings files add on top of the UI's lists.
825
+ router.get(
826
+ '/claude/settings-permissions',
827
+ asyncHandler(async (_req: Request, res: Response) => {
828
+ const sources = await claudeSettingsPermissionsService.listRuleSources();
829
+ res.json(createApiSuccessResponse({ sources }));
830
+ }),
831
+ );
832
+
698
833
  // ----------------- Session routes -----------------
699
834
  /**
700
835
  * Session gateway entry point: allocates the stable app-facing session id for
@@ -717,7 +852,7 @@ router.post(
717
852
  router.get(
718
853
  '/sessions/running',
719
854
  asyncHandler(async (_req: Request, res: Response) => {
720
- const sessions = sessionsService.listRunningSessions();
855
+ const sessions = await sessionsService.listRunningSessions();
721
856
  res.json(createApiSuccessResponse({ sessions }));
722
857
  }),
723
858
  );
@@ -792,6 +927,15 @@ router.post(
792
927
  }),
793
928
  );
794
929
 
930
+ router.post(
931
+ '/sessions/:sessionId/fork',
932
+ asyncHandler(async (req: Request, res: Response) => {
933
+ const sessionId = parseSessionId(req.params.sessionId);
934
+ const result = await sessionsService.forkSessionById(sessionId, parseSessionForkPayload(req.body));
935
+ res.status(201).json(createApiSuccessResponse(result));
936
+ }),
937
+ );
938
+
795
939
  router.put(
796
940
  '/sessions/:sessionId',
797
941
  asyncHandler(async (req: Request, res: Response) => {
@@ -817,6 +961,22 @@ router.get(
817
961
  }),
818
962
  );
819
963
 
964
+ /**
965
+ * One workflow agent's timeline, read on demand when its row in the workflow
966
+ * card is opened. History does not carry it: a run can spawn a dozen agents
967
+ * with hundreds of tool calls each, and the card only lists them.
968
+ */
969
+ router.get(
970
+ '/sessions/:sessionId/workflows/:runId/agents/:agentId',
971
+ asyncHandler(async (req: Request, res: Response) => {
972
+ const sessionId = parseSessionId(req.params.sessionId);
973
+ const runId = parseWorkflowRunId(req.params.runId);
974
+ const agentId = parseWorkflowAgentId(req.params.agentId);
975
+ const result = await sessionsService.readWorkflowAgentActivity(sessionId, runId, agentId);
976
+ res.json(createApiSuccessResponse(result));
977
+ }),
978
+ );
979
+
820
980
  router.get('/search/sessions', asyncHandler(async (req: Request, res: Response) => {
821
981
  const query = parseSessionSearchQuery(req.query.q);
822
982
  const limit = parseSessionSearchLimit(req.query.limit);
@@ -0,0 +1,121 @@
1
+ import fsp from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
5
+ /**
6
+ * One Claude CLI process that is currently producing a response.
7
+ *
8
+ * `providerSessionId` is Claude's own session id, which is what the registry
9
+ * records; callers map it onto an app session themselves.
10
+ */
11
+ type LiveClaudeCliSession = {
12
+ providerSessionId: string;
13
+ startedAt: number;
14
+ };
15
+
16
+ /**
17
+ * Claude Code keeps one file per running session here, named `<pid>.json`.
18
+ * The directory belongs to the CLI, not to CloudCLI: it is only ever read.
19
+ */
20
+ const registryDirectory = () => path.join(os.homedir(), '.claude', 'sessions');
21
+
22
+ /**
23
+ * Upper bound on registry files inspected per poll.
24
+ *
25
+ * The running-sessions endpoint is polled continuously, so a directory left
26
+ * full of stale files by repeated crashes must not turn every poll into
27
+ * unbounded filesystem work. Real installations hold a handful of entries.
28
+ */
29
+ const MAX_REGISTRY_FILES = 256;
30
+
31
+ /**
32
+ * Whether `pid` is still the process the registry recorded.
33
+ *
34
+ * A registry file outlives a crash, so its mere presence proves nothing. The
35
+ * signal-0 probe answers "does this pid exist" (EPERM means it exists but is
36
+ * owned by someone else, which still counts), and on Linux the recorded
37
+ * `procStart` is compared against the kernel's start-time for that pid so a
38
+ * reused pid cannot be mistaken for the original process.
39
+ */
40
+ async function isRecordedProcessAlive(pid: number, procStart: unknown): Promise<boolean> {
41
+ try {
42
+ process.kill(pid, 0);
43
+ } catch (error) {
44
+ if ((error as NodeJS.ErrnoException)?.code !== 'EPERM') {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ if (process.platform !== 'linux' || typeof procStart !== 'string' || !procStart) {
50
+ return true;
51
+ }
52
+
53
+ try {
54
+ const stat = await fsp.readFile(`/proc/${pid}/stat`, 'utf8');
55
+ // The comm field is parenthesised and may itself contain spaces, so the
56
+ // fields are counted from the last ')'. starttime is the 22nd field
57
+ // overall, i.e. the 20th of what follows the comm field.
58
+ const fields = stat.slice(stat.lastIndexOf(')') + 2).split(' ');
59
+ return fields[19] === procStart;
60
+ } catch {
61
+ // No procfs entry means the process is gone between the two checks.
62
+ return false;
63
+ }
64
+ }
65
+
66
+ /** Reads one registry file, returning null for anything that is not a live busy session. */
67
+ async function readLiveBusySession(filePath: string): Promise<LiveClaudeCliSession | null> {
68
+ let parsed: unknown;
69
+ try {
70
+ parsed = JSON.parse(await fsp.readFile(filePath, 'utf8'));
71
+ } catch {
72
+ // Unreadable, half-written or malformed entries are simply not evidence
73
+ // of a running session.
74
+ return null;
75
+ }
76
+
77
+ const record = parsed as Record<string, unknown> | null;
78
+ if (!record || typeof record !== 'object') {
79
+ return null;
80
+ }
81
+
82
+ const providerSessionId = typeof record.sessionId === 'string' ? record.sessionId : '';
83
+ const pid = typeof record.pid === 'number' ? record.pid : NaN;
84
+ if (!providerSessionId || !Number.isInteger(pid) || pid <= 0 || record.status !== 'busy') {
85
+ return null;
86
+ }
87
+
88
+ if (!(await isRecordedProcessAlive(pid, record.procStart))) {
89
+ return null;
90
+ }
91
+
92
+ const startedAt = typeof record.startedAt === 'number' ? record.startedAt : Date.now();
93
+ return { providerSessionId, startedAt };
94
+ }
95
+
96
+ /**
97
+ * Lists the Claude CLI sessions that are mid-turn right now.
98
+ *
99
+ * Used by the providers module's sessions service so the running-sessions poll
100
+ * also reports turns driven outside CloudCLI's own chat runs — including the
101
+ * `claude` processes CloudCLI itself spawns for the Shell view, which live in
102
+ * the PTY map rather than the chat-run registry. Liveness is ephemeral, so it
103
+ * is recomputed on every read instead of being cached or persisted.
104
+ */
105
+ export async function listBusyClaudeCliSessions(): Promise<LiveClaudeCliSession[]> {
106
+ let entries: string[];
107
+ try {
108
+ entries = await fsp.readdir(registryDirectory());
109
+ } catch {
110
+ // No registry directory at all is the normal case for an install that has
111
+ // never run the CLI, and an unreadable one is not worth failing a poll for.
112
+ return [];
113
+ }
114
+
115
+ const registryFiles = entries.filter((entry) => entry.endsWith('.json')).slice(0, MAX_REGISTRY_FILES);
116
+ const sessions = await Promise.all(
117
+ registryFiles.map((entry) => readLiveBusySession(path.join(registryDirectory(), entry))),
118
+ );
119
+
120
+ return sessions.filter((session): session is LiveClaudeCliSession => session !== null);
121
+ }
@@ -0,0 +1,127 @@
1
+ import { readFile, stat } from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
5
+ import { readObjectRecord, readStringArray } from '@/shared/utils.js';
6
+
7
+ /**
8
+ * The permission rules one Claude settings file contributes.
9
+ *
10
+ * `status` says whether the rules could be read at all: `missing` means there
11
+ * is no such file, `invalid` means it exists but the CLI would not load it
12
+ * either (unreadable, over its size cap, or not a JSON object). Both report
13
+ * empty rule lists rather than failing the request, so one bad file never hides
14
+ * the others.
15
+ */
16
+ type ClaudeSettingsPermissionSource = {
17
+ scope: 'user' | 'managed';
18
+ path: string;
19
+ status: 'ok' | 'missing' | 'invalid';
20
+ allow: string[];
21
+ deny: string[];
22
+ ask: string[];
23
+ };
24
+
25
+ /**
26
+ * The user's own settings file. The CLI reads it from `CLAUDE_CONFIG_DIR` when
27
+ * that is set, and the server forwards its whole env to every CLI it spawns,
28
+ * so the same override has to apply here.
29
+ */
30
+ const userSettingsPath = (): string => {
31
+ const configDirectory = process.env.CLAUDE_CONFIG_DIR?.trim();
32
+ const baseDirectory = configDirectory && path.isAbsolute(configDirectory)
33
+ ? configDirectory
34
+ : path.join(os.homedir(), '.claude');
35
+ return path.join(baseDirectory, 'settings.json');
36
+ };
37
+
38
+ /** The administrator-managed settings file, at the fixed path the CLI uses per OS. */
39
+ const managedSettingsPath = (): string => {
40
+ if (process.platform === 'darwin') {
41
+ return '/Library/Application Support/ClaudeCode/managed-settings.json';
42
+ }
43
+ if (process.platform === 'win32') {
44
+ return 'C:\\Program Files\\ClaudeCode\\managed-settings.json';
45
+ }
46
+ return '/etc/claude-code/managed-settings.json';
47
+ };
48
+
49
+ // The CLI refuses to load a settings file larger than this (2 MB).
50
+ const MAX_SETTINGS_FILE_BYTES = 2 * 1024 * 1024;
51
+
52
+ /**
53
+ * Decodes a settings file the way the CLI does: UTF-16LE when it starts with
54
+ * that byte order mark, UTF-8 otherwise, without the leading BOM. Windows
55
+ * editors and PowerShell often save one, and the CLI still applies such files.
56
+ */
57
+ const decodeSettingsFile = (bytes: Buffer): string => {
58
+ const isUtf16LittleEndian = bytes.length >= 2 && bytes[0] === 0xff && bytes[1] === 0xfe;
59
+ return bytes.toString(isUtf16LittleEndian ? 'utf16le' : 'utf8').replace(/^\uFEFF/, '');
60
+ };
61
+
62
+ /** Keeps non-empty string rules only, without duplicates, in file order. */
63
+ const readRuleList = (value: unknown): string[] => [
64
+ ...new Set((readStringArray(value) ?? []).map((rule) => rule.trim()).filter(Boolean)),
65
+ ];
66
+
67
+ async function readPermissionSource(
68
+ scope: ClaudeSettingsPermissionSource['scope'],
69
+ filePath: string,
70
+ ): Promise<ClaudeSettingsPermissionSource> {
71
+ const empty = { scope, path: filePath, allow: [], deny: [], ask: [] };
72
+
73
+ let content: string;
74
+ try {
75
+ if ((await stat(filePath)).size > MAX_SETTINGS_FILE_BYTES) {
76
+ return { ...empty, status: 'invalid' };
77
+ }
78
+ content = decodeSettingsFile(await readFile(filePath));
79
+ } catch (error) {
80
+ const code = (error as NodeJS.ErrnoException).code;
81
+ return { ...empty, status: code === 'ENOENT' || code === 'ENOTDIR' ? 'missing' : 'invalid' };
82
+ }
83
+
84
+ // The CLI loads an empty or whitespace-only file as `{}`.
85
+ if (!content.trim()) {
86
+ return { ...empty, status: 'ok' };
87
+ }
88
+
89
+ let settings: Record<string, unknown> | null;
90
+ try {
91
+ settings = readObjectRecord(JSON.parse(content));
92
+ } catch {
93
+ settings = null;
94
+ }
95
+ if (!settings) {
96
+ return { ...empty, status: 'invalid' };
97
+ }
98
+
99
+ // A file without a `permissions` block is perfectly valid; it just adds no rules.
100
+ const permissions = readObjectRecord(settings.permissions) ?? {};
101
+ return {
102
+ ...empty,
103
+ status: 'ok',
104
+ allow: readRuleList(permissions.allow),
105
+ deny: readRuleList(permissions.deny),
106
+ ask: readRuleList(permissions.ask),
107
+ };
108
+ }
109
+
110
+ /**
111
+ * Read-only view of the permission rules the Claude CLI applies from its own
112
+ * settings files, on top of the allowed/blocked lists CloudCLI passes it.
113
+ *
114
+ * Used by provider.routes.ts for the Claude permissions panel in Settings.
115
+ * Project-level files are left out on purpose: the panel has no project, and
116
+ * those files only apply to chats started inside their project. CloudCLI never
117
+ * writes to any of these files.
118
+ */
119
+ export const claudeSettingsPermissionsService = {
120
+ /** `managedPath` is only overridden by tests, which cannot write to the system path. */
121
+ async listRuleSources(managedPath: string = managedSettingsPath()): Promise<ClaudeSettingsPermissionSource[]> {
122
+ return Promise.all([
123
+ readPermissionSource('user', userSettingsPath()),
124
+ readPermissionSource('managed', managedPath),
125
+ ]);
126
+ },
127
+ };
@@ -25,6 +25,23 @@ type ProviderCapabilities = {
25
25
  supportsTokenUsage: boolean;
26
26
  /** Whether the provider runtime can accept model-level reasoning effort. */
27
27
  supportsEffort: boolean;
28
+ /**
29
+ * Reasoning-effort levels the runtime can pass on, weakest first, and so the
30
+ * levels a custom model-library entry may declare. Empty exactly when
31
+ * `supportsEffort` is false. Covers every level a predefined model declares
32
+ * (a providers test enforces this) and, unlike the model catalog, does not
33
+ * depend on which upstream providers this machine has connected.
34
+ */
35
+ effortLevels: string[];
36
+ /**
37
+ * Whether an already-sent message can be replaced, which requires the
38
+ * provider to re-run a conversation truncated at a chosen point.
39
+ */
40
+ supportsMessageEditing: boolean;
41
+ /**
42
+ * Whether a session's transcript can be branched into an independent one.
43
+ */
44
+ supportsSessionForking: boolean;
28
45
  };
29
46
 
30
47
  /**
@@ -44,6 +61,11 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
44
61
  supportsPermissionRequests: true,
45
62
  supportsTokenUsage: true,
46
63
  supportsEffort: true,
64
+ effortLevels: ['low', 'medium', 'high', 'xhigh', 'max', 'ultracode'],
65
+ // `resumeSessionAt` re-runs a conversation truncated at a message, and
66
+ // `forkSession` copies a transcript prefix into a new session file.
67
+ supportsMessageEditing: true,
68
+ supportsSessionForking: true,
47
69
  },
48
70
  cursor: {
49
71
  provider: 'cursor',
@@ -55,6 +77,9 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
55
77
  supportsPermissionRequests: false,
56
78
  supportsTokenUsage: false,
57
79
  supportsEffort: false,
80
+ effortLevels: [],
81
+ supportsMessageEditing: false,
82
+ supportsSessionForking: false,
58
83
  },
59
84
  codex: {
60
85
  provider: 'codex',
@@ -66,6 +91,13 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
66
91
  supportsPermissionRequests: false,
67
92
  supportsTokenUsage: true,
68
93
  supportsEffort: true,
94
+ effortLevels: ['low', 'medium', 'high', 'xhigh', 'max', 'ultra'],
95
+ // Not from the Codex SDK, which only starts and resumes threads: both ride
96
+ // the same CLI's `app-server` protocol, whose `thread/fork` copies a
97
+ // thread up to a chosen turn. Editing is that fork plus a new prompt,
98
+ // which is how Codex's own IDE clients do it.
99
+ supportsMessageEditing: true,
100
+ supportsSessionForking: true,
69
101
  },
70
102
  opencode: {
71
103
  provider: 'opencode',
@@ -80,11 +112,18 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
80
112
  supportsPermissionRequests: false,
81
113
  supportsTokenUsage: true,
82
114
  supportsEffort: true,
115
+ // Passed on as OpenCode's `--variant`. `thinking` (MiniMax's on/off
116
+ // variant, paired with `none`) is not a strength, so it sorts last.
117
+ effortLevels: ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'thinking'],
118
+ supportsMessageEditing: false,
119
+ supportsSessionForking: false,
83
120
  },
84
121
  };
85
122
 
86
123
  /**
87
- * Application service exposing the provider capability matrix.
124
+ * Application service exposing the provider capability matrix. Used by the
125
+ * Providers routes (the capabilities endpoints) and by the Providers model
126
+ * service, which reads `effortLevels` to validate custom-model effort.
88
127
  */
89
128
  export const providerCapabilitiesService = {
90
129
  getProviderCapabilities(provider: LLMProvider): ProviderCapabilities {