@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
@@ -0,0 +1,199 @@
1
+ import assert from 'node:assert/strict';
2
+ import { once } from 'node:events';
3
+ import type { AddressInfo } from 'node:net';
4
+ import test from 'node:test';
5
+
6
+ import express, {
7
+ type NextFunction,
8
+ type Request,
9
+ type Response,
10
+ } from 'express';
11
+
12
+ import { createWorktreesRouter } from '@/modules/worktrees/worktrees.routes.js';
13
+ import type {
14
+ CreateWorktreeInput,
15
+ WorktreeServices,
16
+ } from '@/shared/types.js';
17
+ import { AppError } from '@/shared/utils.js';
18
+
19
+ function createFakeServices(overrides: Partial<WorktreeServices> = {}): WorktreeServices {
20
+ const unused = async (): Promise<never> => {
21
+ throw new Error('Unexpected Worktrees service call');
22
+ };
23
+
24
+ return {
25
+ resolveProjectPath: () => {
26
+ throw new Error('Unexpected project resolution');
27
+ },
28
+ list: unused,
29
+ create: unused,
30
+ createAndOpen: unused,
31
+ open: unused,
32
+ merge: unused,
33
+ remove: unused,
34
+ ...overrides,
35
+ };
36
+ }
37
+
38
+ async function withWorktreesServer(
39
+ services: WorktreeServices,
40
+ run: (baseUrl: string) => Promise<void>,
41
+ ): Promise<void> {
42
+ const app = express();
43
+ app.use(express.json());
44
+ app.use('/api/worktrees', createWorktreesRouter(services));
45
+ app.use((error: unknown, _req: Request, res: Response, _next: NextFunction) => {
46
+ if (error instanceof AppError) {
47
+ res.status(error.statusCode).json({ error: error.code });
48
+ return;
49
+ }
50
+
51
+ res.status(500).json({ error: 'INTERNAL_ERROR' });
52
+ });
53
+
54
+ const server = app.listen(0, '127.0.0.1');
55
+ await once(server, 'listening');
56
+
57
+ try {
58
+ const address = server.address() as AddressInfo;
59
+ await run(`http://127.0.0.1:${address.port}`);
60
+ } finally {
61
+ await new Promise<void>((resolve, reject) => {
62
+ server.close((error) => error ? reject(error) : resolve());
63
+ });
64
+ }
65
+ }
66
+
67
+ test('create route parses input and invokes the create-and-open application service', async () => {
68
+ const createInputs: CreateWorktreeInput[] = [];
69
+ const services = createFakeServices({
70
+ resolveProjectPath: (projectId) => {
71
+ assert.equal(projectId, 'project-1');
72
+ return '/workspace/repo';
73
+ },
74
+ createAndOpen: async (input) => {
75
+ createInputs.push(input);
76
+ return {
77
+ worktreePath: '/workspace/repo-worktrees/feature-login',
78
+ branch: input.branch,
79
+ createdBranch: true,
80
+ project: {
81
+ projectId: 'worktree-project-1',
82
+ path: '/workspace/repo-worktrees/feature-login',
83
+ fullPath: '/workspace/repo-worktrees/feature-login',
84
+ displayName: 'repo worktree',
85
+ isStarred: false,
86
+ sessions: [],
87
+ sessionMeta: { hasMore: false, total: 0 },
88
+ },
89
+ };
90
+ },
91
+ });
92
+
93
+ await withWorktreesServer(services, async (baseUrl) => {
94
+ const response = await fetch(`${baseUrl}/api/worktrees/create`, {
95
+ method: 'POST',
96
+ headers: { 'content-type': 'application/json' },
97
+ body: JSON.stringify({
98
+ project: ' project-1 ',
99
+ branch: ' feature/login ',
100
+ baseBranch: 'main',
101
+ }),
102
+ });
103
+ const payload = await response.json() as {
104
+ success: boolean;
105
+ data: { project: { projectId: string } };
106
+ };
107
+
108
+ assert.equal(response.status, 200);
109
+ assert.equal(payload.success, true);
110
+ assert.equal(payload.data.project.projectId, 'worktree-project-1');
111
+ });
112
+
113
+ assert.deepEqual(createInputs, [{
114
+ projectPath: '/workspace/repo',
115
+ branch: 'feature/login',
116
+ baseBranch: 'main',
117
+ }]);
118
+ });
119
+
120
+ test('create route rejects missing branch before calling a mutation service', async () => {
121
+ let createCalled = false;
122
+ const services = createFakeServices({
123
+ resolveProjectPath: () => '/workspace/repo',
124
+ createAndOpen: async () => {
125
+ createCalled = true;
126
+ throw new Error('create should not run for invalid input');
127
+ },
128
+ });
129
+
130
+ await withWorktreesServer(services, async (baseUrl) => {
131
+ const response = await fetch(`${baseUrl}/api/worktrees/create`, {
132
+ method: 'POST',
133
+ headers: { 'content-type': 'application/json' },
134
+ body: JSON.stringify({ project: 'project-1' }),
135
+ });
136
+ const payload = await response.json() as { error: string };
137
+
138
+ assert.equal(response.status, 400);
139
+ assert.equal(payload.error, 'INVALID_REQUEST_BODY');
140
+ });
141
+
142
+ assert.equal(createCalled, false);
143
+ });
144
+
145
+ test('merge and remove routes do not coerce string booleans to true', async () => {
146
+ const mergeInputs: Array<{ squash?: boolean; removeAfterMerge?: boolean }> = [];
147
+ const removeInputs: Array<{ force?: boolean; deleteBranch?: boolean }> = [];
148
+ const services = createFakeServices({
149
+ resolveProjectPath: () => '/workspace/repo',
150
+ merge: async (input) => {
151
+ mergeInputs.push(input);
152
+ return {
153
+ mergedBranch: 'feature/login',
154
+ targetBranch: 'main',
155
+ squash: false,
156
+ removedWorktree: null,
157
+ cleanupError: null,
158
+ };
159
+ },
160
+ remove: async (input) => {
161
+ removeInputs.push(input);
162
+ return {
163
+ removedPath: input.worktreePath,
164
+ branch: 'feature/login',
165
+ branchDeleted: false,
166
+ archivedProjectId: null,
167
+ archivalError: null,
168
+ };
169
+ },
170
+ });
171
+
172
+ await withWorktreesServer(services, async (baseUrl) => {
173
+ const body = {
174
+ project: 'project-1',
175
+ worktreePath: '/workspace/repo-worktrees/feature-login',
176
+ squash: 'false',
177
+ removeAfterMerge: 'false',
178
+ force: 'false',
179
+ deleteBranch: 'false',
180
+ };
181
+ const mergeResponse = await fetch(`${baseUrl}/api/worktrees/merge`, {
182
+ method: 'POST',
183
+ headers: { 'content-type': 'application/json' },
184
+ body: JSON.stringify(body),
185
+ });
186
+ const removeResponse = await fetch(`${baseUrl}/api/worktrees/remove`, {
187
+ method: 'POST',
188
+ headers: { 'content-type': 'application/json' },
189
+ body: JSON.stringify(body),
190
+ });
191
+ assert.equal(mergeResponse.status, 200);
192
+ assert.equal(removeResponse.status, 200);
193
+ });
194
+
195
+ assert.equal(mergeInputs[0].squash, false);
196
+ assert.equal(mergeInputs[0].removeAfterMerge, false);
197
+ assert.equal(removeInputs[0].force, false);
198
+ assert.equal(removeInputs[0].deleteBranch, false);
199
+ });
@@ -0,0 +1,113 @@
1
+ import { access } from 'node:fs/promises';
2
+
3
+ import { projectsDb } from '@/modules/database/index.js';
4
+ import {
5
+ createProject,
6
+ deleteOrArchiveProject,
7
+ restoreArchivedProject,
8
+ } from '@/modules/projects/index.js';
9
+ import type {
10
+ WorktreeFileSystem,
11
+ WorktreeProjectGateway,
12
+ WorktreeServices,
13
+ } from '@/shared/types.js';
14
+ import { AppError } from '@/shared/utils.js';
15
+ import { createWorktree } from '@/modules/worktrees/services/worktree-create.service.js';
16
+ import { createAndOpenWorktree } from '@/modules/worktrees/services/worktree-create-and-open.service.js';
17
+ import { runGitCommand } from '@/modules/worktrees/services/worktree-git.service.js';
18
+ import { listWorktrees } from '@/modules/worktrees/services/worktree-list.service.js';
19
+ import { mergeWorktree } from '@/modules/worktrees/services/worktree-merge.service.js';
20
+ import { openWorktreeAsProject } from '@/modules/worktrees/services/worktree-open.service.js';
21
+ import { removeWorktree } from '@/modules/worktrees/services/worktree-remove.service.js';
22
+ import { createWorktreesRouter } from '@/modules/worktrees/worktrees.routes.js';
23
+
24
+ /**
25
+ * Real filesystem adapter used only by Worktrees production composition.
26
+ *
27
+ * Services depend on the shared capability type and therefore cannot touch a
28
+ * developer's filesystem unless this adapter is explicitly supplied.
29
+ */
30
+ const worktreeFileSystem: WorktreeFileSystem = {
31
+ async pathExists(candidatePath: string): Promise<boolean> {
32
+ try {
33
+ await access(candidatePath);
34
+ return true;
35
+ } catch {
36
+ return false;
37
+ }
38
+ },
39
+ };
40
+
41
+ /**
42
+ * Projects boundary for Worktrees production workflows.
43
+ *
44
+ * Imports are deliberately restricted to the Database and Projects barrel
45
+ * files. No Worktrees service knows which repository or project service backs
46
+ * these operations.
47
+ */
48
+ const worktreeProjects: WorktreeProjectGateway = {
49
+ getProjectPathById: (projectId) => projectsDb.getProjectPathById(projectId),
50
+ getProjectByPath: (projectPath) => projectsDb.getProjectPath(projectPath),
51
+ createProject: (input) => createProject(input),
52
+ restoreProject: (projectId) => restoreArchivedProject(projectId),
53
+ archiveProject: (projectId) => deleteOrArchiveProject(projectId, false),
54
+ };
55
+
56
+ const remove: WorktreeServices['remove'] = (input) => removeWorktree(input, {
57
+ runGit: runGitCommand,
58
+ projects: worktreeProjects,
59
+ });
60
+
61
+ const create: WorktreeServices['create'] = (input) => createWorktree(input, {
62
+ runGit: runGitCommand,
63
+ fileSystem: worktreeFileSystem,
64
+ });
65
+
66
+ const open: WorktreeServices['open'] = (input) => openWorktreeAsProject(input, {
67
+ runGit: runGitCommand,
68
+ projects: worktreeProjects,
69
+ });
70
+
71
+ /**
72
+ * Production Worktrees application-service surface.
73
+ *
74
+ * This is the module's composition root: it is the only location that combines
75
+ * concrete adapters with the independently testable workflow functions.
76
+ */
77
+ const worktreeServices: WorktreeServices = {
78
+ resolveProjectPath(projectId) {
79
+ const projectPath = worktreeProjects.getProjectPathById(projectId);
80
+ if (!projectPath) {
81
+ throw new AppError(`Unable to resolve project path for "${projectId}"`, {
82
+ code: 'PROJECT_NOT_FOUND',
83
+ statusCode: 404,
84
+ });
85
+ }
86
+
87
+ return projectPath;
88
+ },
89
+ list: (input) => listWorktrees(input, {
90
+ runGit: runGitCommand,
91
+ getProjectByPath: worktreeProjects.getProjectByPath,
92
+ }),
93
+ create,
94
+ createAndOpen: (input) => createAndOpenWorktree(input, {
95
+ createWorktree: create,
96
+ openWorktree: open,
97
+ removeWorktree: remove,
98
+ }),
99
+ open,
100
+ merge: (input) => mergeWorktree(input, {
101
+ runGit: runGitCommand,
102
+ removeWorktree: remove,
103
+ }),
104
+ remove,
105
+ };
106
+
107
+ /**
108
+ * Worktrees router mounted by the server entrypoint at `/api/worktrees`.
109
+ *
110
+ * It is assembled here so other modules consume only the Worktrees barrel and
111
+ * cannot depend on route or service implementation files.
112
+ */
113
+ export const worktreesRoutes = createWorktreesRouter(worktreeServices);
@@ -0,0 +1,116 @@
1
+ import express from 'express';
2
+
3
+ import type { WorktreeServices } from '@/shared/types.js';
4
+ import { AppError, asyncHandler, createApiSuccessResponse } from '@/shared/utils.js';
5
+
6
+ /**
7
+ * Parses the project identifier shared by all Worktrees routes.
8
+ *
9
+ * Path resolution intentionally remains in the injected application service so
10
+ * this transport layer never reaches into the Database module.
11
+ */
12
+ function readProjectId(projectIdValue: unknown): string {
13
+ const projectId = typeof projectIdValue === 'string' ? projectIdValue.trim() : '';
14
+ if (!projectId) {
15
+ throw new AppError('project is required', {
16
+ code: 'PROJECT_ID_REQUIRED',
17
+ statusCode: 400,
18
+ });
19
+ }
20
+
21
+ return projectId;
22
+ }
23
+
24
+ function readRequiredString(value: unknown, name: string): string {
25
+ const parsed = typeof value === 'string' ? value.trim() : '';
26
+ if (!parsed) {
27
+ throw new AppError(`${name} is required`, {
28
+ code: 'INVALID_REQUEST_BODY',
29
+ statusCode: 400,
30
+ });
31
+ }
32
+ return parsed;
33
+ }
34
+
35
+ /**
36
+ * Builds the Worktrees HTTP router around an injected application-service API.
37
+ *
38
+ * Keeping construction explicit lets route tests supply deterministic services
39
+ * and ensures parsing remains the route layer's only responsibility.
40
+ */
41
+ export function createWorktreesRouter(services: WorktreeServices): express.Router {
42
+ const router = express.Router();
43
+
44
+ router.get(
45
+ '/',
46
+ asyncHandler(async (req, res) => {
47
+ const projectPath = services.resolveProjectPath(readProjectId(req.query.project));
48
+ const result = await services.list({ projectPath });
49
+ res.json(createApiSuccessResponse(result));
50
+ }),
51
+ );
52
+
53
+ router.post(
54
+ '/create',
55
+ asyncHandler(async (req, res) => {
56
+ const body = req.body as Record<string, unknown>;
57
+ const projectPath = services.resolveProjectPath(readProjectId(body.project));
58
+ const branch = readRequiredString(body.branch, 'branch');
59
+ const baseBranch = typeof body.baseBranch === 'string' ? body.baseBranch : null;
60
+
61
+ const result = await services.createAndOpen({ projectPath, branch, baseBranch });
62
+ res.json(createApiSuccessResponse(result));
63
+ }),
64
+ );
65
+
66
+ router.post(
67
+ '/open',
68
+ asyncHandler(async (req, res) => {
69
+ const body = req.body as Record<string, unknown>;
70
+ const projectPath = services.resolveProjectPath(readProjectId(body.project));
71
+ const worktreePath = readRequiredString(body.worktreePath, 'worktreePath');
72
+
73
+ const project = await services.open({ projectPath, worktreePath });
74
+ res.json(createApiSuccessResponse({ project }));
75
+ }),
76
+ );
77
+
78
+ router.post(
79
+ '/merge',
80
+ asyncHandler(async (req, res) => {
81
+ const body = req.body as Record<string, unknown>;
82
+ const projectPath = services.resolveProjectPath(readProjectId(body.project));
83
+ const worktreePath = readRequiredString(body.worktreePath, 'worktreePath');
84
+
85
+ const result = await services.merge({
86
+ projectPath,
87
+ worktreePath,
88
+ squash: typeof body.squash === 'boolean' ? body.squash : false,
89
+ message: typeof body.message === 'string' ? body.message : null,
90
+ removeAfterMerge: typeof body.removeAfterMerge === 'boolean' ? body.removeAfterMerge : false,
91
+ });
92
+
93
+ res.json(createApiSuccessResponse(result));
94
+ }),
95
+ );
96
+
97
+ router.post(
98
+ '/remove',
99
+ asyncHandler(async (req, res) => {
100
+ const body = req.body as Record<string, unknown>;
101
+ const projectPath = services.resolveProjectPath(readProjectId(body.project));
102
+ const worktreePath = readRequiredString(body.worktreePath, 'worktreePath');
103
+
104
+ const result = await services.remove({
105
+ projectPath,
106
+ worktreePath,
107
+ force: typeof body.force === 'boolean' ? body.force : false,
108
+ deleteBranch: typeof body.deleteBranch === 'boolean' ? body.deleteBranch : false,
109
+ });
110
+
111
+ res.json(createApiSuccessResponse(result));
112
+ }),
113
+ );
114
+
115
+ return router;
116
+ }
@@ -3,17 +3,18 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
 
