@cloudcli-ai/cloudcli 1.36.3 → 1.37.1

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 (569) hide show
  1. package/dist/assets/index-D3jfzuKN.css +32 -0
  2. package/dist/assets/index-DTMWjJj8.js +1550 -0
  3. package/dist/index.html +2 -2
  4. package/dist-server/server/constants/config.js.map +1 -1
  5. package/dist-server/server/index.js +73 -1224
  6. package/dist-server/server/index.js.map +1 -1
  7. package/dist-server/server/load-env.js +17 -4
  8. package/dist-server/server/load-env.js.map +1 -1
  9. package/dist-server/server/modules/agent/agent.module.js +37 -0
  10. package/dist-server/server/modules/agent/agent.module.js.map +1 -0
  11. package/dist-server/server/modules/agent/agent.routes.js +1161 -0
  12. package/dist-server/server/modules/agent/agent.routes.js.map +1 -0
  13. package/dist-server/server/modules/agent/index.js +3 -0
  14. package/dist-server/server/modules/agent/index.js.map +1 -0
  15. package/dist-server/server/modules/agent/tests/agent.routes.test.js +176 -0
  16. package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -0
  17. package/dist-server/server/modules/assets/assets.routes.js +56 -15
  18. package/dist-server/server/modules/assets/assets.routes.js.map +1 -1
  19. package/dist-server/server/modules/assets/index.js +2 -2
  20. package/dist-server/server/modules/assets/index.js.map +1 -1
  21. package/dist-server/server/modules/assets/services/image-assets.service.js +39 -1
  22. package/dist-server/server/modules/assets/services/image-assets.service.js.map +1 -1
  23. package/dist-server/server/modules/assets/tests/image-assets.service.test.js +21 -1
  24. package/dist-server/server/modules/assets/tests/image-assets.service.test.js.map +1 -1
  25. package/dist-server/server/{middleware/auth.js → modules/auth/auth.middleware.js} +30 -8
  26. package/dist-server/server/modules/auth/auth.middleware.js.map +1 -0
  27. package/dist-server/server/modules/auth/auth.module.js +29 -0
  28. package/dist-server/server/modules/auth/auth.module.js.map +1 -0
  29. package/dist-server/server/modules/auth/auth.routes.js +45 -0
  30. package/dist-server/server/modules/auth/auth.routes.js.map +1 -0
  31. package/dist-server/server/modules/auth/auth.service.js +113 -0
  32. package/dist-server/server/modules/auth/auth.service.js.map +1 -0
  33. package/dist-server/server/modules/auth/index.js +9 -0
  34. package/dist-server/server/modules/auth/index.js.map +1 -0
  35. package/dist-server/server/modules/auth/tests/auth.service.test.js +80 -0
  36. package/dist-server/server/modules/auth/tests/auth.service.test.js.map +1 -0
  37. package/dist-server/server/{browser-use-mcp.js → modules/browser-use/browser-use-mcp.js} +3 -1
  38. package/dist-server/server/modules/browser-use/browser-use-mcp.js.map +1 -0
  39. package/dist-server/server/modules/browser-use/browser-use.service.js +3 -4
  40. package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
  41. package/dist-server/server/modules/browser-use/index.js +9 -0
  42. package/dist-server/server/modules/browser-use/index.js.map +1 -0
  43. package/dist-server/server/modules/cli/cli.js +11 -0
  44. package/dist-server/server/modules/cli/cli.js.map +1 -0
  45. package/dist-server/server/modules/cli/cli.module.js +86 -0
  46. package/dist-server/server/modules/cli/cli.module.js.map +1 -0
  47. package/dist-server/server/modules/cli/cli.service.js +244 -0
  48. package/dist-server/server/modules/cli/cli.service.js.map +1 -0
  49. package/dist-server/server/modules/cli/index.js +3 -0
  50. package/dist-server/server/modules/cli/index.js.map +1 -0
  51. package/dist-server/server/modules/cli/sandbox.service.js +332 -0
  52. package/dist-server/server/modules/cli/sandbox.service.js.map +1 -0
  53. package/dist-server/server/modules/cli/tests/cli.service.test.js +78 -0
  54. package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -0
  55. package/dist-server/server/modules/cli/tests/sandbox.service.test.js +55 -0
  56. package/dist-server/server/modules/cli/tests/sandbox.service.test.js.map +1 -0
  57. package/dist-server/server/modules/commands/commands.module.js +20 -0
  58. package/dist-server/server/modules/commands/commands.module.js.map +1 -0
  59. package/dist-server/server/modules/commands/commands.routes.js +497 -0
  60. package/dist-server/server/modules/commands/commands.routes.js.map +1 -0
  61. package/dist-server/server/modules/commands/index.js +3 -0
  62. package/dist-server/server/modules/commands/index.js.map +1 -0
  63. package/dist-server/server/modules/commands/tests/commands.test.js +91 -0
  64. package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -0
  65. package/dist-server/server/modules/database/index.js +3 -0
  66. package/dist-server/server/modules/database/index.js.map +1 -1
  67. package/dist-server/server/modules/database/migrations.js +31 -1
  68. package/dist-server/server/modules/database/migrations.js.map +1 -1
  69. package/dist-server/server/modules/database/repositories/provider-models.js +112 -0
  70. package/dist-server/server/modules/database/repositories/provider-models.js.map +1 -0
  71. package/dist-server/server/modules/database/repositories/sessions.db.js +76 -7
  72. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  73. package/dist-server/server/modules/database/schema.js +29 -0
  74. package/dist-server/server/modules/database/schema.js.map +1 -1
  75. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +102 -0
  76. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js.map +1 -0
  77. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +2 -1
  78. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -1
  79. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +22 -0
  80. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
  81. package/dist-server/server/modules/file-tree/file-tree.module.js +95 -0
  82. package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -0
  83. package/dist-server/server/modules/file-tree/file-tree.routes.js +208 -0
  84. package/dist-server/server/modules/file-tree/file-tree.routes.js.map +1 -0
  85. package/dist-server/server/modules/file-tree/file-tree.service.js +576 -0
  86. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -0
  87. package/dist-server/server/modules/file-tree/index.js +3 -0
  88. package/dist-server/server/modules/file-tree/index.js.map +1 -0
  89. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js +123 -0
  90. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js.map +1 -0
  91. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +260 -0
  92. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -0
  93. package/dist-server/server/modules/git/git-parsing.service.js +61 -0
  94. package/dist-server/server/modules/git/git-parsing.service.js.map +1 -0
  95. package/dist-server/server/modules/git/git.module.js +14 -0
  96. package/dist-server/server/modules/git/git.module.js.map +1 -0
  97. package/dist-server/server/modules/git/git.routes.js +1339 -0
  98. package/dist-server/server/modules/git/git.routes.js.map +1 -0
  99. package/dist-server/server/modules/git/index.js +3 -0
  100. package/dist-server/server/modules/git/index.js.map +1 -0
  101. package/dist-server/server/modules/git/tests/git-init.routes.test.js +48 -0
  102. package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -0
  103. package/dist-server/server/{routes → modules/git/tests}/git.test.js +1 -1
  104. package/dist-server/server/modules/git/tests/git.test.js.map +1 -0
  105. package/dist-server/server/modules/notifications/index.js +15 -1
  106. package/dist-server/server/modules/notifications/index.js.map +1 -1
  107. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js +44 -0
  108. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js.map +1 -0
  109. package/dist-server/server/{services/vapid-keys.js → modules/notifications/vapid-keys.service.js} +3 -2
  110. package/dist-server/server/modules/notifications/vapid-keys.service.js.map +1 -0
  111. package/dist-server/server/modules/plugins/index.js +9 -0
  112. package/dist-server/server/modules/plugins/index.js.map +1 -0
  113. package/dist-server/server/{utils/plugin-process-manager.js → modules/plugins/plugin-process.service.js} +3 -2
  114. package/dist-server/server/modules/plugins/plugin-process.service.js.map +1 -0
  115. package/dist-server/server/{utils/plugin-loader.js → modules/plugins/plugin-registry.service.js} +2 -1
  116. package/dist-server/server/modules/plugins/plugin-registry.service.js.map +1 -0
  117. package/dist-server/server/modules/plugins/plugins.module.js +30 -0
  118. package/dist-server/server/modules/plugins/plugins.module.js.map +1 -0
  119. package/dist-server/server/modules/plugins/plugins.routes.js +70 -0
  120. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -0
  121. package/dist-server/server/modules/plugins/plugins.service.js +123 -0
  122. package/dist-server/server/modules/plugins/plugins.service.js.map +1 -0
  123. package/dist-server/server/modules/plugins/tests/plugins.service.test.js +28 -0
  124. package/dist-server/server/modules/plugins/tests/plugins.service.test.js.map +1 -0
  125. package/dist-server/server/modules/projects/index.js +5 -0
  126. package/dist-server/server/modules/projects/index.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 +6 -0
  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-models.provider.js +47 -18
  132. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  133. package/dist-server/server/{claude-sdk.js → modules/providers/list/claude/claude-runtime.provider.js} +69 -55
  134. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -0
  135. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +6 -4
  136. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  137. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +23 -4
  138. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  139. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  140. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  141. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +59 -75
  142. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
  143. package/dist-server/server/{openai-codex.js → modules/providers/list/codex/codex-runtime.provider.js} +48 -34
  144. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -0
  145. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +1 -54
  146. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  147. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +290 -6
  148. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  149. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +5 -0
  150. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -1
  151. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  152. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  153. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +33 -673
  154. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -1
  155. package/dist-server/server/{cursor-cli.js → modules/providers/list/cursor/cursor-runtime.provider.js} +40 -28
  156. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -0
  157. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +21 -14
  158. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  159. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
  160. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
  161. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +112 -333
  162. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
  163. package/dist-server/server/{opencode-cli.js → modules/providers/list/opencode/opencode-runtime.provider.js} +38 -25
  164. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -0
  165. package/dist-server/server/{opencode-cli.test.js → modules/providers/list/opencode/opencode-runtime.provider.test.js} +27 -4
  166. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js.map +1 -0
  167. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +0 -12
  168. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
  169. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +11 -5
  170. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
  171. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +2 -0
  172. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -1
  173. package/dist-server/server/modules/providers/provider.routes.js +169 -37
  174. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  175. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +5 -1
  176. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
  177. package/dist-server/server/modules/providers/services/provider-models.service.js +247 -184
  178. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  179. package/dist-server/server/modules/providers/services/provider-runtime.service.js +66 -0
  180. package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -0
  181. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +268 -0
  182. package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -0
  183. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +12 -4
  184. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
  185. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +2 -0
  186. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  187. package/dist-server/server/modules/providers/services/sessions.service.js +116 -3
  188. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  189. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +2 -3
  190. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
  191. package/dist-server/server/modules/providers/tests/claude-auth.test.js +122 -0
  192. package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -0
  193. package/dist-server/server/modules/providers/tests/claude-sessions.test.js +44 -0
  194. package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -0
  195. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +76 -4
  196. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
  197. package/dist-server/server/modules/providers/tests/opencode-models.test.js +15 -126
  198. package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
  199. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +5 -5
  200. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
  201. package/dist-server/server/modules/providers/tests/{provider-image-history.test.js → provider-attachment-history.test.js} +60 -2
  202. package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js.map +1 -0
  203. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +241 -271
  204. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
  205. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js +126 -0
  206. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js.map +1 -0
  207. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +166 -0
  208. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -0
  209. package/dist-server/server/modules/providers/tests/provider.routes.test.js +126 -0
  210. package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -0
  211. package/dist-server/server/modules/providers/tests/sessions-details.test.js +62 -0
  212. package/dist-server/server/modules/providers/tests/sessions-details.test.js.map +1 -0
  213. package/dist-server/server/modules/providers/tests/sessions.service.test.js +87 -0
  214. package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -0
  215. package/dist-server/server/modules/providers/tests/skills.test.js +4 -2
  216. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  217. package/dist-server/server/modules/settings/index.js +3 -0
  218. package/dist-server/server/modules/settings/index.js.map +1 -0
  219. package/dist-server/server/modules/settings/settings.module.js +35 -0
  220. package/dist-server/server/modules/settings/settings.module.js.map +1 -0
  221. package/dist-server/server/modules/settings/settings.routes.js +34 -0
  222. package/dist-server/server/modules/settings/settings.routes.js.map +1 -0
  223. package/dist-server/server/modules/settings/settings.service.js +116 -0
  224. package/dist-server/server/modules/settings/settings.service.js.map +1 -0
  225. package/dist-server/server/modules/settings/tests/settings.service.test.js +48 -0
  226. package/dist-server/server/modules/settings/tests/settings.service.test.js.map +1 -0
  227. package/dist-server/server/modules/system/index.js +3 -0
  228. package/dist-server/server/modules/system/index.js.map +1 -0
  229. package/dist-server/server/modules/system/system.module.js +44 -0
  230. package/dist-server/server/modules/system/system.module.js.map +1 -0
  231. package/dist-server/server/modules/system/system.routes.js +16 -0
  232. package/dist-server/server/modules/system/system.routes.js.map +1 -0
  233. package/dist-server/server/modules/system/system.service.js +45 -0
  234. package/dist-server/server/modules/system/system.service.js.map +1 -0
  235. package/dist-server/server/modules/system/tests/system.service.test.js +100 -0
  236. package/dist-server/server/modules/system/tests/system.service.test.js.map +1 -0
  237. package/dist-server/server/modules/taskmaster/index.js +3 -0
  238. package/dist-server/server/modules/taskmaster/index.js.map +1 -0
  239. package/dist-server/server/modules/taskmaster/taskmaster.module.js +20 -0
  240. package/dist-server/server/modules/taskmaster/taskmaster.module.js.map +1 -0
  241. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +1372 -0
  242. package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -0
  243. package/dist-server/server/modules/taskmaster/taskmaster.service.js +107 -0
  244. package/dist-server/server/modules/taskmaster/taskmaster.service.js.map +1 -0
  245. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +132 -0
  246. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -0
  247. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js +85 -0
  248. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js.map +1 -0
  249. package/dist-server/server/modules/user/index.js +3 -0
  250. package/dist-server/server/modules/user/index.js.map +1 -0
  251. package/dist-server/server/modules/user/tests/user.service.test.js +53 -0
  252. package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -0
  253. package/dist-server/server/modules/user/user.module.js +47 -0
  254. package/dist-server/server/modules/user/user.module.js.map +1 -0
  255. package/dist-server/server/modules/user/user.routes.js +44 -0
  256. package/dist-server/server/modules/user/user.routes.js.map +1 -0
  257. package/dist-server/server/modules/user/user.service.js +59 -0
  258. package/dist-server/server/modules/user/user.service.js.map +1 -0
  259. package/dist-server/server/modules/voice/index.js +3 -0
  260. package/dist-server/server/modules/voice/index.js.map +1 -0
  261. package/dist-server/server/modules/voice/tests/voice.service.test.js +86 -0
  262. package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -0
  263. package/dist-server/server/modules/voice/voice.module.js +44 -0
  264. package/dist-server/server/modules/voice/voice.module.js.map +1 -0
  265. package/dist-server/server/modules/voice/voice.routes.js +87 -0
  266. package/dist-server/server/modules/voice/voice.routes.js.map +1 -0
  267. package/dist-server/server/modules/voice/voice.service.js +148 -0
  268. package/dist-server/server/modules/voice/voice.service.js.map +1 -0
  269. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +2 -2
  270. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +44 -29
  271. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  272. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +76 -8
  273. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  274. package/dist-server/server/modules/websocket/services/websocket-server.service.js +51 -20
  275. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -1
  276. package/dist-server/server/modules/websocket/tests/{chat-image-filter.test.js → chat-attachment-filter.test.js} +10 -3
  277. package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js.map +1 -0
  278. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +97 -0
  279. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -0
  280. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js +61 -0
  281. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js.map +1 -0
  282. package/dist-server/server/modules/worktrees/index.js +3 -0
  283. package/dist-server/server/modules/worktrees/index.js.map +1 -0
  284. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js +37 -0
  285. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js.map +1 -0
  286. package/dist-server/server/modules/worktrees/services/worktree-create.service.js +67 -0
  287. package/dist-server/server/modules/worktrees/services/worktree-create.service.js.map +1 -0
  288. package/dist-server/server/modules/worktrees/services/worktree-git.service.js +172 -0
  289. package/dist-server/server/modules/worktrees/services/worktree-git.service.js.map +1 -0
  290. package/dist-server/server/modules/worktrees/services/worktree-list.service.js +91 -0
  291. package/dist-server/server/modules/worktrees/services/worktree-list.service.js.map +1 -0
  292. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js +118 -0
  293. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js.map +1 -0
  294. package/dist-server/server/modules/worktrees/services/worktree-open.service.js +58 -0
  295. package/dist-server/server/modules/worktrees/services/worktree-open.service.js.map +1 -0
  296. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +65 -0
  297. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js.map +1 -0
  298. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js +58 -0
  299. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js.map +1 -0
  300. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js +85 -0
  301. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js.map +1 -0
  302. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js +58 -0
  303. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js.map +1 -0
  304. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js +34 -0
  305. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js.map +1 -0
  306. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js +137 -0
  307. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js.map +1 -0
  308. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js +99 -0
  309. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js.map +1 -0
  310. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js +157 -0
  311. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js.map +1 -0
  312. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js +167 -0
  313. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js.map +1 -0
  314. package/dist-server/server/modules/worktrees/worktrees.module.js +97 -0
  315. package/dist-server/server/modules/worktrees/worktrees.module.js.map +1 -0
  316. package/dist-server/server/modules/worktrees/worktrees.routes.js +84 -0
  317. package/dist-server/server/modules/worktrees/worktrees.routes.js.map +1 -0
  318. package/dist-server/server/shared/image-attachments.js +90 -17
  319. package/dist-server/server/shared/image-attachments.js.map +1 -1
  320. package/dist-server/server/shared/tests/image-attachments.test.js +43 -1
  321. package/dist-server/server/shared/tests/image-attachments.test.js.map +1 -1
  322. package/dist-server/server/shared/utils.js +66 -142
  323. package/dist-server/server/shared/utils.js.map +1 -1
  324. package/package.json +9 -5
  325. package/server/index.ts +401 -0
  326. package/server/{load-env.js → load-env.ts} +18 -5
  327. package/server/modules/agent/agent.module.ts +51 -0
  328. package/server/modules/agent/agent.routes.ts +1287 -0
  329. package/server/modules/agent/index.ts +2 -0
  330. package/server/modules/agent/tests/agent.routes.test.ts +205 -0
  331. package/server/modules/assets/assets.routes.ts +63 -16
  332. package/server/modules/assets/index.ts +2 -2
  333. package/server/modules/assets/services/image-assets.service.ts +46 -1
  334. package/server/modules/assets/tests/image-assets.service.test.ts +28 -0
  335. package/server/{middleware/auth.js → modules/auth/auth.middleware.ts} +38 -7
  336. package/server/modules/auth/auth.module.ts +38 -0
  337. package/server/modules/auth/auth.routes.ts +57 -0
  338. package/server/modules/auth/auth.service.ts +155 -0
  339. package/server/modules/auth/index.ts +9 -0
  340. package/server/modules/auth/tests/auth.service.test.ts +95 -0
  341. package/server/{browser-use-mcp.ts → modules/browser-use/browser-use-mcp.ts} +3 -1
  342. package/server/modules/browser-use/browser-use.service.ts +3 -4
  343. package/server/modules/browser-use/index.ts +8 -0
  344. package/server/modules/cli/cli.module.ts +96 -0
  345. package/server/modules/cli/cli.service.ts +281 -0
  346. package/server/modules/cli/cli.ts +13 -0
  347. package/server/modules/cli/index.ts +2 -0
  348. package/server/modules/cli/sandbox.service.ts +413 -0
  349. package/server/modules/cli/tests/cli.service.test.ts +91 -0
  350. package/server/modules/cli/tests/sandbox.service.test.ts +61 -0
  351. package/server/modules/commands/commands.module.ts +22 -0
  352. package/server/{routes/commands.js → modules/commands/commands.routes.ts} +46 -38
  353. package/server/modules/commands/index.ts +2 -0
  354. package/server/modules/commands/tests/commands.test.ts +114 -0
  355. package/server/modules/database/index.ts +3 -0
  356. package/server/modules/database/migrations.ts +35 -0
  357. package/server/modules/database/repositories/provider-models.ts +168 -0
  358. package/server/modules/database/repositories/sessions.db.ts +103 -8
  359. package/server/modules/database/schema.ts +30 -0
  360. package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -0
  361. package/server/modules/database/tests/sessions-provider-mapping.test.ts +2 -1
  362. package/server/modules/database/tests/sessions.db.integration.test.ts +32 -0
  363. package/server/modules/file-tree/file-tree.module.ts +116 -0
  364. package/server/modules/file-tree/file-tree.routes.ts +258 -0
  365. package/server/modules/file-tree/file-tree.service.ts +664 -0
  366. package/server/modules/file-tree/index.ts +2 -0
  367. package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -0
  368. package/server/modules/file-tree/tests/file-tree.service.test.ts +317 -0
  369. package/server/modules/git/git-parsing.service.ts +66 -0
  370. package/server/modules/git/git.module.ts +22 -0
  371. package/server/{routes/git.js → modules/git/git.routes.ts} +91 -132
  372. package/server/modules/git/index.ts +2 -0
  373. package/server/modules/git/tests/git-init.routes.test.ts +52 -0
  374. package/server/{routes/git.test.js → modules/git/tests/git.test.ts} +3 -3
  375. package/server/modules/notifications/index.ts +9 -0
  376. package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -0
  377. package/server/{services/vapid-keys.js → modules/notifications/vapid-keys.service.ts} +3 -1
  378. package/server/modules/plugins/index.ts +9 -0
  379. package/server/{utils/plugin-process-manager.js → modules/plugins/plugin-process.service.ts} +3 -1
  380. package/server/{utils/plugin-loader.js → modules/plugins/plugin-registry.service.ts} +1 -0
  381. package/server/modules/plugins/plugins.module.ts +33 -0
  382. package/server/modules/plugins/plugins.routes.ts +66 -0
  383. package/server/modules/plugins/plugins.service.ts +147 -0
  384. package/server/modules/plugins/tests/plugins.service.test.ts +32 -0
  385. package/server/modules/projects/index.ts +5 -0
  386. package/server/modules/providers/README.md +41 -9
  387. package/server/modules/providers/index.ts +4 -0
  388. package/server/modules/providers/list/claude/claude-auth.provider.ts +8 -0
  389. package/server/modules/providers/list/claude/claude-models.provider.ts +47 -26
  390. package/server/{claude-sdk.js → modules/providers/list/claude/claude-runtime.provider.js} +73 -59
  391. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +6 -4
  392. package/server/modules/providers/list/claude/claude-sessions.provider.ts +27 -4
  393. package/server/modules/providers/list/claude/claude.provider.ts +3 -0
  394. package/server/modules/providers/list/codex/codex-models.provider.ts +58 -108
  395. package/server/{openai-codex.js → modules/providers/list/codex/codex-runtime.provider.js} +54 -36
  396. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +1 -60
  397. package/server/modules/providers/list/codex/codex-sessions.provider.ts +331 -7
  398. package/server/modules/providers/list/codex/codex-skills.provider.ts +5 -0
  399. package/server/modules/providers/list/codex/codex.provider.ts +3 -0
  400. package/server/modules/providers/list/cursor/cursor-models.provider.ts +32 -719
  401. package/server/{cursor-cli.js → modules/providers/list/cursor/cursor-runtime.provider.js} +58 -27
  402. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +26 -15
  403. package/server/modules/providers/list/cursor/cursor.provider.ts +3 -0
  404. package/server/modules/providers/list/opencode/opencode-models.provider.ts +112 -423
  405. package/server/{opencode-cli.js → modules/providers/list/opencode/opencode-runtime.provider.js} +56 -28
  406. package/server/{opencode-cli.test.js → modules/providers/list/opencode/opencode-runtime.provider.test.js} +41 -3
  407. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +0 -13
  408. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +13 -5
  409. package/server/modules/providers/list/opencode/opencode.provider.ts +3 -0
  410. package/server/modules/providers/provider.routes.ts +228 -39
  411. package/server/modules/providers/services/provider-capabilities.service.ts +7 -1
  412. package/server/modules/providers/services/provider-models.service.ts +312 -269
  413. package/server/modules/providers/services/provider-runtime.service.ts +108 -0
  414. package/server/modules/providers/services/provider-token-usage.service.ts +357 -0
  415. package/server/modules/providers/services/session-conversations-search.service.ts +12 -4
  416. package/server/modules/providers/services/sessions-watcher.service.ts +2 -0
  417. package/server/modules/providers/services/sessions.service.ts +166 -3
  418. package/server/modules/providers/shared/base/abstract.provider.ts +4 -3
  419. package/server/modules/providers/tests/claude-auth.test.ts +150 -0
  420. package/server/modules/providers/tests/claude-sessions.test.ts +61 -0
  421. package/server/modules/providers/tests/codex-sessions.test.ts +83 -4
  422. package/server/modules/providers/tests/opencode-models.test.ts +34 -135
  423. package/server/modules/providers/tests/opencode-sessions.test.ts +5 -5
  424. package/server/modules/providers/tests/{provider-image-history.test.ts → provider-attachment-history.test.ts} +68 -1
  425. package/server/modules/providers/tests/provider-models.service.test.ts +300 -296
  426. package/server/modules/providers/tests/provider-runtime.service.test.ts +138 -0
  427. package/server/modules/providers/tests/provider-token-usage.service.test.ts +186 -0
  428. package/server/modules/providers/tests/provider.routes.test.ts +183 -0
  429. package/server/modules/providers/tests/sessions-details.test.ts +73 -0
  430. package/server/modules/providers/tests/sessions.service.test.ts +127 -0
  431. package/server/modules/providers/tests/skills.test.ts +9 -2
  432. package/server/modules/settings/index.ts +2 -0
  433. package/server/modules/settings/settings.module.ts +50 -0
  434. package/server/modules/settings/settings.routes.ts +51 -0
  435. package/server/modules/settings/settings.service.ts +186 -0
  436. package/server/modules/settings/tests/settings.service.test.ts +54 -0
  437. package/server/modules/system/index.ts +2 -0
  438. package/server/modules/system/system.module.ts +62 -0
  439. package/server/modules/system/system.routes.ts +21 -0
  440. package/server/modules/system/system.service.ts +76 -0
  441. package/server/modules/system/tests/system.service.test.ts +118 -0
  442. package/server/modules/taskmaster/index.ts +2 -0
  443. package/server/modules/taskmaster/taskmaster.module.ts +24 -0
  444. package/server/modules/taskmaster/taskmaster.routes.ts +1482 -0
  445. package/server/modules/taskmaster/taskmaster.service.ts +132 -0
  446. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +144 -0
  447. package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -0
  448. package/server/modules/user/index.ts +2 -0
  449. package/server/modules/user/tests/user.service.test.ts +61 -0
  450. package/server/modules/user/user.module.ts +58 -0
  451. package/server/modules/user/user.routes.ts +50 -0
  452. package/server/modules/user/user.service.ts +85 -0
  453. package/server/modules/voice/index.ts +2 -0
  454. package/server/modules/voice/tests/voice.service.test.ts +98 -0
  455. package/server/modules/voice/voice.module.ts +47 -0
  456. package/server/modules/voice/voice.routes.ts +113 -0
  457. package/server/modules/voice/voice.service.ts +192 -0
  458. package/server/modules/websocket/README.md +7 -7
  459. package/server/modules/websocket/services/chat-session-writer.service.ts +2 -2
  460. package/server/modules/websocket/services/chat-websocket.service.ts +77 -61
  461. package/server/modules/websocket/services/shell-websocket.service.ts +88 -12
  462. package/server/modules/websocket/services/websocket-server.service.ts +63 -19
  463. package/server/modules/websocket/tests/{chat-image-filter.test.ts → chat-attachment-filter.test.ts} +17 -2
  464. package/server/modules/websocket/tests/shell-websocket.service.test.ts +119 -0
  465. package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -0
  466. package/server/modules/worktrees/index.ts +2 -0
  467. package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -0
  468. package/server/modules/worktrees/services/worktree-create.service.ts +104 -0
  469. package/server/modules/worktrees/services/worktree-git.service.ts +207 -0
  470. package/server/modules/worktrees/services/worktree-list.service.ts +143 -0
  471. package/server/modules/worktrees/services/worktree-merge.service.ts +157 -0
  472. package/server/modules/worktrees/services/worktree-open.service.ts +85 -0
  473. package/server/modules/worktrees/services/worktree-remove.service.ts +88 -0
  474. package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -0
  475. package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -0
  476. package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -0
  477. package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -0
  478. package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -0
  479. package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -0
  480. package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -0
  481. package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -0
  482. package/server/modules/worktrees/worktrees.module.ts +113 -0
  483. package/server/modules/worktrees/worktrees.routes.ts +116 -0
  484. package/server/shared/image-attachments.ts +112 -18
  485. package/server/shared/interfaces.ts +33 -25
  486. package/server/shared/tests/image-attachments.test.ts +55 -0
  487. package/server/shared/types.ts +685 -36
  488. package/server/shared/utils.ts +77 -212
  489. package/dist/assets/index-CcCsKitq.js +0 -1423
  490. package/dist/assets/index-DLmhQ15L.css +0 -32
  491. package/dist-server/server/browser-use-mcp.js.map +0 -1
  492. package/dist-server/server/claude-sdk.js.map +0 -1
  493. package/dist-server/server/cli.js +0 -647
  494. package/dist-server/server/cli.js.map +0 -1
  495. package/dist-server/server/cursor-cli.js.map +0 -1
  496. package/dist-server/server/middleware/auth.js.map +0 -1
  497. package/dist-server/server/modules/providers/tests/provider-image-history.test.js.map +0 -1
  498. package/dist-server/server/modules/websocket/tests/chat-image-filter.test.js.map +0 -1
  499. package/dist-server/server/openai-codex.js.map +0 -1
  500. package/dist-server/server/opencode-cli.js.map +0 -1
  501. package/dist-server/server/opencode-cli.test.js.map +0 -1
  502. package/dist-server/server/routes/agent.js +0 -1155
  503. package/dist-server/server/routes/agent.js.map +0 -1
  504. package/dist-server/server/routes/auth.js +0 -119
  505. package/dist-server/server/routes/auth.js.map +0 -1
  506. package/dist-server/server/routes/commands.js +0 -492
  507. package/dist-server/server/routes/commands.js.map +0 -1
  508. package/dist-server/server/routes/cursor.js +0 -49
  509. package/dist-server/server/routes/cursor.js.map +0 -1
  510. package/dist-server/server/routes/git.js +0 -1389
  511. package/dist-server/server/routes/git.js.map +0 -1
  512. package/dist-server/server/routes/git.test.js.map +0 -1
  513. package/dist-server/server/routes/mcp-utils.js +0 -29
  514. package/dist-server/server/routes/mcp-utils.js.map +0 -1
  515. package/dist-server/server/routes/plugins.js +0 -266
  516. package/dist-server/server/routes/plugins.js.map +0 -1
  517. package/dist-server/server/routes/settings.js +0 -249
  518. package/dist-server/server/routes/settings.js.map +0 -1
  519. package/dist-server/server/routes/taskmaster.js +0 -1362
  520. package/dist-server/server/routes/taskmaster.js.map +0 -1
  521. package/dist-server/server/routes/tests/commands.test.js +0 -76
  522. package/dist-server/server/routes/tests/commands.test.js.map +0 -1
  523. package/dist-server/server/routes/user.js +0 -116
  524. package/dist-server/server/routes/user.js.map +0 -1
  525. package/dist-server/server/services/notification-orchestrator.js +0 -2
  526. package/dist-server/server/services/notification-orchestrator.js.map +0 -1
  527. package/dist-server/server/services/tests/notification-orchestrator.test.js +0 -64
  528. package/dist-server/server/services/tests/notification-orchestrator.test.js.map +0 -1
  529. package/dist-server/server/services/vapid-keys.js.map +0 -1
  530. package/dist-server/server/utils/colors.js +0 -20
  531. package/dist-server/server/utils/colors.js.map +0 -1
  532. package/dist-server/server/utils/commandParser.js +0 -255
  533. package/dist-server/server/utils/commandParser.js.map +0 -1
  534. package/dist-server/server/utils/gitConfig.js +0 -37
  535. package/dist-server/server/utils/gitConfig.js.map +0 -1
  536. package/dist-server/server/utils/mcp-detector.js +0 -134
  537. package/dist-server/server/utils/mcp-detector.js.map +0 -1
  538. package/dist-server/server/utils/plugin-loader.js.map +0 -1
  539. package/dist-server/server/utils/plugin-process-manager.js.map +0 -1
  540. package/dist-server/server/utils/runtime-paths.js +0 -30
  541. package/dist-server/server/utils/runtime-paths.js.map +0 -1
  542. package/dist-server/server/utils/taskmaster-websocket.js +0 -124
  543. package/dist-server/server/utils/taskmaster-websocket.js.map +0 -1
  544. package/dist-server/server/utils/url-detection.js +0 -58
  545. package/dist-server/server/utils/url-detection.js.map +0 -1
  546. package/dist-server/server/voice-proxy.js +0 -226
  547. package/dist-server/server/voice-proxy.js.map +0 -1
  548. package/server/cli.js +0 -695
  549. package/server/index.js +0 -1651
  550. package/server/routes/agent.js +0 -1257
  551. package/server/routes/auth.js +0 -137
  552. package/server/routes/cursor.js +0 -52
  553. package/server/routes/mcp-utils.js +0 -31
  554. package/server/routes/plugins.js +0 -307
  555. package/server/routes/settings.js +0 -282
  556. package/server/routes/taskmaster.js +0 -1470
  557. package/server/routes/tests/commands.test.js +0 -82
  558. package/server/routes/user.js +0 -124
  559. package/server/services/notification-orchestrator.js +0 -7
  560. package/server/services/tests/notification-orchestrator.test.js +0 -80
  561. package/server/utils/colors.js +0 -21
  562. package/server/utils/commandParser.js +0 -305
  563. package/server/utils/gitConfig.js +0 -35
  564. package/server/utils/mcp-detector.js +0 -147
  565. package/server/utils/runtime-paths.js +0 -37
  566. package/server/utils/taskmaster-websocket.js +0 -135
  567. package/server/utils/url-detection.js +0 -71
  568. package/server/voice-proxy.js +0 -224
  569. /package/server/constants/{config.js → config.ts} +0 -0
