@cloudcli-ai/cloudcli 1.36.3 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (535) hide show
  1. package/dist/assets/index-DSlds633.css +32 -0
  2. package/dist/assets/{index-CcCsKitq.js → index-eGqPeIEu.js} +375 -267
  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 +96 -0
  64. package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -0
  65. package/dist-server/server/modules/database/index.js +1 -0
  66. package/dist-server/server/modules/database/index.js.map +1 -1
  67. package/dist-server/server/modules/database/migrations.js +13 -0
  68. package/dist-server/server/modules/database/migrations.js.map +1 -1
  69. package/dist-server/server/modules/database/repositories/sessions.db.js +14 -1
  70. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  71. package/dist-server/server/modules/database/schema.js +4 -0
  72. package/dist-server/server/modules/database/schema.js.map +1 -1
  73. package/dist-server/server/modules/file-tree/file-tree.module.js +91 -0
  74. package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -0
  75. package/dist-server/server/modules/file-tree/file-tree.routes.js +208 -0
  76. package/dist-server/server/modules/file-tree/file-tree.routes.js.map +1 -0
  77. package/dist-server/server/modules/file-tree/file-tree.service.js +544 -0
  78. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -0
  79. package/dist-server/server/modules/file-tree/index.js +3 -0
  80. package/dist-server/server/modules/file-tree/index.js.map +1 -0
  81. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js +123 -0
  82. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js.map +1 -0
  83. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +184 -0
  84. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -0
  85. package/dist-server/server/modules/git/git-parsing.service.js +61 -0
  86. package/dist-server/server/modules/git/git-parsing.service.js.map +1 -0
  87. package/dist-server/server/modules/git/git.module.js +14 -0
  88. package/dist-server/server/modules/git/git.module.js.map +1 -0
  89. package/dist-server/server/modules/git/git.routes.js +1339 -0
  90. package/dist-server/server/modules/git/git.routes.js.map +1 -0
  91. package/dist-server/server/modules/git/index.js +3 -0
  92. package/dist-server/server/modules/git/index.js.map +1 -0
  93. package/dist-server/server/modules/git/tests/git-init.routes.test.js +48 -0
  94. package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -0
  95. package/dist-server/server/{routes → modules/git/tests}/git.test.js +1 -1
  96. package/dist-server/server/modules/git/tests/git.test.js.map +1 -0
  97. package/dist-server/server/modules/notifications/index.js +15 -1
  98. package/dist-server/server/modules/notifications/index.js.map +1 -1
  99. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js +44 -0
  100. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js.map +1 -0
  101. package/dist-server/server/{services/vapid-keys.js → modules/notifications/vapid-keys.service.js} +3 -2
  102. package/dist-server/server/modules/notifications/vapid-keys.service.js.map +1 -0
  103. package/dist-server/server/modules/plugins/index.js +9 -0
  104. package/dist-server/server/modules/plugins/index.js.map +1 -0
  105. package/dist-server/server/{utils/plugin-process-manager.js → modules/plugins/plugin-process.service.js} +3 -2
  106. package/dist-server/server/modules/plugins/plugin-process.service.js.map +1 -0
  107. package/dist-server/server/{utils/plugin-loader.js → modules/plugins/plugin-registry.service.js} +2 -1
  108. package/dist-server/server/modules/plugins/plugin-registry.service.js.map +1 -0
  109. package/dist-server/server/modules/plugins/plugins.module.js +30 -0
  110. package/dist-server/server/modules/plugins/plugins.module.js.map +1 -0
  111. package/dist-server/server/modules/plugins/plugins.routes.js +70 -0
  112. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -0
  113. package/dist-server/server/modules/plugins/plugins.service.js +123 -0
  114. package/dist-server/server/modules/plugins/plugins.service.js.map +1 -0
  115. package/dist-server/server/modules/plugins/tests/plugins.service.test.js +28 -0
  116. package/dist-server/server/modules/plugins/tests/plugins.service.test.js.map +1 -0
  117. package/dist-server/server/modules/projects/index.js +5 -0
  118. package/dist-server/server/modules/projects/index.js.map +1 -1
  119. package/dist-server/server/modules/providers/index.js +3 -0
  120. package/dist-server/server/modules/providers/index.js.map +1 -1
  121. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +6 -0
  122. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  123. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +1 -4
  124. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  125. package/dist-server/server/{claude-sdk.js → modules/providers/list/claude/claude-runtime.provider.js} +62 -41
  126. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -0
  127. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +6 -4
  128. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  129. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +23 -4
  130. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  131. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  132. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  133. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +1 -4
  134. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
  135. package/dist-server/server/{openai-codex.js → modules/providers/list/codex/codex-runtime.provider.js} +48 -34
  136. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -0
  137. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +290 -6
  138. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  139. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +5 -0
  140. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -1
  141. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  142. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  143. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +1 -4
  144. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -1
  145. package/dist-server/server/{cursor-cli.js → modules/providers/list/cursor/cursor-runtime.provider.js} +40 -28
  146. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -0
  147. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +21 -14
  148. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  149. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
  150. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
  151. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +7 -5
  152. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
  153. package/dist-server/server/{opencode-cli.js → modules/providers/list/opencode/opencode-runtime.provider.js} +38 -25
  154. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -0
  155. package/dist-server/server/{opencode-cli.test.js → modules/providers/list/opencode/opencode-runtime.provider.test.js} +27 -4
  156. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js.map +1 -0
  157. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +11 -5
  158. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
  159. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +2 -0
  160. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -1
  161. package/dist-server/server/modules/providers/provider.routes.js +33 -9
  162. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  163. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +5 -1
  164. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
  165. package/dist-server/server/modules/providers/services/provider-models.service.js +110 -15
  166. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  167. package/dist-server/server/modules/providers/services/provider-runtime.service.js +66 -0
  168. package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -0
  169. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +268 -0
  170. package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -0
  171. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +2 -0
  172. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  173. package/dist-server/server/modules/providers/services/sessions.service.js +54 -0
  174. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  175. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +2 -3
  176. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
  177. package/dist-server/server/modules/providers/tests/claude-auth.test.js +122 -0
  178. package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -0
  179. package/dist-server/server/modules/providers/tests/claude-sessions.test.js +44 -0
  180. package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -0
  181. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +36 -0
  182. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
  183. package/dist-server/server/modules/providers/tests/{provider-image-history.test.js → provider-attachment-history.test.js} +60 -2
  184. package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js.map +1 -0
  185. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +148 -61
  186. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
  187. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js +130 -0
  188. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js.map +1 -0
  189. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +165 -0
  190. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -0
  191. package/dist-server/server/modules/providers/tests/sessions-details.test.js +62 -0
  192. package/dist-server/server/modules/providers/tests/sessions-details.test.js.map +1 -0
  193. package/dist-server/server/modules/providers/tests/skills.test.js +4 -2
  194. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  195. package/dist-server/server/modules/settings/index.js +3 -0
  196. package/dist-server/server/modules/settings/index.js.map +1 -0
  197. package/dist-server/server/modules/settings/settings.module.js +35 -0
  198. package/dist-server/server/modules/settings/settings.module.js.map +1 -0
  199. package/dist-server/server/modules/settings/settings.routes.js +34 -0
  200. package/dist-server/server/modules/settings/settings.routes.js.map +1 -0
  201. package/dist-server/server/modules/settings/settings.service.js +116 -0
  202. package/dist-server/server/modules/settings/settings.service.js.map +1 -0
  203. package/dist-server/server/modules/settings/tests/settings.service.test.js +48 -0
  204. package/dist-server/server/modules/settings/tests/settings.service.test.js.map +1 -0
  205. package/dist-server/server/modules/system/index.js +3 -0
  206. package/dist-server/server/modules/system/index.js.map +1 -0
  207. package/dist-server/server/modules/system/system.module.js +44 -0
  208. package/dist-server/server/modules/system/system.module.js.map +1 -0
  209. package/dist-server/server/modules/system/system.routes.js +16 -0
  210. package/dist-server/server/modules/system/system.routes.js.map +1 -0
  211. package/dist-server/server/modules/system/system.service.js +45 -0
  212. package/dist-server/server/modules/system/system.service.js.map +1 -0
  213. package/dist-server/server/modules/system/tests/system.service.test.js +100 -0
  214. package/dist-server/server/modules/system/tests/system.service.test.js.map +1 -0
  215. package/dist-server/server/modules/taskmaster/index.js +3 -0
  216. package/dist-server/server/modules/taskmaster/index.js.map +1 -0
  217. package/dist-server/server/modules/taskmaster/taskmaster.module.js +20 -0
  218. package/dist-server/server/modules/taskmaster/taskmaster.module.js.map +1 -0
  219. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +1372 -0
  220. package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -0
  221. package/dist-server/server/modules/taskmaster/taskmaster.service.js +107 -0
  222. package/dist-server/server/modules/taskmaster/taskmaster.service.js.map +1 -0
  223. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +132 -0
  224. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -0
  225. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js +85 -0
  226. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js.map +1 -0
  227. package/dist-server/server/modules/user/index.js +3 -0
  228. package/dist-server/server/modules/user/index.js.map +1 -0
  229. package/dist-server/server/modules/user/tests/user.service.test.js +53 -0
  230. package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -0
  231. package/dist-server/server/modules/user/user.module.js +47 -0
  232. package/dist-server/server/modules/user/user.module.js.map +1 -0
  233. package/dist-server/server/modules/user/user.routes.js +44 -0
  234. package/dist-server/server/modules/user/user.routes.js.map +1 -0
  235. package/dist-server/server/modules/user/user.service.js +59 -0
  236. package/dist-server/server/modules/user/user.service.js.map +1 -0
  237. package/dist-server/server/modules/voice/index.js +3 -0
  238. package/dist-server/server/modules/voice/index.js.map +1 -0
  239. package/dist-server/server/modules/voice/tests/voice.service.test.js +86 -0
  240. package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -0
  241. package/dist-server/server/modules/voice/voice.module.js +44 -0
  242. package/dist-server/server/modules/voice/voice.module.js.map +1 -0
  243. package/dist-server/server/modules/voice/voice.routes.js +87 -0
  244. package/dist-server/server/modules/voice/voice.routes.js.map +1 -0
  245. package/dist-server/server/modules/voice/voice.service.js +148 -0
  246. package/dist-server/server/modules/voice/voice.service.js.map +1 -0
  247. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +2 -2
  248. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +40 -29
  249. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  250. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +76 -8
  251. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  252. package/dist-server/server/modules/websocket/services/websocket-server.service.js +51 -20
  253. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -1
  254. package/dist-server/server/modules/websocket/tests/{chat-image-filter.test.js → chat-attachment-filter.test.js} +10 -3
  255. package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js.map +1 -0
  256. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +97 -0
  257. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -0
  258. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js +61 -0
  259. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js.map +1 -0
  260. package/dist-server/server/modules/worktrees/index.js +3 -0
  261. package/dist-server/server/modules/worktrees/index.js.map +1 -0
  262. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js +37 -0
  263. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js.map +1 -0
  264. package/dist-server/server/modules/worktrees/services/worktree-create.service.js +67 -0
  265. package/dist-server/server/modules/worktrees/services/worktree-create.service.js.map +1 -0
  266. package/dist-server/server/modules/worktrees/services/worktree-git.service.js +172 -0
  267. package/dist-server/server/modules/worktrees/services/worktree-git.service.js.map +1 -0
  268. package/dist-server/server/modules/worktrees/services/worktree-list.service.js +91 -0
  269. package/dist-server/server/modules/worktrees/services/worktree-list.service.js.map +1 -0
  270. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js +118 -0
  271. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js.map +1 -0
  272. package/dist-server/server/modules/worktrees/services/worktree-open.service.js +58 -0
  273. package/dist-server/server/modules/worktrees/services/worktree-open.service.js.map +1 -0
  274. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +65 -0
  275. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js.map +1 -0
  276. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js +58 -0
  277. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js.map +1 -0
  278. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js +85 -0
  279. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js.map +1 -0
  280. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js +58 -0
  281. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js.map +1 -0
  282. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js +34 -0
  283. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js.map +1 -0
  284. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js +137 -0
  285. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js.map +1 -0
  286. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js +99 -0
  287. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js.map +1 -0
  288. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js +157 -0
  289. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js.map +1 -0
  290. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js +167 -0
  291. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js.map +1 -0
  292. package/dist-server/server/modules/worktrees/worktrees.module.js +97 -0
  293. package/dist-server/server/modules/worktrees/worktrees.module.js.map +1 -0
  294. package/dist-server/server/modules/worktrees/worktrees.routes.js +84 -0
  295. package/dist-server/server/modules/worktrees/worktrees.routes.js.map +1 -0
  296. package/dist-server/server/shared/image-attachments.js +90 -17
  297. package/dist-server/server/shared/image-attachments.js.map +1 -1
  298. package/dist-server/server/shared/tests/image-attachments.test.js +43 -1
  299. package/dist-server/server/shared/tests/image-attachments.test.js.map +1 -1
  300. package/dist-server/server/shared/utils.js +66 -142
  301. package/dist-server/server/shared/utils.js.map +1 -1
  302. package/package.json +8 -4
  303. package/server/index.ts +401 -0
  304. package/server/{load-env.js → load-env.ts} +18 -5
  305. package/server/modules/agent/agent.module.ts +51 -0
  306. package/server/modules/agent/agent.routes.ts +1287 -0
  307. package/server/modules/agent/index.ts +2 -0
  308. package/server/modules/agent/tests/agent.routes.test.ts +205 -0
  309. package/server/modules/assets/assets.routes.ts +63 -16
  310. package/server/modules/assets/index.ts +2 -2
  311. package/server/modules/assets/services/image-assets.service.ts +46 -1
  312. package/server/modules/assets/tests/image-assets.service.test.ts +28 -0
  313. package/server/{middleware/auth.js → modules/auth/auth.middleware.ts} +38 -7
  314. package/server/modules/auth/auth.module.ts +38 -0
  315. package/server/modules/auth/auth.routes.ts +57 -0
  316. package/server/modules/auth/auth.service.ts +155 -0
  317. package/server/modules/auth/index.ts +9 -0
  318. package/server/modules/auth/tests/auth.service.test.ts +95 -0
  319. package/server/{browser-use-mcp.ts → modules/browser-use/browser-use-mcp.ts} +3 -1
  320. package/server/modules/browser-use/browser-use.service.ts +3 -4
  321. package/server/modules/browser-use/index.ts +8 -0
  322. package/server/modules/cli/cli.module.ts +96 -0
  323. package/server/modules/cli/cli.service.ts +281 -0
  324. package/server/modules/cli/cli.ts +13 -0
  325. package/server/modules/cli/index.ts +2 -0
  326. package/server/modules/cli/sandbox.service.ts +413 -0
  327. package/server/modules/cli/tests/cli.service.test.ts +91 -0
  328. package/server/modules/cli/tests/sandbox.service.test.ts +61 -0
  329. package/server/modules/commands/commands.module.ts +22 -0
  330. package/server/{routes/commands.js → modules/commands/commands.routes.ts} +44 -36
  331. package/server/modules/commands/index.ts +2 -0
  332. package/server/modules/commands/tests/commands.test.ts +119 -0
  333. package/server/modules/database/index.ts +1 -0
  334. package/server/modules/database/migrations.ts +15 -0
  335. package/server/modules/database/repositories/sessions.db.ts +19 -1
  336. package/server/modules/database/schema.ts +4 -0
  337. package/server/modules/file-tree/file-tree.module.ts +112 -0
  338. package/server/modules/file-tree/file-tree.routes.ts +258 -0
  339. package/server/modules/file-tree/file-tree.service.ts +616 -0
  340. package/server/modules/file-tree/index.ts +2 -0
  341. package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -0
  342. package/server/modules/file-tree/tests/file-tree.service.test.ts +220 -0
  343. package/server/modules/git/git-parsing.service.ts +66 -0
  344. package/server/modules/git/git.module.ts +22 -0
  345. package/server/{routes/git.js → modules/git/git.routes.ts} +91 -132
  346. package/server/modules/git/index.ts +2 -0
  347. package/server/modules/git/tests/git-init.routes.test.ts +52 -0
  348. package/server/{routes/git.test.js → modules/git/tests/git.test.ts} +3 -3
  349. package/server/modules/notifications/index.ts +9 -0
  350. package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -0
  351. package/server/{services/vapid-keys.js → modules/notifications/vapid-keys.service.ts} +3 -1
  352. package/server/modules/plugins/index.ts +9 -0
  353. package/server/{utils/plugin-process-manager.js → modules/plugins/plugin-process.service.ts} +3 -1
  354. package/server/{utils/plugin-loader.js → modules/plugins/plugin-registry.service.ts} +1 -0
  355. package/server/modules/plugins/plugins.module.ts +33 -0
  356. package/server/modules/plugins/plugins.routes.ts +66 -0
  357. package/server/modules/plugins/plugins.service.ts +147 -0
  358. package/server/modules/plugins/tests/plugins.service.test.ts +32 -0
  359. package/server/modules/projects/index.ts +5 -0
  360. package/server/modules/providers/README.md +41 -9
  361. package/server/modules/providers/index.ts +4 -0
  362. package/server/modules/providers/list/claude/claude-auth.provider.ts +8 -0
  363. package/server/modules/providers/list/claude/claude-models.provider.ts +1 -12
  364. package/server/{claude-sdk.js → modules/providers/list/claude/claude-runtime.provider.js} +66 -44
  365. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +6 -4
  366. package/server/modules/providers/list/claude/claude-sessions.provider.ts +27 -4
  367. package/server/modules/providers/list/claude/claude.provider.ts +3 -0
  368. package/server/modules/providers/list/codex/codex-models.provider.ts +0 -9
  369. package/server/{openai-codex.js → modules/providers/list/codex/codex-runtime.provider.js} +54 -36
  370. package/server/modules/providers/list/codex/codex-sessions.provider.ts +331 -7
  371. package/server/modules/providers/list/codex/codex-skills.provider.ts +5 -0
  372. package/server/modules/providers/list/codex/codex.provider.ts +3 -0
  373. package/server/modules/providers/list/cursor/cursor-models.provider.ts +0 -9
  374. package/server/{cursor-cli.js → modules/providers/list/cursor/cursor-runtime.provider.js} +58 -27
  375. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +26 -15
  376. package/server/modules/providers/list/cursor/cursor.provider.ts +3 -0
  377. package/server/modules/providers/list/opencode/opencode-models.provider.ts +7 -10
  378. package/server/{opencode-cli.js → modules/providers/list/opencode/opencode-runtime.provider.js} +56 -28
  379. package/server/{opencode-cli.test.js → modules/providers/list/opencode/opencode-runtime.provider.test.js} +41 -3
  380. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +13 -5
  381. package/server/modules/providers/list/opencode/opencode.provider.ts +3 -0
  382. package/server/modules/providers/provider.routes.ts +47 -10
  383. package/server/modules/providers/services/provider-capabilities.service.ts +7 -1
  384. package/server/modules/providers/services/provider-models.service.ts +131 -23
  385. package/server/modules/providers/services/provider-runtime.service.ts +109 -0
  386. package/server/modules/providers/services/provider-token-usage.service.ts +357 -0
  387. package/server/modules/providers/services/sessions-watcher.service.ts +2 -0
  388. package/server/modules/providers/services/sessions.service.ts +79 -0
  389. package/server/modules/providers/shared/base/abstract.provider.ts +4 -3
  390. package/server/modules/providers/tests/claude-auth.test.ts +150 -0
  391. package/server/modules/providers/tests/claude-sessions.test.ts +61 -0
  392. package/server/modules/providers/tests/codex-sessions.test.ts +40 -0
  393. package/server/modules/providers/tests/{provider-image-history.test.ts → provider-attachment-history.test.ts} +68 -1
  394. package/server/modules/providers/tests/provider-models.service.test.ts +450 -349
  395. package/server/modules/providers/tests/provider-runtime.service.test.ts +142 -0
  396. package/server/modules/providers/tests/provider-token-usage.service.test.ts +185 -0
  397. package/server/modules/providers/tests/sessions-details.test.ts +73 -0
  398. package/server/modules/providers/tests/skills.test.ts +9 -2
  399. package/server/modules/settings/index.ts +2 -0
  400. package/server/modules/settings/settings.module.ts +50 -0
  401. package/server/modules/settings/settings.routes.ts +51 -0
  402. package/server/modules/settings/settings.service.ts +186 -0
  403. package/server/modules/settings/tests/settings.service.test.ts +54 -0
  404. package/server/modules/system/index.ts +2 -0
  405. package/server/modules/system/system.module.ts +62 -0
  406. package/server/modules/system/system.routes.ts +21 -0
  407. package/server/modules/system/system.service.ts +76 -0
  408. package/server/modules/system/tests/system.service.test.ts +118 -0
  409. package/server/modules/taskmaster/index.ts +2 -0
  410. package/server/modules/taskmaster/taskmaster.module.ts +24 -0
  411. package/server/modules/taskmaster/taskmaster.routes.ts +1482 -0
  412. package/server/modules/taskmaster/taskmaster.service.ts +132 -0
  413. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +144 -0
  414. package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -0
  415. package/server/modules/user/index.ts +2 -0
  416. package/server/modules/user/tests/user.service.test.ts +61 -0
  417. package/server/modules/user/user.module.ts +58 -0
  418. package/server/modules/user/user.routes.ts +50 -0
  419. package/server/modules/user/user.service.ts +85 -0
  420. package/server/modules/voice/index.ts +2 -0
  421. package/server/modules/voice/tests/voice.service.test.ts +98 -0
  422. package/server/modules/voice/voice.module.ts +47 -0
  423. package/server/modules/voice/voice.routes.ts +113 -0
  424. package/server/modules/voice/voice.service.ts +192 -0
  425. package/server/modules/websocket/README.md +7 -7
  426. package/server/modules/websocket/services/chat-session-writer.service.ts +2 -2
  427. package/server/modules/websocket/services/chat-websocket.service.ts +73 -61
  428. package/server/modules/websocket/services/shell-websocket.service.ts +88 -12
  429. package/server/modules/websocket/services/websocket-server.service.ts +63 -19
  430. package/server/modules/websocket/tests/{chat-image-filter.test.ts → chat-attachment-filter.test.ts} +17 -2
  431. package/server/modules/websocket/tests/shell-websocket.service.test.ts +119 -0
  432. package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -0
  433. package/server/modules/worktrees/index.ts +2 -0
  434. package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -0
  435. package/server/modules/worktrees/services/worktree-create.service.ts +104 -0
  436. package/server/modules/worktrees/services/worktree-git.service.ts +207 -0
  437. package/server/modules/worktrees/services/worktree-list.service.ts +143 -0
  438. package/server/modules/worktrees/services/worktree-merge.service.ts +157 -0
  439. package/server/modules/worktrees/services/worktree-open.service.ts +85 -0
  440. package/server/modules/worktrees/services/worktree-remove.service.ts +88 -0
  441. package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -0
  442. package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -0
  443. package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -0
  444. package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -0
  445. package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -0
  446. package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -0
  447. package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -0
  448. package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -0
  449. package/server/modules/worktrees/worktrees.module.ts +113 -0
  450. package/server/modules/worktrees/worktrees.routes.ts +116 -0
  451. package/server/shared/image-attachments.ts +112 -18
  452. package/server/shared/interfaces.ts +29 -19
  453. package/server/shared/tests/image-attachments.test.ts +55 -0
  454. package/server/shared/types.ts +658 -21
  455. package/server/shared/utils.ts +77 -212
  456. package/dist/assets/index-DLmhQ15L.css +0 -32
  457. package/dist-server/server/browser-use-mcp.js.map +0 -1
  458. package/dist-server/server/claude-sdk.js.map +0 -1
  459. package/dist-server/server/cli.js +0 -647
  460. package/dist-server/server/cli.js.map +0 -1
  461. package/dist-server/server/cursor-cli.js.map +0 -1
  462. package/dist-server/server/middleware/auth.js.map +0 -1
  463. package/dist-server/server/modules/providers/tests/provider-image-history.test.js.map +0 -1
  464. package/dist-server/server/modules/websocket/tests/chat-image-filter.test.js.map +0 -1
  465. package/dist-server/server/openai-codex.js.map +0 -1
  466. package/dist-server/server/opencode-cli.js.map +0 -1
  467. package/dist-server/server/opencode-cli.test.js.map +0 -1
  468. package/dist-server/server/routes/agent.js +0 -1155
  469. package/dist-server/server/routes/agent.js.map +0 -1
  470. package/dist-server/server/routes/auth.js +0 -119
  471. package/dist-server/server/routes/auth.js.map +0 -1
  472. package/dist-server/server/routes/commands.js +0 -492
  473. package/dist-server/server/routes/commands.js.map +0 -1
  474. package/dist-server/server/routes/cursor.js +0 -49
  475. package/dist-server/server/routes/cursor.js.map +0 -1
  476. package/dist-server/server/routes/git.js +0 -1389
  477. package/dist-server/server/routes/git.js.map +0 -1
  478. package/dist-server/server/routes/git.test.js.map +0 -1
  479. package/dist-server/server/routes/mcp-utils.js +0 -29
  480. package/dist-server/server/routes/mcp-utils.js.map +0 -1
  481. package/dist-server/server/routes/plugins.js +0 -266
  482. package/dist-server/server/routes/plugins.js.map +0 -1
  483. package/dist-server/server/routes/settings.js +0 -249
  484. package/dist-server/server/routes/settings.js.map +0 -1
  485. package/dist-server/server/routes/taskmaster.js +0 -1362
  486. package/dist-server/server/routes/taskmaster.js.map +0 -1
  487. package/dist-server/server/routes/tests/commands.test.js +0 -76
  488. package/dist-server/server/routes/tests/commands.test.js.map +0 -1
  489. package/dist-server/server/routes/user.js +0 -116
  490. package/dist-server/server/routes/user.js.map +0 -1
  491. package/dist-server/server/services/notification-orchestrator.js +0 -2
  492. package/dist-server/server/services/notification-orchestrator.js.map +0 -1
  493. package/dist-server/server/services/tests/notification-orchestrator.test.js +0 -64
  494. package/dist-server/server/services/tests/notification-orchestrator.test.js.map +0 -1
  495. package/dist-server/server/services/vapid-keys.js.map +0 -1
  496. package/dist-server/server/utils/colors.js +0 -20
  497. package/dist-server/server/utils/colors.js.map +0 -1
  498. package/dist-server/server/utils/commandParser.js +0 -255
  499. package/dist-server/server/utils/commandParser.js.map +0 -1
  500. package/dist-server/server/utils/gitConfig.js +0 -37
  501. package/dist-server/server/utils/gitConfig.js.map +0 -1
  502. package/dist-server/server/utils/mcp-detector.js +0 -134
  503. package/dist-server/server/utils/mcp-detector.js.map +0 -1
  504. package/dist-server/server/utils/plugin-loader.js.map +0 -1
  505. package/dist-server/server/utils/plugin-process-manager.js.map +0 -1
  506. package/dist-server/server/utils/runtime-paths.js +0 -30
  507. package/dist-server/server/utils/runtime-paths.js.map +0 -1
  508. package/dist-server/server/utils/taskmaster-websocket.js +0 -124
  509. package/dist-server/server/utils/taskmaster-websocket.js.map +0 -1
  510. package/dist-server/server/utils/url-detection.js +0 -58
  511. package/dist-server/server/utils/url-detection.js.map +0 -1
  512. package/dist-server/server/voice-proxy.js +0 -226
  513. package/dist-server/server/voice-proxy.js.map +0 -1
  514. package/server/cli.js +0 -695
  515. package/server/index.js +0 -1651
  516. package/server/routes/agent.js +0 -1257
  517. package/server/routes/auth.js +0 -137
  518. package/server/routes/cursor.js +0 -52
  519. package/server/routes/mcp-utils.js +0 -31
  520. package/server/routes/plugins.js +0 -307
  521. package/server/routes/settings.js +0 -282
  522. package/server/routes/taskmaster.js +0 -1470
  523. package/server/routes/tests/commands.test.js +0 -82
  524. package/server/routes/user.js +0 -124
  525. package/server/services/notification-orchestrator.js +0 -7
  526. package/server/services/tests/notification-orchestrator.test.js +0 -80
  527. package/server/utils/colors.js +0 -21
  528. package/server/utils/commandParser.js +0 -305
  529. package/server/utils/gitConfig.js +0 -35
  530. package/server/utils/mcp-detector.js +0 -147
  531. package/server/utils/runtime-paths.js +0 -37
  532. package/server/utils/taskmaster-websocket.js +0 -135
  533. package/server/utils/url-detection.js +0 -71
  534. package/server/voice-proxy.js +0 -224
  535. /package/server/constants/{config.js → config.ts} +0 -0