5
5
  /**
6
- * Shared image-attachment plumbing for every provider runtime.
6
+ * Shared chat-attachment plumbing for every provider runtime.
7
7
  *
8
- * Uploaded chat images are persisted once in the global `~/.cloudcli/assets`
8
+ * Uploaded chat files are persisted once in the global `~/.cloudcli/assets`
9
9
  * folder and referenced by absolute path everywhere else:
10
10
  * - Claude: paths are read back into base64 `image` content blocks.
11
11
  * - Codex: paths become `local_image` input items.
12
- * - Cursor/OpenCode: paths are appended to the prompt inside an
13
- * `<images_input>` tag, which is stripped again when history is read.
12
+ * - General files: verified paths are appended inside a `<files_input>` tag,
13
+ * which every provider history adapter strips back out for display.
14
+ * - Cursor/OpenCode images: paths use the equivalent `<images_input>` tag.
14
15
  *
15
- * The chat UI loads them through the dedicated `/api/assets/images/:filename`
16
- * route, which serves only from this folder.
16
+ * The chat UI loads them through dedicated `/api/assets/images/:filename` and
17
+ * `/api/assets/files/:filename` routes, which serve only from this folder.
17
18
  */
18
19
 
19
20
  /** Global storage folder for uploaded chat image attachments. */