@@ -1,358 +1,401 @@
1
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
-
1
+ import { providerModelsDb, sessionsDb } from '@/modules/database/index.js';
5
2
  import { providerRegistry } from '@/modules/providers/provider.registry.js';
6
3
  import type { IProvider } from '@/shared/interfaces.js';
7
4
  import type {
5
+ CustomProviderModelInput,
6
+ CustomProviderModelRecord,
8
7
  LLMProvider,
9
- ProviderChangeActiveModelInput,
10
8
  ProviderCurrentActiveModel,
11
- ProviderModelsCacheInfo,
9
+ ProviderModelOption,
12
10
  ProviderModelsDefinition,
13
- ProviderModelsResult,
14
- ProviderSessionActiveModelChange,
11
+ ProviderSessionModel,
15
12
  } from '@/shared/types.js';
16
- import { readProviderSessionActiveModelChange } from '@/shared/utils.js';
13
+ import { AppError } from '@/shared/utils.js';
14
+
15
+ /** Session-row access the service needs, narrowed so tests can stub it. */
16
+ type ProviderModelsSessionStore = {
17
+ getSessionById(sessionId: string): { model: string | null; effort: string | null } | null;
18
+ setSessionModel(sessionId: string, model: string): void;
19
+ setSessionEffort(sessionId: string, effort: string): void;
20
+ };
17
21
 
