@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
@@ -109,6 +109,11 @@ CREATE TABLE IF NOT EXISTS sessions (
109
109
  custom_name TEXT,
110
110
  project_path TEXT,
111
111
  jsonl_path TEXT,
112
+ -- Model and reasoning effort this session runs with. Written when the user
113
+ -- changes either selection and on every send, so reopening a session
114
+ -- restores its exact runtime configuration instead of provider defaults.
115
+ model TEXT,
116
+ effort TEXT,
112
117
  isArchived BOOLEAN DEFAULT 0,
113
118
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
114
119
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -134,6 +139,27 @@ CREATE TABLE IF NOT EXISTS app_config (
134
139
  );
135
140
  `;
136
141
 
142
+ /**
143
+ * Persistent custom-model library used by the Providers module.
144
+ *
145
+ * Only user-created models are stored here. Predefined models remain source-
146
+ * controlled in each provider's `-models.provider.ts` adapter so they can be
147
+ * updated without migrating application data. `model_id` is unique only within
148
+ * a provider because different CLIs can accept the same identifier.
149
+ */
150
+ export const PROVIDER_MODELS_TABLE_SCHEMA_SQL = `
151
+ CREATE TABLE IF NOT EXISTS provider_models (
152
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
153
+ provider TEXT NOT NULL CHECK (provider IN ('claude', 'cursor', 'codex', 'opencode')),
154
+ model_id TEXT NOT NULL,
155
+ model_name TEXT NOT NULL,
156
+ sort_order INTEGER NOT NULL DEFAULT 0,
157
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
158
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
159
+ UNIQUE(provider, model_id)
160
+ );
161
+ `;
162
+
137
163
  export const INIT_SCHEMA_SQL = `
138
164
  -- Initialize authentication database
139
165
  PRAGMA foreign_keys = ON;
@@ -177,4 +203,8 @@ CREATE INDEX IF NOT EXISTS idx_session_ids_lookup ON sessions(session_id);
177
203
  ${LAST_SCANNED_AT_SQL}
178
204
 
179
205
  ${APP_CONFIG_TABLE_SCHEMA_SQL}
206
+
207
+ ${PROVIDER_MODELS_TABLE_SCHEMA_SQL}
208
+ CREATE INDEX IF NOT EXISTS idx_provider_models_provider_order
209
+ ON provider_models(provider, sort_order, id);
180
210
  `;
@@ -0,0 +1,125 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import test from 'node:test';
6
+
7
+ import {
8
+ closeConnection,
9
+ getConnection,
10
+ initializeDatabase,
11
+ providerModelsDb,
12
+ sessionsDb,
13
+ } from '@/modules/database/index.js';
14
+ import { runMigrations } from '@/modules/database/migrations.js';
15
+
16
+ test('provider model repository stores custom rows only and maintains session references', async () => {
17
+ const previousDatabasePath = process.env.DATABASE_PATH;
18
+ const tempDirectory = await mkdtemp(path.join(os.tmpdir(), 'provider-model-db-'));
19
+ const databasePath = path.join(tempDirectory, 'auth.db');
20
+
21
+ closeConnection();
22
+ process.env.DATABASE_PATH = databasePath;
23
+ await writeFile(databasePath, '');
24
+ await initializeDatabase();
25
+
26
+ try {
27
+ const columns = getConnection().prepare('PRAGMA table_info(provider_models)').all() as Array<{
28
+ name: string;
29
+ }>;
30
+ assert.deepEqual(columns.map((column) => column.name), [
31
+ 'id',
32
+ 'provider',
33
+ 'model_id',
34
+ 'model_name',
35
+ 'sort_order',
36
+ 'created_at',
37
+ 'updated_at',
38
+ ]);
39
+ assert.deepEqual(providerModelsDb.listCustomProviderModels('codex'), []);
40
+
41
+ const custom = providerModelsDb.createCustomProviderModel('codex', {
42
+ model: 'Private Gateway Model',
43
+ id: 'gateway/model-v1',
44
+ });
45
+ assert.equal(custom.modelId, 'gateway/model-v1');
46
+ assert.equal(
47
+ providerModelsDb.findCustomProviderModelByModelId('codex', 'gateway/model-v1')?.recordId,
48
+ custom.recordId,
49
+ );
50
+
51
+ const db = getConnection();
52
+ db.prepare(`
53
+ INSERT INTO projects (project_id, project_path)
54
+ VALUES ('project-1', '/tmp/project-1')
55
+ `).run();
56
+ db.prepare(`
57
+ INSERT INTO sessions (session_id, provider, project_path, model, effort)
58
+ VALUES ('session-1', 'codex', '/tmp/project-1', 'gateway/model-v1', 'high')
59
+ `).run();
60
+
61
+ const updated = providerModelsDb.updateCustomProviderModel('codex', custom.recordId, {
62
+ model: 'Private Gateway Model 2',
63
+ id: 'gateway/model-v2',
64
+ });
65
+ assert.equal(updated?.modelId, 'gateway/model-v2');
66
+ assert.equal(sessionsDb.getSessionById('session-1')?.model, 'gateway/model-v2');
67
+ // A rename keeps the same underlying model, so its effort stays applicable.
68
+ assert.equal(sessionsDb.getSessionById('session-1')?.effort, 'high');
69
+
70
+ const removed = providerModelsDb.deleteCustomProviderModel(
71
+ 'codex',
72
+ custom.recordId,
73
+ 'gpt-default',
74
+ );
75
+ assert.equal(removed?.modelId, 'gateway/model-v2');
76
+ assert.equal(sessionsDb.getSessionById('session-1')?.model, 'gpt-default');
77
+ // The effort belonged to the deleted model and must not survive onto the
78
+ // fallback, which has its own default.
79
+ assert.equal(sessionsDb.getSessionById('session-1')?.effort, null);
80
+ assert.equal(providerModelsDb.getCustomProviderModel('codex', custom.recordId), null);
81
+ } finally {
82
+ closeConnection();
83
+ if (previousDatabasePath === undefined) {
84
+ delete process.env.DATABASE_PATH;
85
+ } else {
86
+ process.env.DATABASE_PATH = previousDatabasePath;
87
+ }
88
+ await rm(tempDirectory, { recursive: true, force: true });
89
+ }
90
+ });
91
+
92
+ test('migrations create the provider model index on an install that lacks it', async () => {
93
+ const previousDatabasePath = process.env.DATABASE_PATH;
94
+ const tempDirectory = await mkdtemp(path.join(os.tmpdir(), 'provider-model-index-'));
95
+ const databasePath = path.join(tempDirectory, 'auth.db');
96
+
97
+ closeConnection();
98
+ process.env.DATABASE_PATH = databasePath;
99
+ await writeFile(databasePath, '');
100
+ await initializeDatabase();
101
+
102
+ try {
103
+ const db = getConnection();
104
+ // Upgraded installs reach runMigrations with provider_models present but no
105
+ // index, so the CREATE INDEX statement is compiled against the real table
106
+ // instead of short-circuiting on the existing index name.
107
+ db.exec('DROP INDEX IF EXISTS idx_provider_models_provider_order');
108
+
109
+ runMigrations(db);
110
+
111
+ const indexedColumns = (db
112
+ .prepare('PRAGMA index_info(idx_provider_models_provider_order)')
113
+ .all() as Array<{ name: string }>)
114
+ .map((column) => column.name);
115
+ assert.deepEqual(indexedColumns, ['provider', 'sort_order', 'id']);
116
+ } finally {
117
+ closeConnection();
118
+ if (previousDatabasePath === undefined) {
119
+ delete process.env.DATABASE_PATH;
120
+ } else {
121
+ process.env.DATABASE_PATH = previousDatabasePath;
122
+ }
123
+ await rm(tempDirectory, { recursive: true, force: true });
124
+ }
125
+ });
@@ -45,7 +45,7 @@ test('disk-discovered sessions are keyed by the provider id for both columns', a
45
45
 
46
46
  test('app sessions get the provider id assigned without creating a duplicate row', async () => {
47
47
  await withIsolatedDatabase(() => {
48
- sessionsDb.createAppSession('app-id-1', 'claude', '/workspace/demo');
48
+ sessionsDb.createAppSession('app-id-1', 'claude', '/workspace/demo', 'Initial CloudCLI message');
49
49
  sessionsDb.assignProviderSessionId('app-id-1', 'provider-xyz');
50
50
 
51
51
  // A later synchronizer pass that discovers the transcript on disk must
@@ -66,6 +66,7 @@ test('app sessions get the provider id assigned without creating a duplicate row
66
66
  const row = sessionsDb.getSessionById('app-id-1');
67
67
  assert.equal(row?.provider_session_id, 'provider-xyz');
68
68
  assert.equal(row?.jsonl_path, '/fake/path/provider-xyz.jsonl');
69
+ assert.equal(row?.custom_name, 'Initial CloudCLI message');
69
70
  });
70
71
  });
71
72
 
@@ -6,6 +6,7 @@ import test from 'node:test';
6
6
 
7
7
  import { closeConnection } from '@/modules/database/connection.js';
8
8
  import { initializeDatabase } from '@/modules/database/init-db.js';
9
+ import { projectsDb } from '@/modules/database/repositories/projects.db.js';
9
10
  import { sessionsDb } from '@/modules/database/repositories/sessions.db.js';
10
11
 
11
12
  async function withIsolatedDatabase(runTest: () => void | Promise<void>): Promise<void> {
@@ -82,3 +83,34 @@ test('repository reads normalize SQLite UTC timestamps to ISO strings', async ()
82
83
  assert.match(row?.updated_at ?? '', /^\d{4}-\d{2}-\d{2}T/);
83
84
  });
84
85
  });
86
+
87
+ test('recent sessions are globally ordered, paginated, and limited to visible conversations', async () => {
88
+ await withIsolatedDatabase(() => {
89
+ const fixtures: Array<Parameters<typeof sessionsDb.createSession>> = [
90
+ ['session-oldest', 'claude', '/workspace/project-a', 'Oldest', '2026-07-18T09:00:00.000Z', '2026-07-18T10:00:00.000Z'],
91
+ ['session-newest', 'codex', '/workspace/project-b', 'Newest', '2026-07-18T11:00:00.000Z', '2026-07-18T12:00:00.900Z'],
92
+ ['session-same-second', 'claude', '/workspace/project-a', 'Same second, slightly older', '2026-07-18T12:00:00.000Z', '2026-07-18T12:00:00.100Z'],
93
+ ['session-middle', 'claude', '/workspace/project-a', 'Middle', '2026-07-18T10:00:00.000Z', '2026-07-18T11:00:00.000Z'],
94
+ ['session-archived', 'claude', '/workspace/project-a', 'Archived session', '2026-07-18T13:00:00.000Z', '2026-07-18T13:00:00.000Z'],
95
+ ['session-hidden-project', 'claude', '/workspace/project-hidden', 'Archived project session', '2026-07-18T14:00:00.000Z', '2026-07-18T14:00:00.000Z'],
96
+ ];
97
+ fixtures.forEach((fixture) => sessionsDb.createSession(...fixture));
98
+
99
+ sessionsDb.updateSessionIsArchived('session-archived', true);
100
+ projectsDb.updateProjectIsArchived('/workspace/project-hidden', true);
101
+
102
+ const firstPage = sessionsDb.getRecentSessionsPage(2, 0);
103
+ const secondPage = sessionsDb.getRecentSessionsPage(2, 2);
104
+
105
+ assert.equal(firstPage.total, 4);
106
+ assert.deepEqual(
107
+ firstPage.sessions.map((session) => session.session_id),
108
+ ['session-newest', 'session-same-second'],
109
+ );
110
+ assert.equal(secondPage.total, 4);
111
+ assert.deepEqual(
112
+ secondPage.sessions.map((session) => session.session_id),
113
+ ['session-middle', 'session-oldest'],
114
+ );
115
+ });
116
+ });
@@ -0,0 +1,116 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import fs, { promises as fsPromises } from 'node:fs';
3
+ import os from 'node:os';
4
+
5
+ import mime from 'mime-types';
6
+ import multer from 'multer';
7
+
8
+ import { projectsDb } from '@/modules/database/index.js';
9
+ import { createFileTreeRouter } from '@/modules/file-tree/file-tree.routes.js';
10
+ import { createFileTreeService } from '@/modules/file-tree/file-tree.service.js';
11
+ import type {
12
+ FileTreeFileSystem,
13
+ FileTreeLogger,
14
+ FileTreeProjectGateway,
15
+ FileTreeWorkspaceGateway,
16
+ } from '@/shared/types.js';
17
+ import { WORKSPACES_ROOT, validateWorkspacePath } from '@/shared/utils.js';
18
+
19
+ const MAXIMUM_UPLOAD_SIZE_MEGABYTES = 200;
20
+ const MAXIMUM_UPLOAD_SIZE_BYTES = MAXIMUM_UPLOAD_SIZE_MEGABYTES * 1024 * 1024;
21
+ const MAXIMUM_UPLOAD_FILE_COUNT = 20;
22
+
23
+ function readFileSystemConcurrency(): number {
24
+ const configuredConcurrency = Number.parseInt(process.env.FS_CONCURRENCY ?? '', 10);
25
+ return Number.isFinite(configuredConcurrency) && configuredConcurrency > 0
26
+ ? configuredConcurrency
27
+ : 64;
28
+ }
29
+
30
+ /**
31
+ * Production filesystem adapter owned by the File Tree composition root.
32
+ * Application services receive this complete capability explicitly and never
33
+ * import Node's mutable filesystem APIs themselves.
34
+ */
35
+ const fileTreeFileSystem: FileTreeFileSystem = {
36
+ access: (candidatePath) => fsPromises.access(candidatePath),
37
+ stat: (candidatePath) => fsPromises.stat(candidatePath),
38
+ lstat: (candidatePath) => fsPromises.lstat(candidatePath),
39
+ // `opendir` streams entries in batches and the handle is closed by the
40
+ // iterator protocol, including when the caller stops early at the entry cap.
41
+ openDirectory: async function* (directoryPath) {
42
+ yield* await fsPromises.opendir(directoryPath);
43
+ },
44
+ realpath: (candidatePath) => fsPromises.realpath(candidatePath),
45
+ readTextFile: (filePath) => fsPromises.readFile(filePath, 'utf8'),
46
+ writeTextFile: (filePath, content) => fsPromises.writeFile(filePath, content, 'utf8'),
47
+ async makeDirectory(directoryPath, recursive) {
48
+ await fsPromises.mkdir(directoryPath, { recursive });
49
+ },
50
+ rename: (oldPath, newPath) => fsPromises.rename(oldPath, newPath),
51
+ async removeDirectory(directoryPath) {
52
+ await fsPromises.rm(directoryPath, { recursive: true, force: true });
53
+ },
54
+ unlink: (filePath) => fsPromises.unlink(filePath),
55
+ copyFile: (sourcePath, destinationPath) => fsPromises.copyFile(sourcePath, destinationPath),
56
+ createReadStream: (filePath) => fs.createReadStream(filePath),
57
+ };
58
+
59
+ /**
60
+ * Database boundary used only by File Tree production composition.
61
+ * The Database module is consumed through its barrel; services and routes see
62
+ * only the narrow project-path lookup contract.
63
+ */
64
+ const fileTreeProjects: FileTreeProjectGateway = {
65
+ getProjectPathById: (projectId) => projectsDb.getProjectPathById(projectId),
66
+ };
67
+
68
+ /**
69
+ * Workspace-policy boundary used only by File Tree production composition.
70
+ * Keeping both the configured root and symlink-aware validator together makes
71
+ * the path policy explicit for every service instance.
72
+ */
73
+ const fileTreeWorkspace: FileTreeWorkspaceGateway = {
74
+ rootPath: WORKSPACES_ROOT,
75
+ validatePath: (candidatePath) => validateWorkspacePath(candidatePath),
76
+ };
77
+
78
+ const fileTreeLogger: FileTreeLogger = {
79
+ error: (message, error) => console.error(message, error),
80
+ };
81
+
82
+ const fileTreeServices = createFileTreeService({
83
+ fileSystem: fileTreeFileSystem,
84
+ projects: fileTreeProjects,
85
+ workspace: fileTreeWorkspace,
86
+ resolveMimeType: (filePath) => mime.lookup(filePath) || 'application/octet-stream',
87
+ fileSystemConcurrency: readFileSystemConcurrency(),
88
+ logger: fileTreeLogger,
89
+ });
90
+
91
+ const fileUploadMiddleware = multer({
92
+ storage: multer.diskStorage({
93
+ destination: os.tmpdir(),
94
+ filename: (_request, _file, callback) => {
95
+ callback(null, `cloudcli-file-upload-${randomUUID()}`);
96
+ },
97
+ }),
98
+ limits: {
99
+ fileSize: MAXIMUM_UPLOAD_SIZE_BYTES,
100
+ files: MAXIMUM_UPLOAD_FILE_COUNT,
101
+ },
102
+ }).array('files', MAXIMUM_UPLOAD_FILE_COUNT);
103
+
104
+ /**
105
+ * File Tree router used by the server entrypoint to mount the authenticated
106
+ * browsing, editing, file-management, and upload API under `/api/file-tree`.
107
+ */
108
+ export const fileTreeRoutes = createFileTreeRouter(
109
+ fileTreeServices,
110
+ fileUploadMiddleware,
111
+ {
112
+ maximumFileSizeMegabytes: MAXIMUM_UPLOAD_SIZE_MEGABYTES,
113
+ maximumFileCount: MAXIMUM_UPLOAD_FILE_COUNT,
114
+ },
115
+ fileTreeLogger,
116
+ );
@@ -0,0 +1,258 @@
1
+ import express from 'express';
2
+ import type { NextFunction, Request, RequestHandler, Response } from 'express';
3
+
4
+ import type {
5
+ FileTreeLogger,
6
+ FileTreeServices,
7
+ FileTreeUploadedFile,
8
+ } from '@/shared/types.js';
9
+ import { AppError } from '@/shared/utils.js';
10
+
11
+ type FileTreeUploadLimits = {
12
+ maximumFileSizeMegabytes: number;
13
+ maximumFileCount: number;
14
+ };
15
+
16
+ type UploadedRequest = Request & {
17
+ files?: Express.Multer.File[];
18
+ };
19
+
20
+ function readBody(request: Request): Record<string, unknown> {
21
+ return typeof request.body === 'object' && request.body !== null
22
+ ? request.body as Record<string, unknown>
23
+ : {};
24
+ }
25
+
26
+ function readRequiredString(value: unknown, fieldName: string, message?: string): string {
27
+ if (typeof value !== 'string' || !value.trim()) {
28
+ throw new AppError(message ?? `${fieldName} is required`, {
29
+ code: 'INVALID_FILE_TREE_REQUEST',
30
+ statusCode: 400,
31
+ });
32
+ }
33
+ return value;
34
+ }
35
+
36
+ function readOptionalString(value: unknown): string | null {
37
+ return typeof value === 'string' ? value : null;
38
+ }
39
+
40
+ function readProjectId(request: Request): string {
41
+ return readRequiredString(request.params.projectId, 'projectId');
42
+ }
43
+
44
+ function readEntryType(value: unknown): 'file' | 'directory' {
45
+ if (value !== 'file' && value !== 'directory') {
46
+ throw new AppError('Type must be "file" or "directory"', {
47
+ code: 'INVALID_FILE_TREE_ENTRY_TYPE',
48
+ statusCode: 400,
49
+ });
50
+ }
51
+ return value;
52
+ }
53
+
54
+ function readRelativePaths(value: unknown): string[] {
55
+ if (typeof value !== 'string' || !value) {
56
+ return [];
57
+ }
58
+
59
+ try {
60
+ const parsed = JSON.parse(value) as unknown;
61
+ return Array.isArray(parsed)
62
+ ? parsed.filter((entry): entry is string => typeof entry === 'string')
63
+ : [];
64
+ } catch {
65
+ return [];
66
+ }
67
+ }
68
+
69
+ function readRequestedFileCount(value: unknown, fallbackCount: number): number {
70
+ const parsedCount = typeof value === 'string' ? Number.parseInt(value, 10) : Number.NaN;
71
+ return Number.isFinite(parsedCount) && parsedCount > 0 ? parsedCount : fallbackCount;
72
+ }
73
+
74
+ function normalizeUploadedFiles(request: UploadedRequest): FileTreeUploadedFile[] {
75
+ return Array.isArray(request.files)
76
+ ? request.files.map((file) => ({
77
+ originalName: file.originalname,
78
+ temporaryPath: file.path,
79
+ size: file.size,
80
+ mimeType: file.mimetype,
81
+ }))
82
+ : [];
83
+ }
84
+
85
+ function createRouteHandler(
86
+ operation: (request: Request, response: Response) => void | Promise<void>,
87
+ logger: FileTreeLogger,
88
+ ): RequestHandler {
89
+ return async (request, response) => {
90
+ try {
91
+ await operation(request, response);
92
+ } catch (error) {
93
+ if (error instanceof AppError) {
94
+ response.status(error.statusCode).json({ error: error.message });
95
+ return;
96
+ }
97
+
98
+ const message = error instanceof Error ? error.message : String(error);
99
+ logger.error('File Tree API error', error);
100
+ response.status(500).json({ error: message });
101
+ }
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Builds the File Tree HTTP router for the server composition root and route tests.
107
+ * Paths are relative to the module's `/api/file-tree` mount point so the
108
+ * complete HTTP surface has one feature-owned namespace.
109
+ */
110
+ export function createFileTreeRouter(
111
+ services: FileTreeServices,
112
+ uploadFilesMiddleware: RequestHandler,
113
+ uploadLimits: FileTreeUploadLimits,
114
+ logger: FileTreeLogger,
115
+ ): express.Router {
116
+ const router = express.Router();
117
+
118
+ router.get('/browse-filesystem', createRouteHandler(async (request, response) => {
119
+ response.json(await services.browseWorkspace(readOptionalString(request.query.path)));
120
+ }, logger));
121
+
122
+ router.post('/create-folder', createRouteHandler(async (request, response) => {
123
+ const body = readBody(request);
124
+ const folderPath = readRequiredString(body.path, 'path', 'Path is required');
125
+ response.json(await services.createWorkspaceFolder(folderPath));
126
+ }, logger));
127
+
128
+ router.get('/projects/:projectId/file', createRouteHandler(async (request, response) => {
129
+ const filePath = readRequiredString(request.query.filePath, 'filePath', 'Invalid file path');
130
+ response.json(await services.readTextFile(readProjectId(request), filePath));
131
+ }, logger));
132
+
133
+ router.get('/projects/:projectId/files/content', createRouteHandler(async (request, response) => {
134
+ const filePath = readRequiredString(request.query.path, 'path', 'Invalid file path');
135
+ const file = await services.openFile(readProjectId(request), filePath);
136
+ response.setHeader('Content-Type', file.contentType);
137
+ file.stream.pipe(response);
138
+ file.stream.on('error', (error) => {
139
+ logger.error('Error streaming File Tree content', error);
140
+ if (!response.headersSent) {
141
+ response.status(500).json({ error: 'Error reading file' });
142
+ }
143
+ });
144
+ }, logger));
145
+
146
+ router.put('/projects/:projectId/file', createRouteHandler(async (request, response) => {
147
+ const body = readBody(request);
148
+ const filePath = readRequiredString(body.filePath, 'filePath', 'Invalid file path');
149
+ if (body.content === undefined) {
150
+ throw new AppError('Content is required', {
151
+ code: 'FILE_CONTENT_REQUIRED',
152
+ statusCode: 400,
153
+ });
154
+ }
155
+ if (typeof body.content !== 'string') {
156
+ throw new AppError('Content must be a string', {
157
+ code: 'INVALID_FILE_CONTENT',
158
+ statusCode: 400,
159
+ });
160
+ }
161
+ response.json(await services.saveTextFile(readProjectId(request), filePath, body.content));
162
+ }, logger));
163
+
164
+ router.get('/projects/:projectId/files', createRouteHandler(async (request, response) => {
165
+ response.json(await services.listProjectFiles(readProjectId(request), {
166
+ respectGitignore: request.query.respectGitignore === 'true',
167
+ }));
168
+ }, logger));
169
+
170
+ router.post('/projects/:projectId/files/create', createRouteHandler(async (request, response) => {
171
+ const body = readBody(request);
172
+ if (!body.name || !body.type) {
173
+ throw new AppError('Name and type are required', {
174
+ code: 'FILE_TREE_ENTRY_FIELDS_REQUIRED',
175
+ statusCode: 400,
176
+ });
177
+ }
178
+ const name = readRequiredString(body.name, 'name');
179
+ const type = readEntryType(body.type);
180
+ const parentPath = readOptionalString(body.path) ?? '';
181
+ response.json(await services.createEntry({
182
+ projectId: readProjectId(request),
183
+ parentPath,
184
+ type,
185
+ name,
186
+ }));
187
+ }, logger));
188
+
189
+ router.put('/projects/:projectId/files/rename', createRouteHandler(async (request, response) => {
190
+ const body = readBody(request);
191
+ if (!body.oldPath || !body.newName) {
192
+ throw new AppError('oldPath and newName are required', {
193
+ code: 'FILE_TREE_RENAME_FIELDS_REQUIRED',
194
+ statusCode: 400,
195
+ });
196
+ }
197
+ response.json(await services.renameEntry({
198
+ projectId: readProjectId(request),
199
+ oldPath: readRequiredString(body.oldPath, 'oldPath'),
200
+ newName: readRequiredString(body.newName, 'newName'),
201
+ }));
202
+ }, logger));
203
+
204
+ router.delete('/projects/:projectId/files', createRouteHandler(async (request, response) => {
205
+ const body = readBody(request);
206
+ const targetPath = readRequiredString(body.path, 'path', 'Path is required');
207
+ response.json(await services.deleteEntry({
208
+ projectId: readProjectId(request),
209
+ targetPath,
210
+ }));
211
+ }, logger));
212
+
213
+ const uploadHandler = createRouteHandler(async (request, response) => {
214
+ const uploadedRequest = request as UploadedRequest;
215
+ const body = readBody(request);
216
+ const files = normalizeUploadedFiles(uploadedRequest);
217
+ response.json(await services.storeUploadedFiles({
218
+ projectId: readProjectId(request),
219
+ targetPath: readOptionalString(body.targetPath) ?? '',
220
+ relativePaths: readRelativePaths(body.relativePaths),
221
+ requestedFileCount: readRequestedFileCount(body.requestedFileCount, files.length),
222
+ files,
223
+ }));
224
+ }, logger);
225
+
226
+ router.post(
227
+ '/projects/:projectId/files/upload',
228
+ (request: Request, response: Response, next: NextFunction) => {
229
+ uploadFilesMiddleware(request, response, (error?: unknown) => {
230
+ if (!error) {
231
+ void uploadHandler(request, response, next);
232
+ return;
233
+ }
234
+
235
+ const errorCode = typeof error === 'object' && error !== null && 'code' in error
236
+ ? String(error.code)
237
+ : null;
238
+ if (errorCode === 'LIMIT_FILE_SIZE') {
239
+ response.status(400).json({
240
+ error: `File too large. Maximum size is ${uploadLimits.maximumFileSizeMegabytes}MB.`,
241
+ });
242
+ return;
243
+ }
244
+ if (errorCode === 'LIMIT_FILE_COUNT') {
245
+ response.status(400).json({
246
+ error: `Too many files. Maximum is ${uploadLimits.maximumFileCount} files.`,
247
+ });
248
+ return;
249
+ }
250
+
251
+ const message = error instanceof Error ? error.message : String(error);
252
+ response.status(500).json({ error: message });
253
+ });
254
+ },
255
+ );
256
+
257
+ return router;
258
+ }