@@ -26,8 +27,12 @@ export type ImageAttachmentDescriptor = {
26
27
  path: string;
27
28
  name?: string;
28
29
  mimeType?: string;
30
+ size?: number;
29
31
  };
30
32
 
33
+ /** Provider-neutral descriptor used for both image and non-image chat attachments. */
34
+ export type ChatAttachmentDescriptor = ImageAttachmentDescriptor;
35
+
31
36
  /** Media types the Claude Messages API accepts for base64 image blocks. */
32
37
  const CLAUDE_IMAGE_MEDIA_TYPES = new Set([
33
38
  'image/jpeg',
@@ -46,17 +51,17 @@ const EXTENSION_TO_MEDIA_TYPE: Record<string, string> = {
46
51
  };
47
52
 
48
53
  /**
49
- * Accepts the loosely-typed `options.images` payload from chat.send and
50
- * returns only well-formed descriptors. Plain path strings are supported so
51
- * callers can also pass bare path arrays.
54
+ * Accepts a loosely typed chat attachment payload and returns only well-formed
55
+ * descriptors. The websocket gateway and provider adapters use this to handle
56
+ * current `attachments` payloads and legacy image path arrays consistently.
52
57
  */
53
- export function normalizeImageDescriptors(images: unknown): ImageAttachmentDescriptor[] {
54
- if (!Array.isArray(images)) {
58
+ export function normalizeAttachmentDescriptors(attachments: unknown): ChatAttachmentDescriptor[] {
59
+ if (!Array.isArray(attachments)) {
55
60
  return [];
56
61
  }
57
62
 
58
- const descriptors: ImageAttachmentDescriptor[] = [];
59
- for (const entry of images) {
63
+ const descriptors: ChatAttachmentDescriptor[] = [];
64
+ for (const entry of attachments) {
60
65
  if (typeof entry === 'string' && entry.trim()) {
61
66
  descriptors.push({ path: entry.trim() });
62
67
  continue;
@@ -67,16 +72,40 @@ export function normalizeImageDescriptors(images: unknown): ImageAttachmentDescr
67
72
  if (!entryPath) {
68
73
  continue;
69
74
  }
70
- descriptors.push({
71
- path: entryPath,
72
- name: typeof record.name === 'string' ? record.name : undefined,
73
- mimeType: typeof record.mimeType === 'string' ? record.mimeType : undefined,
74
- });
75
+ const descriptor: ChatAttachmentDescriptor = { path: entryPath };
76
+ if (typeof record.name === 'string') {
77
+ descriptor.name = record.name;
78
+ }
79
+ if (typeof record.mimeType === 'string') {
80
+ descriptor.mimeType = record.mimeType;
81
+ }
82
+ if (typeof record.size === 'number' && Number.isFinite(record.size)) {
83
+ descriptor.size = record.size;
84
+ }
85
+ descriptors.push(descriptor);
75
86
  }
76
87
  }
77
88
  return descriptors;
78
89
  }
79
90
 
91
+ /** Backward-compatible image-specific alias used by existing provider adapters. */
92
+ export function normalizeImageDescriptors(images: unknown): ImageAttachmentDescriptor[] {
93
+ return normalizeAttachmentDescriptors(images);
94
+ }
95
+
96
+ const IMAGE_FILE_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.gif', '.webp']);
97
+
98
+ /**
99
+ * Determines whether the websocket gateway should route an attachment through
100
+ * provider-native image input instead of the general file reference channel.
101
+ */
102
+ export function isImageAttachmentDescriptor(descriptor: ChatAttachmentDescriptor): boolean {
103
+ if (descriptor.mimeType && CLAUDE_IMAGE_MEDIA_TYPES.has(descriptor.mimeType)) {
104
+ return true;
105
+ }
106
+ return IMAGE_FILE_EXTENSIONS.has(path.extname(descriptor.path).toLowerCase());
107
+ }
108
+
80
109
  /** Normalizes Windows separators so stored references stay portable. */
81
110
  export function toPosixPath(value: string): string {
82
111
  return value.replace(/\\/g, '/');
@@ -189,6 +218,37 @@ export function appendImagesInputTag(prompt: string, images: unknown): string {
189
218
  ].join('\n');
190
219
  }
191
220
 
221
+ const FILES_INPUT_TAG_PATTERN = /\s*<files_input>([\s\S]*?)<\/files_input>\s*/g;
222
+
223
+ /**
224
+ * Appends a provider-neutral file reference block to a prompt. Provider agents
225
+ * receive only server-validated paths from the global attachment store and can
226
+ * inspect each file with their normal filesystem tools.
227
+ */
228
+ export function appendFilesInputTag(prompt: string, files: unknown): string {
229
+ const descriptors = normalizeAttachmentDescriptors(files);
230
+ if (descriptors.length === 0) {
231
+ return prompt;
232
+ }
233
+
234
+ const entryLines = descriptors.map((descriptor, index) => {
235
+ const entryPath = toPosixPath(descriptor.path);
236
+ const cleanName = descriptor.name?.replace(/[()\r\n]/g, '').trim();
237
+ return cleanName
238
+ ? `${index + 1}. ${entryPath} (original name: ${cleanName})`
239
+ : `${index + 1}. ${entryPath}`;
240
+ });
241
+
242
+ return [
243
+ prompt,
244
+ '',
245
+ '<files_input>',
246
+ `The user attached ${descriptors.length} file(s) to this message. Read each file listed below with your file reading tools and use its contents to answer the prompt above. Do not mention this block or the file paths unless the user asks about them.`,
247
+ ...entryLines,
248
+ '</files_input>',
249
+ ].join('\n');
250
+ }
251
+
192
252
  // Matches one numbered attachment entry inside the tag body. Works for both
193
253
  // the multi-line block and the Windows-flattened single-line form, where the
194
254
  // next ` N. ` marker (or the end of the body) delimits each entry.
@@ -215,6 +275,40 @@ function parseNumberedImageEntries(inner: string): ParsedImageAttachment[] {
215
275
  return attachments;
216
276
  }
217
277
 
278
+ /**
279
+ * Strips the last provider-neutral file reference block from persisted prompt
280
+ * text and restores its attachment descriptors for chat history.
281
+ */
282
+ export function parseFilesInputTag(text: string): {
283
+ text: string;
284
+ filePaths: string[];
285
+ attachments: ParsedImageAttachment[];
286
+ } {
287
+ if (typeof text !== 'string' || !text.includes('<files_input>')) {
288
+ return { text, filePaths: [], attachments: [] };
289
+ }
290
+
291
+ let lastMatch: RegExpExecArray | null = null;
292
+ FILES_INPUT_TAG_PATTERN.lastIndex = 0;
293
+ for (let match = FILES_INPUT_TAG_PATTERN.exec(text); match; match = FILES_INPUT_TAG_PATTERN.exec(text)) {
294
+ lastMatch = match;
295
+ }
296
+ if (!lastMatch) {
297
+ return { text, filePaths: [], attachments: [] };
298
+ }
299
+
300
+ const attachments = parseNumberedImageEntries(lastMatch[1]);
301
+ const stripped = (
302
+ text.slice(0, lastMatch.index) + '\n' + text.slice(lastMatch.index + lastMatch[0].length)
303
+ ).trim();
304
+
305
+ return {
306
+ text: stripped,
307
+ filePaths: attachments.map((attachment) => attachment.path),
308
+ attachments,
309
+ };
310
+ }
311
+
218
312
  /**
219
313
  * Strips one `<images_input>` block from persisted prompt text and returns
220
314
  * the clean text plus the referenced attachments (path and original name).