18
- export const PROVIDER_MODELS_CACHE_TTL_MS = 3 * 24 * 60 * 60 * 1000;
19
- const PROVIDER_MODELS_CACHE_VERSION = 2;
20
- const UNCACHED_PROVIDERS = new Set<LLMProvider>(['claude']);
22
+ /** SQLite catalog operations used by the Providers service and its unit fakes. */
23
+ type ProviderModelsCatalogStore = Pick<
24
+ typeof providerModelsDb,
25
+ | 'listCustomProviderModels'
26
+ | 'getCustomProviderModel'
27
+ | 'findCustomProviderModelByModelId'
28
+ | 'createCustomProviderModel'
29
+ | 'updateCustomProviderModel'
30
+ | 'deleteCustomProviderModel'
31
+ >;
21
32
 
22
33
  type ProviderModelsServiceDependencies = {
23
34
  resolveProvider?: (provider: LLMProvider) => Pick<IProvider, 'models'>;
24
- cachePath?: string;
25
- activeModelChangesPath?: string;
26
- now?: () => number;
27
- };
28
-
29
- type ProviderModelsOptions = {
30
- bypassCache?: boolean;
35
+ catalog?: ProviderModelsCatalogStore;
36
+ sessions?: ProviderModelsSessionStore;
31
37
  };