@@ -4,7 +4,20 @@ import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import test from 'node:test';
6
6
 
7
- import { resolveOpenCodePermissionOptions, spawnOpenCode } from './opencode-cli.js';
7
+ import {
8
+ opencodeRuntime,
9
+ resolveOpenCodePermissionOptions,
10
+ } from './opencode-runtime.provider.js';
11
+ import { OpenCodeSessionsProvider } from './opencode-sessions.provider.js';
12
+
13
+ const sessionsProvider = new OpenCodeSessionsProvider();
14
+ const runtimeContext = {
15
+ resolveProviderSessionId: (sessionId) => sessionId || null,
16
+ resolveResumeModel: async (_sessionId, requestedModel) => requestedModel || undefined,
17
+ getProviderModels: async () => ({ OPTIONS: [], DEFAULT: '' }),
18
+ normalizeMessage: (raw, sessionId) => sessionsProvider.normalizeMessage(raw, sessionId),
19
+ isProviderInstalled: async () => true,
20
+ };
8
21
 
9
22
  const findEnvKey = (name) =>
10
23
  Object.keys(process.env).find((key) => key.toLowerCase() === name.toLowerCase()) || name;
@@ -71,7 +84,7 @@ test('spawnOpenCode emits session_created before normalized live messages for ne
71
84
  : `.COM;.EXE;.BAT;.CMD${previousPathExt ? `;${previousPathExt}` : ''}`;
72
85
  }