32
38
 
33
- type ProviderModelsCacheEntry = {
34
- updatedAt: number;
35
- expiresAt: number;
36
- models: ProviderModelsDefinition;
37
- };
39
+ const toCustomProviderModelOption = (
40
+ record: CustomProviderModelRecord,
41
+ ): ProviderModelOption => ({
42
+ value: record.modelId,
43
+ label: record.model,
44
+ recordId: record.recordId,
45
+ isCustom: true,
46
+ });
38
47
 
39
- type ProviderModelsCacheFile = {
40
- version: number;
41
- entries: Record<string, ProviderModelsCacheEntry>;
48
+ const mergeProviderModels = (
49
+ predefined: ProviderModelsDefinition,
50
+ custom: CustomProviderModelRecord[],
51
+ ): ProviderModelsDefinition => {
52
+ return {
53
+ OPTIONS: [
54
+ ...predefined.OPTIONS.map((option) => ({ ...option, isCustom: false })),
55
+ ...custom.map(toCustomProviderModelOption),
56
+ ],
57
+ DEFAULT: predefined.DEFAULT,
58
+ };
42
59
  };
43
60
 
44
- const getProviderModelsCachePath = (): string => path.join(
45
- os.homedir(),
46
- '.cloudcli',
47
- 'provider-models-cache.json',
48
- );
49
-
50
- const toProviderModelsCacheInfo = (
51
- entry: ProviderModelsCacheEntry,
52
- source: ProviderModelsCacheInfo['source'],
53
- ): ProviderModelsCacheInfo => ({
54
- updatedAt: new Date(entry.updatedAt).toISOString(),
55
- expiresAt: new Date(entry.expiresAt).toISOString(),
56
- source,
61
+ const normalizeCustomModelInput = (input: CustomProviderModelInput): CustomProviderModelInput => ({
62
+ id: input.id.trim(),
63
+ model: input.model.trim(),
57
64
  });
58
65
 
59
- const isProviderModelOption = (
60
- value: unknown,
61
- ): value is ProviderModelsDefinition['OPTIONS'][number] => (
62
- Boolean(value)
63
- && typeof value === 'object'
64
- && typeof (value as ProviderModelsDefinition['OPTIONS'][number]).value === 'string'
65
- && typeof (value as ProviderModelsDefinition['OPTIONS'][number]).label === 'string'
66
- && (
67
- typeof (value as ProviderModelsDefinition['OPTIONS'][number]).description === 'undefined'
68
- || typeof (value as ProviderModelsDefinition['OPTIONS'][number]).description === 'string'
69
- )
70
- );
71
-
72
- const isProviderModelsDefinition = (value: unknown): value is ProviderModelsDefinition => (
73
- Boolean(value)
74
- && typeof value === 'object'
75
- && Array.isArray((value as ProviderModelsDefinition).OPTIONS)
76
- && (value as ProviderModelsDefinition).OPTIONS.every(isProviderModelOption)
77
- && typeof (value as ProviderModelsDefinition).DEFAULT === 'string'
78
- );
79
-
80
- const isProviderModelsCacheEntry = (value: unknown): value is ProviderModelsCacheEntry => (
81
- Boolean(value)
82
- && typeof value === 'object'
83
- && typeof (value as ProviderModelsCacheEntry).updatedAt === 'number'
84
- && typeof (value as ProviderModelsCacheEntry).expiresAt === 'number'
85
- && isProviderModelsDefinition((value as ProviderModelsCacheEntry).models)
66
+ const isUniqueConstraintError = (error: unknown): boolean => (
67
+ error !== null
68
+ && error !== undefined
69
+ && typeof error === 'object'
70
+ && 'code' in error
71
+ && String(error.code).startsWith('SQLITE_CONSTRAINT')
86
72
  );
87
73
 
88
- const readProviderModelsCacheFile = async (
89
- cachePath: string,
90
- ): Promise<ProviderModelsCacheFile | null> => {
91
- try {
92
- const raw = await readFile(cachePath, 'utf8');
93
- const parsed = JSON.parse(raw) as Partial<ProviderModelsCacheFile>;
94
- if (parsed.version !== PROVIDER_MODELS_CACHE_VERSION || !parsed.entries || typeof parsed.entries !== 'object') {
95
- return null;
96
- }
97
-
98
- const entries = Object.fromEntries(
99
- Object.entries(parsed.entries).filter((entry): entry is [string, ProviderModelsCacheEntry] =>
100
- isProviderModelsCacheEntry(entry[1]),
101
- ),
102
- );
103
-
104
- return {
105
- version: PROVIDER_MODELS_CACHE_VERSION,
106
- entries,
107
- };
108
- } catch {
109
- return null;
110
- }
111
- };
112
-
113
- const writeProviderModelsCacheFile = async (
114
- cachePath: string,
115
- entries: Map<LLMProvider, ProviderModelsCacheEntry>,
116
- now: number,
117
- ): Promise<void> => {
118
- const serializableEntries = Object.fromEntries(
119
- [...entries.entries()].filter(([, entry]) => entry.expiresAt > now),
120
- );
121
- const payload: ProviderModelsCacheFile = {
122
- version: PROVIDER_MODELS_CACHE_VERSION,
123
- entries: serializableEntries,
124
- };
125
-
126
- await mkdir(path.dirname(cachePath), { recursive: true });
127
- await writeFile(cachePath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
128
- };
129
-
130
74
  /**
131
- * Provider model lookup service.
75
+ * Creates the provider model application service used by Providers routes,
76
+ * Commands, and provider runtimes.
132
77
  *
133
- * Routes and other service callers use this layer instead of resolving provider
134
- * classes directly so the provider-registry dependency stays centralized in one
135
- * place.
78
+ * Curated adapter definitions stay source-controlled and are merged at read
79
+ * time with custom SQLite rows. This deliberately has no predefined-model
80
+ * persistence, memory cache, disk cache, TTL, or provider-native discovery.
81
+ * Tests inject a small custom-model store through the same boundary.
136
82
  */
137
83
  export const createProviderModelsService = (dependencies: ProviderModelsServiceDependencies = {}) => {
138
84
  const resolveProvider = dependencies.resolveProvider ?? providerRegistry.resolveProvider;
139
- const cachePath = dependencies.cachePath ?? getProviderModelsCachePath();
140
- const activeModelChangesPath = dependencies.activeModelChangesPath;
141
- const now = dependencies.now ?? (() => Date.now());
142
- const memoryCache = new Map<LLMProvider, ProviderModelsCacheEntry>();
143
- const pendingRequests = new Map<LLMProvider, Promise<ProviderModelsResult>>();
144
- let persistedCacheLoaded = false;
145
- let persistedCacheLoadPromise: Promise<void> | null = null;
146
-
147
- const pruneExpiredMemoryEntry = (
85
+ const catalog = dependencies.catalog ?? providerModelsDb;
86
+ const sessions = dependencies.sessions ?? sessionsDb;
87
+
88
+ const getProviderModels = async (provider: LLMProvider): Promise<ProviderModelsDefinition> => {
89
+ const predefined = await resolveProvider(provider).models.getSupportedModels();
90
+ return mergeProviderModels(predefined, catalog.listCustomProviderModels(provider));
91
+ };
92
+
93
+ const getCurrentActiveModel = async (
148
94
  provider: LLMProvider,
149
- currentTime: number,
150
- source: ProviderModelsCacheInfo['source'],
151
- ): ProviderModelsResult | null => {
152
- const cachedEntry = memoryCache.get(provider);
153
- if (!cachedEntry) {
154
- return null;
155
- }
95
+ sessionId?: string,
96
+ ): Promise<ProviderCurrentActiveModel> => resolveProvider(provider).models.getCurrentActiveModel(sessionId);
156
97
 
157
- if (cachedEntry.expiresAt > currentTime) {
158
- return {
159
- models: cachedEntry.models,
160
- cache: toProviderModelsCacheInfo(cachedEntry, source),
161
- };
98
+ const readCustomModel = (
99
+ provider: LLMProvider,
100
+ recordId: number,
101
+ ): CustomProviderModelRecord => {
102
+ const existing = catalog.getCustomProviderModel(provider, recordId);
103
+ if (!existing) {
104
+ throw new AppError('Model not found.', {
105
+ code: 'MODEL_NOT_FOUND',
106
+ statusCode: 404,
107
+ });
162
108
  }
163
109
 
164
- memoryCache.delete(provider);
165
- return null;
110
+ return existing;
166
111
  };
167
112
 
168
- const loadPersistedCache = async (): Promise<void> => {
169
- if (persistedCacheLoaded) {
170
- return;
113
+ const assertModelIdAvailable = (
114
+ provider: LLMProvider,
115
+ predefined: ProviderModelsDefinition,
116
+ modelId: string,
117
+ currentRecordId?: number,
118
+ ): void => {
119
+ if (predefined.OPTIONS.some((option) => option.value === modelId)) {
120
+ throw new AppError(`A ${provider} model with this ID already exists.`, {
121
+ code: 'MODEL_ID_ALREADY_EXISTS',
122
+ statusCode: 409,
123
+ });
171
124
  }
172
125
 
173
- if (!persistedCacheLoadPromise) {
174
- persistedCacheLoadPromise = (async () => {
175
- const cacheFile = await readProviderModelsCacheFile(cachePath);
176
- const currentTime = now();
177
-
178
- for (const [provider, entry] of Object.entries(cacheFile?.entries ?? {})) {
179
- if (entry.expiresAt > currentTime) {
180
- memoryCache.set(provider as LLMProvider, entry);
181
- }
182
- }
183
-
184
- persistedCacheLoaded = true;
185
- })().finally(() => {
186
- persistedCacheLoadPromise = null;
126
+ const duplicate = catalog.findCustomProviderModelByModelId(provider, modelId);
127
+ if (duplicate && duplicate.recordId !== currentRecordId) {
128
+ throw new AppError(`A ${provider} model with this ID already exists.`, {
129
+ code: 'MODEL_ID_ALREADY_EXISTS',
130
+ statusCode: 409,
187
131
  });
188
132
  }
189
-
190
- await persistedCacheLoadPromise;
191
133
  };
192
134
 
193
- const persistCache = async (): Promise<void> => {
135
+ const createCustomModel = async (
136
+ provider: LLMProvider,
137
+ input: CustomProviderModelInput,
138
+ ): Promise<{ model: ProviderModelOption; models: ProviderModelsDefinition }> => {
139
+ const predefined = await resolveProvider(provider).models.getSupportedModels();
140
+ const normalized = normalizeCustomModelInput(input);
141
+ assertModelIdAvailable(provider, predefined, normalized.id);
142
+
194
143
  try {
195
- await writeProviderModelsCacheFile(cachePath, memoryCache, now());
144
+ const created = catalog.createCustomProviderModel(provider, normalized);
145
+ return {
146
+ model: toCustomProviderModelOption(created),
147
+ models: mergeProviderModels(predefined, catalog.listCustomProviderModels(provider)),
148
+ };
196
149
  } catch (error) {
197
- console.warn('Unable to persist provider models cache:', error);
150
+ if (isUniqueConstraintError(error)) {
151
+ throw new AppError(`A ${provider} model with this ID already exists.`, {
152
+ code: 'MODEL_ID_ALREADY_EXISTS',
153
+ statusCode: 409,
154
+ });
155
+ }
156
+ throw error;
198
157
  }
199
158
  };
200
159
 
201
- const setCacheEntry = async (
160
+ const updateCustomModel = async (
202
161
  provider: LLMProvider,
203
- models: ProviderModelsDefinition,
204
- ): Promise<ProviderModelsCacheEntry> => {
205
- const currentTime = now();
206
- const entry: ProviderModelsCacheEntry = {
207
- updatedAt: currentTime,
208
- expiresAt: currentTime + PROVIDER_MODELS_CACHE_TTL_MS,
209
- models,
210
- };
162
+ recordId: number,
163
+ input: CustomProviderModelInput,
164
+ ): Promise<{ model: ProviderModelOption; models: ProviderModelsDefinition }> => {
165
+ const predefined = await resolveProvider(provider).models.getSupportedModels();
166
+ readCustomModel(provider, recordId);
167
+ const normalized = normalizeCustomModelInput(input);
168
+ assertModelIdAvailable(provider, predefined, normalized.id, recordId);
169
+
170
+ try {
171
+ const updated = catalog.updateCustomProviderModel(provider, recordId, normalized);
172
+ if (!updated) {
173
+ throw new AppError('Model not found.', {
174
+ code: 'MODEL_NOT_FOUND',
175
+ statusCode: 404,
176
+ });
177
+ }
211
178
 
212
- memoryCache.set(provider, entry);
213
- await persistCache();
214
- return entry;
179
+ return {
180
+ model: toCustomProviderModelOption(updated),
181
+ models: mergeProviderModels(predefined, catalog.listCustomProviderModels(provider)),
182
+ };
183
+ } catch (error) {
184
+ if (isUniqueConstraintError(error)) {
185
+ throw new AppError(`A ${provider} model with this ID already exists.`, {
186
+ code: 'MODEL_ID_ALREADY_EXISTS',
187
+ statusCode: 409,
188
+ });
189
+ }
190
+ throw error;
191
+ }
215
192
  };
216
193
 
217
- const loadAndCacheModels = (
194
+ const deleteCustomModel = async (
218
195
  provider: LLMProvider,
219
- ): Promise<ProviderModelsResult> => {
220
- const request = resolveProvider(provider).models.getSupportedModels()
221
- .then(async (models) => {
222
- const entry = await setCacheEntry(provider, models);
223
- return {
224
- models,
225
- cache: toProviderModelsCacheInfo(entry, 'fresh'),
226
- };
227
- })
228
- .finally(() => {
229
- pendingRequests.delete(provider);
196
+ recordId: number,
197
+ ): Promise<{ model: ProviderModelOption; models: ProviderModelsDefinition }> => {
198
+ const predefined = await resolveProvider(provider).models.getSupportedModels();
199
+ readCustomModel(provider, recordId);
200
+ const removed = catalog.deleteCustomProviderModel(provider, recordId, predefined.DEFAULT);
201
+ if (!removed) {
202
+ throw new AppError('Model not found.', {
203
+ code: 'MODEL_NOT_FOUND',
204
+ statusCode: 404,
230
205
  });
206
+ }
231
207
 
232
- pendingRequests.set(provider, request);
233
- return request;
208
+ return {
209
+ model: toCustomProviderModelOption(removed),
210
+ models: mergeProviderModels(predefined, catalog.listCustomProviderModels(provider)),
211
+ };
234
212
  };
235
213
 
236
- const loadDirectModels = (
237
- provider: LLMProvider,
238
- ): Promise<ProviderModelsResult> => {
239
- const request = resolveProvider(provider).models.getSupportedModels()
240
- .then((models) => {
241
- const currentTime = now();
242
- return {
243
- models,
244
- cache: {
245
- updatedAt: new Date(currentTime).toISOString(),
246
- expiresAt: new Date(currentTime).toISOString(),
247
- source: 'fresh' as const,
248
- },
249
- };
250
- })
251
- .finally(() => {
252
- pendingRequests.delete(provider);
253
- });
214
+ const readRecordedSessionSelection = (
215
+ sessionId: string,
216
+ ): { model: string | null; effort: string | null } | null => {
217
+ const session = sessions.getSessionById(sessionId);
218
+ if (!session) {
219
+ return null;
220
+ }
254
221
 
255
- pendingRequests.set(provider, request);
256
- return request;
222
+ return {
223
+ model: session.model?.trim() || null,
224
+ effort: session.effort?.trim() || null,
225
+ };
257
226
  };
258
227
 
259
- const getProviderModels = async (
228
+ /**
229
+ * Records the model one session runs with.
230
+ *
231
+ * Called from the active-model route when the user picks a model and from
232
+ * `chat.send` on every turn, so the row always matches what the session last
233
+ * ran with. Sessions the app has not created yet (no row) are ignored rather
234
+ * than treated as an error: the client keeps its own pending selection and
235
+ * the value lands on the row with the first send.
236
+ */
237
+ const setSessionModel = (
260
238
  provider: LLMProvider,
261
- options: ProviderModelsOptions = {},
262
- ): Promise<ProviderModelsResult> => {
263
- if (UNCACHED_PROVIDERS.has(provider)) {
264
- const pendingRequest = pendingRequests.get(provider);
265
- if (pendingRequest) {
266
- return pendingRequest;
267
- }
239
+ sessionId: string,
240
+ model: string,
241
+ ): ProviderSessionModel | null => {
242
+ const normalizedSessionId = sessionId.trim();
243
+ const normalizedModel = model.trim();
244
+ if (!normalizedSessionId || !normalizedModel) {
245
+ return null;
246
+ }
268
247
 
269
- return loadDirectModels(provider);
248
+ const recordedSelection = readRecordedSessionSelection(normalizedSessionId);
249
+ if (!recordedSelection) {
250
+ return null;
270
251
  }
271
252
 
272
- if (options.bypassCache) {
273
- const pendingRequest = pendingRequests.get(provider);
274
- if (pendingRequest) {
275
- return pendingRequest;
276
- }
253
+ sessions.setSessionModel(normalizedSessionId, normalizedModel);
254
+ return {
255
+ provider,
256
+ sessionId: normalizedSessionId,
257
+ model: normalizedModel,
258
+ effort: recordedSelection.effort,
259
+ source: 'session',
260
+ };
261
+ };
277
262
 
278
- return loadAndCacheModels(provider);
263
+ /**
264
+ * Records the reasoning effort one session runs with.
265
+ *
266
+ * Like `setSessionModel`, this ignores an id that has not been allocated by
267
+ * the session gateway yet. The websocket send path records it once the row
268
+ * exists, so a pre-session composer choice is not lost.
269
+ */
270
+ const setSessionEffort = (
271
+ provider: LLMProvider,
272
+ sessionId: string,
273
+ effort: string,
274
+ ): { provider: LLMProvider; sessionId: string; effort: string; source: 'session' } | null => {
275
+ const normalizedSessionId = sessionId.trim();
276
+ const normalizedEffort = effort.trim();
277
+ if (!normalizedSessionId || !normalizedEffort) {
278
+ return null;
279
279
  }
280
280
 
281
- const cachedModels = pruneExpiredMemoryEntry(provider, now(), 'memory');
282
- if (cachedModels) {
283
- return cachedModels;
281
+ if (!readRecordedSessionSelection(normalizedSessionId)) {
282
+ return null;
284
283
  }
285
284
 
286
- const pendingRequest = pendingRequests.get(provider);
287
- if (pendingRequest) {
288
- return pendingRequest;
289
- }
285
+ sessions.setSessionEffort(normalizedSessionId, normalizedEffort);
286
+ return {
287
+ provider,
288
+ sessionId: normalizedSessionId,
289
+ effort: normalizedEffort,
290
+ source: 'session',
291
+ };
292
+ };
290
293
 
291
- await loadPersistedCache();
294
+ /**
295
+ * Answers "which model is this session using?" for every display surface.
296
+ *
297
+ * Precedence, highest first:
298
+ * 1. the model recorded on the session row;
299
+ * 2. the provider's own session state for externally-created sessions;
300
+ * 3. `requestedModel`, the client's current default;
301
+ * 4. the source-controlled provider catalog default.
302
+ */
303
+ const resolveSessionModel = async (
304
+ provider: LLMProvider,
305
+ options: { sessionId?: string | null; requestedModel?: string | null } = {},
306
+ ): Promise<ProviderSessionModel> => {
307
+ const normalizedSessionId = typeof options.sessionId === 'string' ? options.sessionId.trim() : '';
308
+ const normalizedRequestedModel = typeof options.requestedModel === 'string'
309
+ ? options.requestedModel.trim()
310
+ : '';
311
+
312
+ if (normalizedSessionId) {
313
+ const recordedSelection = readRecordedSessionSelection(normalizedSessionId);
314
+ if (recordedSelection?.model) {
315
+ return {
316
+ provider,
317
+ sessionId: normalizedSessionId,
318
+ model: recordedSelection.model,
319
+ effort: recordedSelection.effort,
320
+ source: 'session',
321
+ };
322
+ }
292
323
 
293
- const persistedModels = pruneExpiredMemoryEntry(provider, now(), 'disk');
294
- if (persistedModels) {
295
- return persistedModels;
324
+ const providerCatalog = await getProviderModels(provider);
325
+ const providerModel = await getCurrentActiveModel(provider, normalizedSessionId);
326
+ const resolvedProviderModel = providerModel.model?.trim();
327
+ if (resolvedProviderModel && resolvedProviderModel !== providerCatalog.DEFAULT) {
328
+ return {
329
+ provider,
330
+ sessionId: normalizedSessionId,
331
+ model: resolvedProviderModel,
332
+ effort: recordedSelection?.effort ?? null,
333
+ source: 'provider',
334
+ };
335
+ }
336
+
337
+ return {
338
+ provider,
339
+ sessionId: normalizedSessionId,
340
+ model: normalizedRequestedModel || providerCatalog.DEFAULT,
341
+ effort: recordedSelection?.effort ?? null,
342
+ source: normalizedRequestedModel ? 'session' : 'default',
343
+ };
296
344
  }
297
345
 
298
- const postLoadPendingRequest = pendingRequests.get(provider);
299
- if (postLoadPendingRequest) {
300
- return postLoadPendingRequest;
346
+ if (normalizedRequestedModel) {
347
+ return {
348
+ provider,
349
+ sessionId: null,
350
+ model: normalizedRequestedModel,
351
+ effort: null,
352
+ source: 'session',
353
+ };
301
354
  }
302
355
 
303
- return loadAndCacheModels(provider);
356
+ const providerCatalog = await getProviderModels(provider);
357
+ return {
358
+ provider,
359
+ sessionId: null,
360
+ model: providerCatalog.DEFAULT,
361
+ effort: null,
362
+ source: 'default',
363
+ };
304
364
  };
305
365
 
306
- const getCurrentActiveModel = async (
307
- provider: LLMProvider,
308
- sessionId?: string,
309
- ): Promise<ProviderCurrentActiveModel> => resolveProvider(provider).models.getCurrentActiveModel(sessionId);
310
-
311
- const changeActiveModel = async (
312
- provider: LLMProvider,
313
- input: ProviderChangeActiveModelInput,
314
- ): Promise<ProviderSessionActiveModelChange> => resolveProvider(provider).models.changeActiveModel(input);
315
-
316
- const getChangedActiveModel = async (
317
- provider: LLMProvider,
318
- sessionId: string,
319
- ): Promise<ProviderSessionActiveModelChange> => readProviderSessionActiveModelChange(provider, sessionId, {
320
- filePath: activeModelChangesPath,
321
- });
322
-
366
+ /**
367
+ * Picks the model one resumed provider run should use.
368
+ *
369
+ * Provider-global state is deliberately ignored because it must never
370
+ * override the model explicitly selected in the composer.
371
+ */
323
372
  const resolveResumeModel = async (
324
373
  provider: LLMProvider,
325
374
  sessionId: string | undefined,
326
375
  requestedModel?: string | null,
327
376
  ): Promise<string | undefined> => {
377
+ void provider;
328
378
  const normalizedRequestedModel = typeof requestedModel === 'string' ? requestedModel.trim() : '';
329
- if (!sessionId?.trim()) {
379
+ const normalizedSessionId = sessionId?.trim();
380
+ if (!normalizedSessionId) {
330
381
  return normalizedRequestedModel || undefined;
331
382
  }
332
383
 
333
- const changedModel = await getChangedActiveModel(provider, sessionId);
334
- if (changedModel.supported && changedModel.changed && changedModel.model?.trim()) {
335
- return changedModel.model.trim();
336
- }
337
-
338
- return normalizedRequestedModel || undefined;
339
- };
340
-
341
- const clearCache = (): void => {
342
- memoryCache.clear();
343
- pendingRequests.clear();
344
- persistedCacheLoaded = false;
345
- persistedCacheLoadPromise = null;
384
+ const recordedModel = readRecordedSessionSelection(normalizedSessionId)?.model;
385
+ return recordedModel || normalizedRequestedModel || undefined;
346
386
  };
347
387
 
348
388
  return {
349
389
  getProviderModels,
350
- getCurrentActiveModel,
351
- getChangedActiveModel,
352
- changeActiveModel,
390
+ createCustomModel,
391
+ updateCustomModel,
392
+ deleteCustomModel,
393
+ setSessionModel,
394
+ setSessionEffort,
395
+ resolveSessionModel,
353
396
  resolveResumeModel,
354
- clearCache,
355
397
  };
356
398
  };
357
399
 
400
+ /** Shared Providers service used by routes, Commands, and provider runtimes. */
358
401
  export const providerModelsService = createProviderModelsService();