73
86
 
74
- await spawnOpenCode('Hi', { cwd: tempRoot }, writer);
87
+ await opencodeRuntime.run('Hi', { cwd: tempRoot }, writer, runtimeContext);
75
88
 
76
89
  const sessionCreatedIndex = messages.findIndex((message) => message.kind === 'session_created');
77
90
  const assistantDeltaIndex = messages.findIndex((message) =>
@@ -98,6 +111,26 @@ test('spawnOpenCode emits session_created before normalized live messages for ne
98
111
  assert.equal(launchedArgs.includes('--auto'), false);
99
112
  assert.equal(launchedArgs.includes('--agent'), false);
100
113
  assert.equal(capture.permissionEnv, null);
114
+
115
+ const attachmentOnlyCapturePath = path.join(tempRoot, 'opencode-attachment-only.json');
116
+ process.env.OPENCODE_ARGS_CAPTURE = attachmentOnlyCapturePath;
117
+ await opencodeRuntime.run(
118
+ '',
119
+ {
120
+ cwd: tempRoot,
121
+ files: [{
122
+ path: path.join(tempRoot, 'brief.pdf'),
123
+ name: 'brief.pdf',
124
+ mimeType: 'application/pdf',
125
+ }],
126
+ },
127
+ writer,
128
+ runtimeContext,
129
+ );
130
+ const attachmentOnlyCapture = JSON.parse(await readFile(attachmentOnlyCapturePath, 'utf8'));
131
+ const attachmentPrompt = attachmentOnlyCapture.args[attachmentOnlyCapture.args.length - 1];
132
+ assert.match(attachmentPrompt, /<files_input>/);
133
+ assert.match(attachmentPrompt, /brief\.pdf/);
101
134
  } finally {
102
135
  if (previousPath === undefined) {
103
136
  delete process.env[pathKey];
@@ -186,7 +219,12 @@ test('spawnOpenCode passes permission mode flags and env to the CLI', async () =
186
219
  const argsCapturePath = path.join(tempRoot, `opencode-args-${scenario.permissionMode}.json`);
187
220
  process.env.OPENCODE_ARGS_CAPTURE = argsCapturePath;
188
221
 
189
- await spawnOpenCode('Hi', { cwd: tempRoot, permissionMode: scenario.permissionMode }, writer);
222
+ await opencodeRuntime.run(
223
+ 'Hi',
224
+ { cwd: tempRoot, permissionMode: scenario.permissionMode },
225
+ writer,
226
+ runtimeContext,
227
+ );
190
228
 
191
229
  const capture = JSON.parse(await readFile(argsCapturePath, 'utf8'));
192
230
  for (const expectedArg of scenario.expectArgs) {
@@ -2,7 +2,7 @@ import fsSync from 'node:fs';
2
2
 
3
3
  import Database from 'better-sqlite3';
4
4
 
5
- import { parseImagesInputTag } from '@/shared/image-attachments.js';
5
+ import { parseFilesInputTag, parseImagesInputTag } from '@/shared/image-attachments.js';
6
6
  import type { IProviderSessions } from '@/shared/interfaces.js';
7
7
  import type { AnyRecord, FetchHistoryOptions, FetchHistoryResult, NormalizedMessage } from '@/shared/types.js';
8
8
  import {
@@ -404,10 +404,17 @@ export class OpenCodeSessionsProvider implements IProviderSessions {
404
404
  const rawContent = extractText(partData);
405
405
  // User prompts sent with attachments carry an <images_input> path
406
406
  // list; strip it for display and surface the paths as images.
407
- const { text: content, attachments } = messageRole === 'user'
407
+ const parsedImages = messageRole === 'user'
408
408
  ? parseImagesInputTag(rawContent)
409
409
  : { text: rawContent, attachments: [] };
410
- if (content.trim() || attachments.length > 0) {
410
+ const parsedFiles = messageRole === 'user'
411
+ ? parseFilesInputTag(parsedImages.text)
412
+ : { text: rawContent, attachments: [] };
413
+ if (
414
+ parsedFiles.text.trim()
415
+ || parsedImages.attachments.length > 0
416
+ || parsedFiles.attachments.length > 0
417
+ ) {
411
418
  normalized.push(createNormalizedMessage({
412
419
  id: baseId,
413
420
  sessionId,
@@ -415,8 +422,9 @@ export class OpenCodeSessionsProvider implements IProviderSessions {
415
422
  provider: PROVIDER,
416
423
  kind: 'text',
417
424
  role: messageRole === 'user' ? 'user' : 'assistant',
418
- content,
419
- images: attachments.length > 0 ? attachments : undefined,
425
+ content: parsedFiles.text,
426
+ images: parsedImages.attachments.length > 0 ? parsedImages.attachments : undefined,
427
+ files: parsedFiles.attachments.length > 0 ? parsedFiles.attachments : undefined,
420
428
  }));
421
429
  }
422
430
  continue;
@@ -1,5 +1,6 @@
1
1
  import { OpenCodeProviderAuth } from '@/modules/providers/list/opencode/opencode-auth.provider.js';
2
2
  import { OpenCodeProviderModels } from '@/modules/providers/list/opencode/opencode-models.provider.js';
3
+ import { opencodeRuntime } from '@/modules/providers/list/opencode/opencode-runtime.provider.js';
3
4
  import { OpenCodeMcpProvider } from '@/modules/providers/list/opencode/opencode-mcp.provider.js';
4
5
  import { OpenCodeSessionSynchronizer } from '@/modules/providers/list/opencode/opencode-session-synchronizer.provider.js';
5
6
  import { OpenCodeSessionsProvider } from '@/modules/providers/list/opencode/opencode-sessions.provider.js';
@@ -8,12 +9,14 @@ import { AbstractProvider } from '@/modules/providers/shared/base/abstract.provi
8
9
  import type {
9
10
  IProviderAuth,
10
11
  IProviderModels,
12
+ IProviderRuntime,
11
13
  IProviderSessionSynchronizer,
12
14
  IProviderSkills,
13
15
  IProviderSessions,
14
16
  } from '@/shared/interfaces.js';
15
17
 
16
18
  export class OpenCodeProvider extends AbstractProvider {
19
+ readonly runtime: IProviderRuntime = opencodeRuntime;
17
20
  readonly models: IProviderModels = new OpenCodeProviderModels();
18
21
  readonly mcp = new OpenCodeMcpProvider();
19
22
  readonly auth: IProviderAuth = new OpenCodeProviderAuth();
@@ -4,6 +4,7 @@ import { providerAuthService } from '@/modules/providers/services/provider-auth.
4
4
  import { providerCapabilitiesService } from '@/modules/providers/services/provider-capabilities.service.js';
5
5
  import { providerMcpService } from '@/modules/providers/services/mcp.service.js';
6
6
  import { providerModelsService } from '@/modules/providers/services/provider-models.service.js';
7
+ import { providerTokenUsageService } from '@/modules/providers/services/provider-token-usage.service.js';
7
8
  import { providerSkillsService } from '@/modules/providers/services/skills.service.js';
8
9
  import { sessionConversationsSearchService } from '@/modules/providers/services/session-conversations-search.service.js';
9
10
  import { sessionsService } from '@/modules/providers/services/sessions.service.js';
@@ -11,7 +12,6 @@ import type {
11
12
  LLMProvider,
12
13
  McpScope,
13
14
  McpTransport,
14
- ProviderChangeActiveModelInput,
15
15
  ProviderSkillCreateFile,
16
16
  ProviderSkillCreateInput,
17
17
  UpsertProviderMcpServerInput,
@@ -352,7 +352,7 @@ const parseSessionSearchLimit = (value: unknown): number => {
352
352
  return Math.max(1, Math.min(parsed, 100));
353
353
  };
354
354
 
355
- const parseChangeActiveModelPayload = (payload: unknown): ProviderChangeActiveModelInput => {
355
+ const parseSessionModelPayload = (payload: unknown): string => {
356
356
  if (!payload || typeof payload !== 'object') {
357
357
  throw new AppError('Request body must be an object.', {
358
358
  code: 'INVALID_REQUEST_BODY',
@@ -369,10 +369,7 @@ const parseChangeActiveModelPayload = (payload: unknown): ProviderChangeActiveMo
369
369
  });
370
370
  }
371
371
 
372
- return {
373
- sessionId: '',
374
- model,
375
- };
372
+ return model;
376
373
  };
377
374
 
378
375
  router.get(
@@ -394,20 +391,40 @@ router.get(
394
391
  }),
395
392
  );
396
393
 
397
- router.post(
394
+ /**
395
+ * Reports which model one session is using. `requestedModel` lets the client
396
+ * pass the default it would otherwise send, so a session that has not been
397
+ * sent on yet resolves to that instead of the catalog default.
398
+ */
399
+ router.get(
398
400
  '/:provider/sessions/:sessionId/active-model',
399
401
  asyncHandler(async (req: Request, res: Response) => {
400
402
  const provider = parseProvider(req.params.provider);
401
403
  const sessionId = parseSessionId(req.params.sessionId);
402
- const payload = parseChangeActiveModelPayload(req.body);
403
- const result = await providerModelsService.changeActiveModel(provider, {
404
- ...payload,
404
+ const requestedModel = readOptionalQueryString(req.query.requestedModel);
405
+ const result = await providerModelsService.resolveSessionModel(provider, {
405
406
  sessionId,
407
+ requestedModel,
406
408
  });
407
409
  res.json(createApiSuccessResponse(result));
408
410
  }),
409
411
  );
410
412
 
413
+ router.post(
414
+ '/:provider/sessions/:sessionId/active-model',
415
+ asyncHandler(async (req: Request, res: Response) => {
416
+ const provider = parseProvider(req.params.provider);
417
+ const sessionId = parseSessionId(req.params.sessionId);
418
+ const model = parseSessionModelPayload(req.body);
419
+ const stored = providerModelsService.setSessionModel(provider, sessionId, model);
420
+ // A session row only exists once the gateway has allocated one. Report the
421
+ // selection back either way so the client can hold it until the first send.
422
+ res.json(createApiSuccessResponse(
423
+ stored ?? { provider, sessionId, model, source: 'session' as const },
424
+ ));
425
+ }),
426
+ );
427
+
411
428
  // ----------------- Skills routes -----------------
412
429
  router.get(
413
430
  '/:provider/skills',
@@ -556,6 +573,26 @@ router.get(
556
573
  }),
557
574
  );
558
575
 
576
+ router.get(
577
+ '/sessions/:sessionId/token-usage',
578
+ asyncHandler(async (req: Request, res: Response) => {
579
+ const sessionId = parseSessionId(req.params.sessionId);
580
+ const result = await providerTokenUsageService.getSessionTokenUsage(sessionId);
581
+ res.json(createApiSuccessResponse(result));
582
+ }),
583
+ );
584
+
585
+ // Must stay registered after the static `/sessions/running` and
586
+ // `/sessions/archived` routes so those literals never match `:sessionId`.
587
+ router.get(
588
+ '/sessions/:sessionId',
589
+ asyncHandler(async (req: Request, res: Response) => {
590
+ const sessionId = parseSessionId(req.params.sessionId);
591
+ const result = sessionsService.getSessionDetailsById(sessionId);
592
+ res.json(createApiSuccessResponse(result));
593
+ }),
594
+ );
595
+
559
596
  router.delete(
560
597
  '/sessions/:sessionId',
561
598
  asyncHandler(async (req: Request, res: Response) => {
@@ -15,6 +15,8 @@ type ProviderCapabilities = {
15
15
  defaultPermissionMode: string;
16
16
  /** Whether image attachments can be included in a chat.send. */
17
17
  supportsImages: boolean;
18
+ /** Whether general file attachments can be included in a chat.send. */
19
+ supportsFiles: boolean;
18
20
  /** Whether an in-flight run can be cancelled via chat.abort. */
19
21
  supportsAbort: boolean;
20
22
  /** Whether interactive tool permission prompts can reach the UI. */
@@ -37,6 +39,7 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
37
39
  permissionModes: ['default', 'auto', 'acceptEdits', 'bypassPermissions', 'plan'],
38
40
  defaultPermissionMode: 'default',
39
41
  supportsImages: true,
42
+ supportsFiles: true,
40
43
  supportsAbort: true,
41
44
  supportsPermissionRequests: true,
42
45
  supportsTokenUsage: true,
@@ -47,6 +50,7 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
47
50
  permissionModes: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
48
51
  defaultPermissionMode: 'default',
49
52
  supportsImages: true,
53
+ supportsFiles: true,
50
54
  supportsAbort: true,
51
55
  supportsPermissionRequests: false,
52
56
  supportsTokenUsage: false,
@@ -57,6 +61,7 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
57
61
  permissionModes: ['default', 'acceptEdits', 'bypassPermissions'],
58
62
  defaultPermissionMode: 'default',
59
63
  supportsImages: true,
64
+ supportsFiles: true,
60
65
  supportsAbort: true,
61
66
  supportsPermissionRequests: false,
62
67
  supportsTokenUsage: true,
@@ -66,10 +71,11 @@ const PROVIDER_CAPABILITIES: Record<LLMProvider, ProviderCapabilities> = {
66
71
  provider: 'opencode',
67
72
  // Mapped by the runtime onto OpenCode's controls: `--agent plan` (plan),
68
73
  // `--auto` (bypassPermissions) and the OPENCODE_PERMISSION env var
69
- // (acceptEdits). See resolveOpenCodePermissionOptions in opencode-cli.js.
74
+ // (acceptEdits). See resolveOpenCodePermissionOptions in the OpenCode runtime adapter.
70
75
  permissionModes: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
71
76
  defaultPermissionMode: 'default',
72
77
  supportsImages: true,
78
+ supportsFiles: true,
73
79
  supportsAbort: true,
74
80
  supportsPermissionRequests: false,
75
81
  supportsTokenUsage: true,
@@ -2,27 +2,32 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
 
5
+ import { sessionsDb } from '@/modules/database/index.js';
5
6
  import { providerRegistry } from '@/modules/providers/provider.registry.js';
6
7
  import type { IProvider } from '@/shared/interfaces.js';
7
8
  import type {
8
9
  LLMProvider,
9
- ProviderChangeActiveModelInput,
10
10
  ProviderCurrentActiveModel,
11
11
  ProviderModelsCacheInfo,
12
12
  ProviderModelsDefinition,
13
13
  ProviderModelsResult,
14
- ProviderSessionActiveModelChange,
14
+ ProviderSessionModel,
15
15
  } from '@/shared/types.js';
16
- import { readProviderSessionActiveModelChange } from '@/shared/utils.js';
17
16
 
18
17
  export const PROVIDER_MODELS_CACHE_TTL_MS = 3 * 24 * 60 * 60 * 1000;
19
18
  const PROVIDER_MODELS_CACHE_VERSION = 2;
20
19
  const UNCACHED_PROVIDERS = new Set<LLMProvider>(['claude']);
21
20
 
21
+ /** Session-row access the service needs, narrowed so tests can stub it. */
22
+ type ProviderModelsSessionStore = {
23
+ getSessionById(sessionId: string): { model: string | null } | null;
24
+ setSessionModel(sessionId: string, model: string): void;
25
+ };
26
+
22
27
  type ProviderModelsServiceDependencies = {
23
28
  resolveProvider?: (provider: LLMProvider) => Pick<IProvider, 'models'>;
24
29
  cachePath?: string;
25
- activeModelChangesPath?: string;
30
+ sessions?: ProviderModelsSessionStore;
26
31
  now?: () => number;
27
32
  };
28
33
 
@@ -137,7 +142,7 @@ const writeProviderModelsCacheFile = async (
137
142
  export const createProviderModelsService = (dependencies: ProviderModelsServiceDependencies = {}) => {
138
143
  const resolveProvider = dependencies.resolveProvider ?? providerRegistry.resolveProvider;
139
144
  const cachePath = dependencies.cachePath ?? getProviderModelsCachePath();
140
- const activeModelChangesPath = dependencies.activeModelChangesPath;
145
+ const sessions = dependencies.sessions ?? sessionsDb;
141
146
  const now = dependencies.now ?? (() => Date.now());
142
147
  const memoryCache = new Map<LLMProvider, ProviderModelsCacheEntry>();
143
148
  const pendingRequests = new Map<LLMProvider, Promise<ProviderModelsResult>>();
@@ -308,34 +313,138 @@ export const createProviderModelsService = (dependencies: ProviderModelsServiceD
308
313
  sessionId?: string,
309
314
  ): Promise<ProviderCurrentActiveModel> => resolveProvider(provider).models.getCurrentActiveModel(sessionId);
310
315
 
311
- const changeActiveModel = async (
312
- provider: LLMProvider,
313
- input: ProviderChangeActiveModelInput,
314
- ): Promise<ProviderSessionActiveModelChange> => resolveProvider(provider).models.changeActiveModel(input);
316
+ const readRecordedSessionModel = (sessionId: string): string | null => {
317
+ const session = sessions.getSessionById(sessionId);
318
+ return session?.model?.trim() || null;
319
+ };
315
320
 
316
- const getChangedActiveModel = async (
321
+ /**
322
+ * Records the model one session runs with.
323
+ *
324
+ * Called from the active-model route when the user picks a model and from
325
+ * `chat.send` on every turn, so the row always matches what the session last
326
+ * ran with. Sessions the app has not created yet (no row) are ignored rather
327
+ * than treated as an error: the client keeps its own pending selection and
328
+ * the value lands on the row with the first send.
329
+ */
330
+ const setSessionModel = (
317
331
  provider: LLMProvider,
318
332
  sessionId: string,
319
- ): Promise<ProviderSessionActiveModelChange> => readProviderSessionActiveModelChange(provider, sessionId, {
320
- filePath: activeModelChangesPath,
321
- });
333
+ model: string,
334
+ ): ProviderSessionModel | null => {
335
+ const normalizedSessionId = sessionId.trim();
336
+ const normalizedModel = model.trim();
337
+ if (!normalizedSessionId || !normalizedModel) {
338
+ return null;
339
+ }
340
+
341
+ if (!sessions.getSessionById(normalizedSessionId)) {
342
+ return null;
343
+ }
344
+
345
+ sessions.setSessionModel(normalizedSessionId, normalizedModel);
346
+ return {
347
+ provider,
348
+ sessionId: normalizedSessionId,
349
+ model: normalizedModel,
350
+ source: 'session',
351
+ };
352
+ };
353
+
354
+ /**
355
+ * Answers "which model is this session using?" for every display surface.
356
+ *
357
+ * Precedence, highest first:
358
+ * 1. the model recorded on the session row — the user's pick, or whatever
359
+ * the last send used;
360
+ * 2. the provider's own session state, for sessions started outside the app
361
+ * that we have never recorded a model for;
362
+ * 3. `requestedModel`, the client's current default, for a chat that has no
363
+ * session yet;
364
+ * 4. the provider catalog default.
365
+ */
366
+ const resolveSessionModel = async (
367
+ provider: LLMProvider,
368
+ options: { sessionId?: string | null; requestedModel?: string | null } = {},
369
+ ): Promise<ProviderSessionModel> => {
370
+ const normalizedSessionId = typeof options.sessionId === 'string' ? options.sessionId.trim() : '';
371
+ const normalizedRequestedModel = typeof options.requestedModel === 'string'
372
+ ? options.requestedModel.trim()
373
+ : '';
374
+
375
+ if (normalizedSessionId) {
376
+ const recordedModel = readRecordedSessionModel(normalizedSessionId);
377
+ if (recordedModel) {
378
+ return {
379
+ provider,
380
+ sessionId: normalizedSessionId,
381
+ model: recordedModel,
382
+ source: 'session',
383
+ };
384
+ }
322
385
 
386
+ // Never sent on through the app. Ask the provider what its own session
387
+ // state says before falling back to anything client-supplied.
388
+ const catalog = (await getProviderModels(provider)).models;
389
+ const providerModel = await getCurrentActiveModel(provider, normalizedSessionId);
390
+ const resolvedProviderModel = providerModel.model?.trim();
391
+ if (resolvedProviderModel && resolvedProviderModel !== catalog.DEFAULT) {
392
+ return {
393
+ provider,
394
+ sessionId: normalizedSessionId,
395
+ model: resolvedProviderModel,
396
+ source: 'provider',
397
+ };
398
+ }
399
+
400
+ return {
401
+ provider,
402
+ sessionId: normalizedSessionId,
403
+ model: normalizedRequestedModel || catalog.DEFAULT,
404
+ source: normalizedRequestedModel ? 'session' : 'default',
405
+ };
406
+ }
407
+
408
+ if (normalizedRequestedModel) {
409
+ return {
410
+ provider,
411
+ sessionId: null,
412
+ model: normalizedRequestedModel,
413
+ source: 'session',
414
+ };
415
+ }
416
+
417
+ const catalog = (await getProviderModels(provider)).models;
418
+ return {
419
+ provider,
420
+ sessionId: null,
421
+ model: catalog.DEFAULT,
422
+ source: 'default',
423
+ };
424
+ };
425
+
426
+ /**
427
+ * Picks the model one run should use, for provider runtime adapters.
428
+ *
429
+ * Deliberately narrower than `resolveSessionModel`: the provider's own
430
+ * session state is not consulted here. Codex reports a global config value
431
+ * from `getCurrentActiveModel`, which would silently override the model the
432
+ * user picked in the composer on every single run.
433
+ */
323
434
  const resolveResumeModel = async (
324
435
  provider: LLMProvider,
325
436
  sessionId: string | undefined,
326
437
  requestedModel?: string | null,
327
438
  ): Promise<string | undefined> => {
439
+ void provider;
328
440
  const normalizedRequestedModel = typeof requestedModel === 'string' ? requestedModel.trim() : '';
329
- if (!sessionId?.trim()) {
441
+ const normalizedSessionId = sessionId?.trim();
442
+ if (!normalizedSessionId) {
330
443
  return normalizedRequestedModel || undefined;
331
444
  }
332
445
 
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;
446
+ const recordedModel = readRecordedSessionModel(normalizedSessionId);
447
+ return recordedModel || normalizedRequestedModel || undefined;
339
448
  };
340
449
 
341
450
  const clearCache = (): void => {
@@ -347,9 +456,8 @@ export const createProviderModelsService = (dependencies: ProviderModelsServiceD
347
456
 
348
457
  return {
349
458
  getProviderModels,
350
- getCurrentActiveModel,
351
- getChangedActiveModel,
352
- changeActiveModel,
459
+ setSessionModel,
460
+ resolveSessionModel,
353
461
  resolveResumeModel,
354
462
  clearCache,
355
463
  };
@@ -0,0 +1,109 @@
1
+ import { providerRegistry } from '@/modules/providers/provider.registry.js';
2
+ import { providerModelsService } from '@/modules/providers/services/provider-models.service.js';
3
+ import { sessionsService } from '@/modules/providers/services/sessions.service.js';
4
+ import type { IProvider } from '@/shared/interfaces.js';
5
+ import type {
6
+ AnyRecord,
7
+ LLMProvider,
8
+ ProviderPermissionDecision,
9
+ ProviderRunFunction,
10
+ ProviderRuntimeContext,
11
+ ProviderRuntimeWriter,
12
+ } from '@/shared/types.js';
13
+
14
+ type ProviderRuntimeServiceDependencies = {
15
+ listProviders(): IProvider[];
16
+ resolveProvider(provider: string): IProvider;
17
+ resolveProviderSessionId(sessionId: string | null | undefined): string | null;
18
+ resolveResumeModel(
19
+ provider: LLMProvider,
20
+ sessionId: string | undefined,
21
+ requestedModel?: string | null,
22
+ ): Promise<string | undefined>;
23
+ getProviderModels: typeof providerModelsService.getProviderModels;
24
+ };
25
+
26
+ const defaultDependencies: ProviderRuntimeServiceDependencies = {
27
+ listProviders: () => providerRegistry.listProviders(),
28
+ resolveProvider: (provider) => providerRegistry.resolveProvider(provider),
29
+ resolveProviderSessionId: (sessionId) => sessionsService.resolveProviderSessionId(sessionId),
30
+ resolveResumeModel: (provider, sessionId, requestedModel) =>
31
+ providerModelsService.resolveResumeModel(provider, sessionId, requestedModel),
32
+ getProviderModels: (provider, options) => providerModelsService.getProviderModels(provider, options),
33
+ };
34
+
35
+ /**
36
+ * Creates the application-facing provider runtime dispatcher.
37
+ *
38
+ * The provider registry owns each concrete runtime. This service supplies the
39
+ * registry-backed model/session lookups at execution time so runtime adapters
40
+ * never import services that resolve back through the registry.
41
+ */
42
+ export function createProviderRuntimeService(
43
+ dependencyOverrides: Partial<ProviderRuntimeServiceDependencies> = {},
44
+ ) {
45
+ const dependencies = { ...defaultDependencies, ...dependencyOverrides };
46
+
47
+ const createRuntimeContext = (
48
+ provider: IProvider,
49
+ ): ProviderRuntimeContext => ({
50
+ resolveProviderSessionId: dependencies.resolveProviderSessionId,
51
+ resolveResumeModel: (sessionId, requestedModel) =>
52
+ dependencies.resolveResumeModel(provider.id, sessionId, requestedModel),
53
+ getProviderModels: async () =>
54
+ (await dependencies.getProviderModels(provider.id)).models,
55
+ normalizeMessage: (raw, sessionId) => provider.sessions.normalizeMessage(raw, sessionId),
56
+ async isProviderInstalled() {
57
+ try {
58
+ return (await provider.auth.getStatus()).installed;
59
+ } catch {
60
+ // Preserve the runtime's original error when installation probing fails.
61
+ return true;
62
+ }
63
+ },
64
+ });
65
+
66
+ const run = (
67
+ providerName: LLMProvider,
68
+ command: string,
69
+ options: AnyRecord,
70
+ writer: ProviderRuntimeWriter,
71
+ ): Promise<unknown> => {
72
+ const provider = dependencies.resolveProvider(providerName);
73
+ return provider.runtime.run(command, options, writer, createRuntimeContext(provider));
74
+ };
75
+
76
+ return {
77
+ run,
78
+
79
+ hasRuntime(providerName: string): boolean {
80
+ try {
81
+ return Boolean(dependencies.resolveProvider(providerName).runtime);
82
+ } catch {
83
+ return false;
84
+ }
85
+ },
86
+
87
+ getRunner(provider: LLMProvider): ProviderRunFunction {
88
+ return (command, options, writer) => run(provider, command, options, writer);
89
+ },
90
+
91
+ async abort(providerName: LLMProvider, sessionId: string): Promise<boolean> {
92
+ return Boolean(await dependencies.resolveProvider(providerName).runtime.abort(sessionId));
93
+ },
94
+
95
+ resolveToolApproval(requestId: string, decision: ProviderPermissionDecision): void {
96
+ for (const provider of dependencies.listProviders()) {
97
+ provider.runtime.permissions?.resolve(requestId, decision);
98
+ }
99
+ },
100
+
101
+ getPendingApprovalsForSession(sessionId: string): unknown[] {
102
+ return dependencies.listProviders().flatMap(
103
+ (provider) => provider.runtime.permissions?.listPending(sessionId) ?? [],
104
+ );
105
+ },
106
+ };
107
+ }
108
+
109
+ export const providerRuntimeService = createProviderRuntimeService();