@cloudcli-ai/cloudcli 1.34.0 → 1.35.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 (324) hide show
  1. package/README.de.md +9 -1
  2. package/README.ja.md +8 -0
  3. package/README.ko.md +9 -1
  4. package/README.md +16 -3
  5. package/README.ru.md +9 -1
  6. package/README.tr.md +8 -1
  7. package/README.zh-CN.md +9 -1
  8. package/README.zh-TW.md +9 -1
  9. package/dist/api-docs.html +36 -18
  10. package/dist/assets/index-CtwxqzGG.js +1407 -0
  11. package/dist/assets/index-DlvtxFyt.css +32 -0
  12. package/dist/index.html +2 -2
  13. package/dist-server/server/browser-use-mcp.js +350 -0
  14. package/dist-server/server/browser-use-mcp.js.map +1 -0
  15. package/dist-server/server/claude-sdk.js +25 -5
  16. package/dist-server/server/claude-sdk.js.map +1 -1
  17. package/dist-server/server/cli.js +14 -6
  18. package/dist-server/server/cli.js.map +1 -1
  19. package/dist-server/server/computer-use-agent.js +242 -0
  20. package/dist-server/server/computer-use-agent.js.map +1 -0
  21. package/dist-server/server/computer-use-mcp.js +519 -0
  22. package/dist-server/server/computer-use-mcp.js.map +1 -0
  23. package/dist-server/server/cursor-cli.js +27 -11
  24. package/dist-server/server/cursor-cli.js.map +1 -1
  25. package/dist-server/server/gemini-cli.js +17 -2
  26. package/dist-server/server/gemini-cli.js.map +1 -1
  27. package/dist-server/server/index.js +149 -40
  28. package/dist-server/server/index.js.map +1 -1
  29. package/dist-server/server/load-env.js +1 -1
  30. package/dist-server/server/load-env.js.map +1 -1
  31. package/dist-server/server/modules/browser-use/browser-use-mcp.routes.js +107 -0
  32. package/dist-server/server/modules/browser-use/browser-use-mcp.routes.js.map +1 -0
  33. package/dist-server/server/modules/browser-use/browser-use.routes.js +93 -0
  34. package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -0
  35. package/dist-server/server/modules/browser-use/browser-use.service.js +688 -0
  36. package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -0
  37. package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js +8 -0
  38. package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js.map +1 -0
  39. package/dist-server/server/modules/computer-use/actions/raw-action-dispatcher.js +55 -0
  40. package/dist-server/server/modules/computer-use/actions/raw-action-dispatcher.js.map +1 -0
  41. package/dist-server/server/modules/computer-use/actions/raw-action-types.js +2 -0
  42. package/dist-server/server/modules/computer-use/actions/raw-action-types.js.map +1 -0
  43. package/dist-server/server/modules/computer-use/computer-executor.js +212 -0
  44. package/dist-server/server/modules/computer-use/computer-executor.js.map +1 -0
  45. package/dist-server/server/modules/computer-use/computer-semantics.service.js +422 -0
  46. package/dist-server/server/modules/computer-use/computer-semantics.service.js.map +1 -0
  47. package/dist-server/server/modules/computer-use/computer-use-mcp.routes.js +126 -0
  48. package/dist-server/server/modules/computer-use/computer-use-mcp.routes.js.map +1 -0
  49. package/dist-server/server/modules/computer-use/computer-use.routes.js +196 -0
  50. package/dist-server/server/modules/computer-use/computer-use.routes.js.map +1 -0
  51. package/dist-server/server/modules/computer-use/computer-use.service.js +759 -0
  52. package/dist-server/server/modules/computer-use/computer-use.service.js.map +1 -0
  53. package/dist-server/server/modules/computer-use/desktop-agent-relay.service.js +126 -0
  54. package/dist-server/server/modules/computer-use/desktop-agent-relay.service.js.map +1 -0
  55. package/dist-server/server/modules/computer-use/index.js +3 -0
  56. package/dist-server/server/modules/computer-use/index.js.map +1 -0
  57. package/dist-server/server/modules/computer-use/semantics/adapters/helper-semantic-adapter.js +59 -0
  58. package/dist-server/server/modules/computer-use/semantics/adapters/helper-semantic-adapter.js.map +1 -0
  59. package/dist-server/server/modules/computer-use/semantics/adapters/macos/macos-semantic-adapter.js +5 -0
  60. package/dist-server/server/modules/computer-use/semantics/adapters/macos/macos-semantic-adapter.js.map +1 -0
  61. package/dist-server/server/modules/computer-use/semantics/adapters/semantic-adapter.js +2 -0
  62. package/dist-server/server/modules/computer-use/semantics/adapters/semantic-adapter.js.map +1 -0
  63. package/dist-server/server/modules/computer-use/semantics/adapters/windows/windows-semantic-adapter.js +5 -0
  64. package/dist-server/server/modules/computer-use/semantics/adapters/windows/windows-semantic-adapter.js.map +1 -0
  65. package/dist-server/server/modules/computer-use/semantics/bin/darwin-arm64/CloudCLISemantics +0 -0
  66. package/dist-server/server/modules/computer-use/semantics/bin/darwin-x64/CloudCLISemantics +0 -0
  67. package/dist-server/server/modules/computer-use/semantics/bin/win32-arm64/CloudCLISemantics.exe +0 -0
  68. package/dist-server/server/modules/computer-use/semantics/bin/win32-x64/CloudCLISemantics.exe +0 -0
  69. package/dist-server/server/modules/computer-use/semantics/helpers/semantic-helper-process.js +106 -0
  70. package/dist-server/server/modules/computer-use/semantics/helpers/semantic-helper-process.js.map +1 -0
  71. package/dist-server/server/modules/computer-use/semantics/helpers/semantic-helper-resolver.js +78 -0
  72. package/dist-server/server/modules/computer-use/semantics/helpers/semantic-helper-resolver.js.map +1 -0
  73. package/dist-server/server/modules/computer-use/semantics/semantic-session-store.js +68 -0
  74. package/dist-server/server/modules/computer-use/semantics/semantic-session-store.js.map +1 -0
  75. package/dist-server/server/modules/computer-use/semantics/semantic-tool-dispatcher.js +16 -0
  76. package/dist-server/server/modules/computer-use/semantics/semantic-tool-dispatcher.js.map +1 -0
  77. package/dist-server/server/modules/computer-use/semantics/semantic-types.js +2 -0
  78. package/dist-server/server/modules/computer-use/semantics/semantic-types.js.map +1 -0
  79. package/dist-server/server/modules/database/index.js +1 -0
  80. package/dist-server/server/modules/database/index.js.map +1 -1
  81. package/dist-server/server/modules/database/migrations.js +23 -1
  82. package/dist-server/server/modules/database/migrations.js.map +1 -1
  83. package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js +100 -0
  84. package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js.map +1 -0
  85. package/dist-server/server/modules/database/repositories/notification-preferences.js +8 -0
  86. package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -1
  87. package/dist-server/server/modules/database/repositories/sessions.db.js +173 -17
  88. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  89. package/dist-server/server/modules/database/schema.js +26 -0
  90. package/dist-server/server/modules/database/schema.js.map +1 -1
  91. package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -0
  92. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +78 -0
  93. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -0
  94. package/dist-server/server/modules/database/{repositories → tests}/sessions.db.integration.test.js +10 -0
  95. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -0
  96. package/dist-server/server/modules/notifications/index.js +4 -0
  97. package/dist-server/server/modules/notifications/index.js.map +1 -0
  98. package/dist-server/server/modules/notifications/notifications.routes.js +115 -0
  99. package/dist-server/server/modules/notifications/notifications.routes.js.map +1 -0
  100. package/dist-server/server/modules/notifications/services/desktop-notification-clients.service.js +97 -0
  101. package/dist-server/server/modules/notifications/services/desktop-notification-clients.service.js.map +1 -0
  102. package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +229 -0
  103. package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -0
  104. package/dist-server/server/modules/notifications/websocket/desktop-notifications-websocket.service.js +79 -0
  105. package/dist-server/server/modules/notifications/websocket/desktop-notifications-websocket.service.js.map +1 -0
  106. package/dist-server/server/modules/projects/services/project-management.service.js +0 -4
  107. package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -1
  108. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +10 -38
  109. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
  110. package/dist-server/server/modules/providers/index.js +1 -0
  111. package/dist-server/server/modules/providers/index.js.map +1 -1
  112. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +24 -1
  113. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  114. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +9 -12
  115. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  116. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +7 -0
  117. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -1
  118. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +7 -3
  119. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  120. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +3 -9
  121. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  122. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +7 -0
  123. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -1
  124. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +13 -22
  125. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  126. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +7 -0
  127. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -1
  128. package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js +5 -8
  129. package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js.map +1 -1
  130. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +6 -6
  131. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -1
  132. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +7 -0
  133. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -1
  134. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +17 -3
  135. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
  136. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +9 -10
  137. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
  138. package/dist-server/server/modules/providers/provider.routes.js +123 -1
  139. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  140. package/dist-server/server/modules/providers/services/mcp.service.js +23 -0
  141. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -1
  142. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +65 -0
  143. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -0
  144. package/dist-server/server/modules/providers/services/provider-models.service.js +1 -1
  145. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  146. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +62 -23
  147. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  148. package/dist-server/server/modules/providers/services/sessions.service.js +62 -4
  149. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  150. package/dist-server/server/modules/providers/services/skills.service.js +11 -0
  151. package/dist-server/server/modules/providers/services/skills.service.js.map +1 -1
  152. package/dist-server/server/modules/providers/shared/skills/skills.provider.js +163 -1
  153. package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -1
  154. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +45 -0
  155. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
  156. package/dist-server/server/modules/providers/tests/skills.test.js +160 -0
  157. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  158. package/dist-server/server/modules/websocket/index.js +1 -0
  159. package/dist-server/server/modules/websocket/index.js.map +1 -1
  160. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +252 -0
  161. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -0
  162. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +105 -0
  163. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -0
  164. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +218 -156
  165. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  166. package/dist-server/server/modules/websocket/services/desktop-agent-websocket.service.js +39 -0
  167. package/dist-server/server/modules/websocket/services/desktop-agent-websocket.service.js.map +1 -0
  168. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +83 -31
  169. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  170. package/dist-server/server/modules/websocket/services/websocket-server.service.js +10 -0
  171. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -1
  172. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +216 -0
  173. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -0
  174. package/dist-server/server/openai-codex.js +24 -14
  175. package/dist-server/server/openai-codex.js.map +1 -1
  176. package/dist-server/server/opencode-cli.js +21 -8
  177. package/dist-server/server/opencode-cli.js.map +1 -1
  178. package/dist-server/server/opencode-cli.test.js +19 -1
  179. package/dist-server/server/opencode-cli.test.js.map +1 -1
  180. package/dist-server/server/routes/settings.js +1 -1
  181. package/dist-server/server/routes/settings.js.map +1 -1
  182. package/dist-server/server/services/notification-orchestrator.js +1 -176
  183. package/dist-server/server/services/notification-orchestrator.js.map +1 -1
  184. package/dist-server/server/services/tests/notification-orchestrator.test.js +64 -0
  185. package/dist-server/server/services/tests/notification-orchestrator.test.js.map +1 -0
  186. package/dist-server/server/shared/{claude-cli-path.test.js → tests/claude-cli-path.test.js} +1 -1
  187. package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -0
  188. package/dist-server/server/shared/tests/slice-tail-page.test.js +35 -0
  189. package/dist-server/server/shared/tests/slice-tail-page.test.js.map +1 -0
  190. package/dist-server/server/shared/utils.js +73 -1
  191. package/dist-server/server/shared/utils.js.map +1 -1
  192. package/dist-server/server/voice-proxy.js +226 -0
  193. package/dist-server/server/voice-proxy.js.map +1 -0
  194. package/electron/assets/logo-macos.icns +0 -0
  195. package/electron/assets/logo-macos.png +0 -0
  196. package/electron/assets/logo-windows.ico +0 -0
  197. package/electron/cloud.js +260 -0
  198. package/electron/computerAgent.js +290 -0
  199. package/electron/desktopNotifications.js +378 -0
  200. package/electron/desktopWindow.js +781 -0
  201. package/electron/launcher/index.html +14 -0
  202. package/electron/launcher/launcher.css +801 -0
  203. package/electron/launcher/launcher.js +829 -0
  204. package/electron/localServer.js +550 -0
  205. package/electron/main.js +1060 -0
  206. package/electron/preload.cjs +63 -0
  207. package/electron/scripts/generate-macos-icon.js +62 -0
  208. package/electron/serverInstaller.js +277 -0
  209. package/electron/tabs.js +87 -0
  210. package/electron/viewHost.js +331 -0
  211. package/package.json +86 -5
  212. package/public/api-docs.html +36 -18
  213. package/scripts/build-computer-semantics.mjs +133 -0
  214. package/scripts/copy-computer-semantics-bin.mjs +24 -0
  215. package/scripts/release/build-server-bundle.js +176 -0
  216. package/scripts/release/prepare-desktop-app.js +158 -0
  217. package/server/browser-use-mcp.ts +384 -0
  218. package/server/claude-sdk.js +27 -5
  219. package/server/cli.js +15 -6
  220. package/server/computer-use-agent.ts +279 -0
  221. package/server/computer-use-mcp.ts +574 -0
  222. package/server/cursor-cli.js +27 -11
  223. package/server/gemini-cli.js +17 -2
  224. package/server/index.js +151 -47
  225. package/server/load-env.js +1 -1
  226. package/server/modules/browser-use/browser-use-mcp.routes.ts +120 -0
  227. package/server/modules/browser-use/browser-use.routes.ts +96 -0
  228. package/server/modules/browser-use/browser-use.service.ts +836 -0
  229. package/server/modules/browser-use/tests/browser-use.service.test.ts +10 -0
  230. package/server/modules/computer-use/actions/raw-action-dispatcher.ts +67 -0
  231. package/server/modules/computer-use/actions/raw-action-types.ts +28 -0
  232. package/server/modules/computer-use/computer-executor.ts +242 -0
  233. package/server/modules/computer-use/computer-semantics.service.ts +460 -0
  234. package/server/modules/computer-use/computer-use-mcp.routes.ts +141 -0
  235. package/server/modules/computer-use/computer-use.routes.ts +211 -0
  236. package/server/modules/computer-use/computer-use.service.ts +920 -0
  237. package/server/modules/computer-use/desktop-agent-relay.service.ts +158 -0
  238. package/server/modules/computer-use/index.ts +2 -0
  239. package/server/modules/computer-use/semantics/adapters/helper-semantic-adapter.ts +82 -0
  240. package/server/modules/computer-use/semantics/adapters/macos/macos-semantic-adapter.ts +5 -0
  241. package/server/modules/computer-use/semantics/adapters/semantic-adapter.ts +23 -0
  242. package/server/modules/computer-use/semantics/adapters/windows/windows-semantic-adapter.ts +5 -0
  243. package/server/modules/computer-use/semantics/bin/darwin-arm64/CloudCLISemantics +0 -0
  244. package/server/modules/computer-use/semantics/bin/darwin-x64/CloudCLISemantics +0 -0
  245. package/server/modules/computer-use/semantics/bin/win32-arm64/CloudCLISemantics.exe +0 -0
  246. package/server/modules/computer-use/semantics/bin/win32-x64/CloudCLISemantics.exe +0 -0
  247. package/server/modules/computer-use/semantics/helpers/macos/CloudCLISemantics.swift +467 -0
  248. package/server/modules/computer-use/semantics/helpers/semantic-helper-process.ts +124 -0
  249. package/server/modules/computer-use/semantics/helpers/semantic-helper-resolver.ts +97 -0
  250. package/server/modules/computer-use/semantics/helpers/windows/CloudCLISemantics.csproj +11 -0
  251. package/server/modules/computer-use/semantics/helpers/windows/Program.cs +534 -0
  252. package/server/modules/computer-use/semantics/semantic-session-store.ts +87 -0
  253. package/server/modules/computer-use/semantics/semantic-tool-dispatcher.ts +17 -0
  254. package/server/modules/computer-use/semantics/semantic-types.ts +58 -0
  255. package/server/modules/database/index.ts +1 -0
  256. package/server/modules/database/migrations.ts +25 -0
  257. package/server/modules/database/repositories/notification-channel-endpoints.ts +153 -0
  258. package/server/modules/database/repositories/notification-preferences.ts +12 -1
  259. package/server/modules/database/repositories/sessions.db.ts +227 -23
  260. package/server/modules/database/schema.ts +27 -0
  261. package/server/modules/database/tests/sessions-provider-mapping.test.ts +108 -0
  262. package/server/modules/database/{repositories → tests}/sessions.db.integration.test.ts +12 -0
  263. package/server/modules/notifications/index.ts +13 -0
  264. package/server/modules/notifications/notifications.routes.ts +127 -0
  265. package/server/modules/notifications/services/desktop-notification-clients.service.ts +124 -0
  266. package/server/modules/notifications/services/notification-orchestrator.service.js +288 -0
  267. package/server/modules/notifications/websocket/desktop-notifications-websocket.service.ts +109 -0
  268. package/server/modules/projects/services/project-management.service.ts +0 -8
  269. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +12 -53
  270. package/server/modules/providers/README.md +1 -1
  271. package/server/modules/providers/index.ts +1 -0
  272. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +26 -1
  273. package/server/modules/providers/list/claude/claude-sessions.provider.ts +9 -14
  274. package/server/modules/providers/list/claude/claude-skills.provider.ts +8 -0
  275. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +7 -3
  276. package/server/modules/providers/list/codex/codex-sessions.provider.ts +3 -12
  277. package/server/modules/providers/list/codex/codex-skills.provider.ts +8 -0
  278. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +13 -22
  279. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +8 -0
  280. package/server/modules/providers/list/gemini/gemini-models.provider.ts +5 -8
  281. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +6 -6
  282. package/server/modules/providers/list/gemini/gemini-skills.provider.ts +8 -0
  283. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +18 -4
  284. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +9 -12
  285. package/server/modules/providers/provider.routes.ts +167 -1
  286. package/server/modules/providers/services/mcp.service.ts +26 -0
  287. package/server/modules/providers/services/provider-capabilities.service.ts +91 -0
  288. package/server/modules/providers/services/provider-models.service.ts +1 -1
  289. package/server/modules/providers/services/sessions-watcher.service.ts +71 -25
  290. package/server/modules/providers/services/sessions.service.ts +79 -4
  291. package/server/modules/providers/services/skills.service.ts +25 -1
  292. package/server/modules/providers/shared/skills/skills.provider.ts +223 -0
  293. package/server/modules/providers/tests/opencode-sessions.test.ts +49 -0
  294. package/server/modules/providers/tests/skills.test.ts +212 -0
  295. package/server/modules/websocket/README.md +33 -27
  296. package/server/modules/websocket/index.ts +1 -0
  297. package/server/modules/websocket/services/chat-run-registry.service.ts +327 -0
  298. package/server/modules/websocket/services/chat-session-writer.service.ts +145 -0
  299. package/server/modules/websocket/services/chat-websocket.service.ts +292 -207
  300. package/server/modules/websocket/services/desktop-agent-websocket.service.ts +51 -0
  301. package/server/modules/websocket/services/shell-websocket.service.ts +108 -32
  302. package/server/modules/websocket/services/websocket-server.service.ts +12 -0
  303. package/server/modules/websocket/tests/chat-run-registry.test.ts +244 -0
  304. package/server/openai-codex.js +24 -14
  305. package/server/opencode-cli.js +21 -8
  306. package/server/opencode-cli.test.js +20 -1
  307. package/server/routes/settings.js +6 -1
  308. package/server/services/notification-orchestrator.js +3 -224
  309. package/server/services/tests/notification-orchestrator.test.js +80 -0
  310. package/server/shared/interfaces.ts +15 -0
  311. package/server/shared/tests/slice-tail-page.test.ts +42 -0
  312. package/server/shared/types.ts +84 -1
  313. package/server/shared/utils.ts +95 -1
  314. package/server/voice-proxy.js +224 -0
  315. package/dist/assets/index-73Xw3i9v.css +0 -32
  316. package/dist/assets/index-BIHaviaA.js +0 -1361
  317. package/dist/modelConstants.js +0 -854
  318. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +0 -1
  319. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +0 -1
  320. package/dist-server/server/shared/claude-cli-path.test.js.map +0 -1
  321. package/public/modelConstants.js +0 -854
  322. /package/dist-server/server/modules/database/{repositories → tests}/projects.db.integration.test.js +0 -0
  323. /package/server/modules/database/{repositories → tests}/projects.db.integration.test.ts +0 -0
  324. /package/server/shared/{claude-cli-path.test.ts → tests/claude-cli-path.test.ts} +0 -0
@@ -0,0 +1,260 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { safeStorage } from 'electron';
5
+
6
+ const CLOUD_API_TIMEOUT_MS = 15000;
7
+
8
+ function encryptSecret(secret) {
9
+ if (!safeStorage.isEncryptionAvailable()) {
10
+ return { encrypted: false, value: secret };
11
+ }
12
+
13
+ return {
14
+ encrypted: true,
15
+ value: safeStorage.encryptString(secret).toString('base64'),
16
+ };
17
+ }
18
+
19
+ function decryptSecret(record) {
20
+ if (!record?.value) return null;
21
+ if (!record.encrypted) return record.value;
22
+ try {
23
+ return safeStorage.decryptString(Buffer.from(record.value, 'base64'));
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ export class CloudController {
30
+ constructor({ storePath, controlPlaneUrl, callbackUrl, onChange }) {
31
+ this.storePath = storePath;
32
+ this.controlPlaneUrl = controlPlaneUrl;
33
+ this.callbackUrl = callbackUrl;
34
+ this.onChange = onChange;
35
+ this.cloudAccount = null;
36
+ this.cloudEnvironments = [];
37
+ this.authState = 'logged_out';
38
+ }
39
+
40
+ getAccount() {
41
+ return this.cloudAccount;
42
+ }
43
+
44
+ getAuthState() {
45
+ return this.authState;
46
+ }
47
+
48
+ getEnvironments() {
49
+ return this.cloudEnvironments;
50
+ }
51
+
52
+ getEnvironmentUrl(environment) {
53
+ return environment.access_url || `https://${environment.subdomain}.cloudcli.ai`;
54
+ }
55
+
56
+ async getEnvironmentLaunchUrl(environment) {
57
+ if (!environment?.id) {
58
+ return this.getEnvironmentUrl(environment);
59
+ }
60
+
61
+ const data = await this.cloudApi(`/api/v1/environments/${encodeURIComponent(environment.id)}/launch`, {
62
+ method: 'POST',
63
+ });
64
+
65
+ return data.launch_url || data.environment_url || this.getEnvironmentUrl(environment);
66
+ }
67
+
68
+ findEnvironment(environmentId) {
69
+ return this.cloudEnvironments.find((item) => item.id === environmentId) || null;
70
+ }
71
+
72
+ async loadCloudAccount() {
73
+ try {
74
+ const raw = await fs.readFile(this.storePath, 'utf8');
75
+ const stored = JSON.parse(raw);
76
+ const apiKey = decryptSecret(stored.apiKey);
77
+ this.cloudAccount = {
78
+ deviceId: stored.deviceId || crypto.randomUUID(),
79
+ email: stored.email || null,
80
+ apiKey: apiKey || null,
81
+ };
82
+ this.authState = apiKey ? 'connected' : (stored.email ? 'expired' : 'logged_out');
83
+ return this.cloudAccount;
84
+ } catch {
85
+ this.cloudAccount = {
86
+ deviceId: crypto.randomUUID(),
87
+ email: null,
88
+ apiKey: null,
89
+ };
90
+ this.authState = 'logged_out';
91
+ return this.cloudAccount;
92
+ }
93
+ }
94
+
95
+ async saveCloudAccount(account) {
96
+ const payload = {
97
+ deviceId: account.deviceId || crypto.randomUUID(),
98
+ email: account.email || null,
99
+ apiKey: account.apiKey ? encryptSecret(account.apiKey) : null,
100
+ };
101
+
102
+ await fs.mkdir(path.dirname(this.storePath), { recursive: true });
103
+ await fs.writeFile(this.storePath, JSON.stringify(payload, null, 2), 'utf8');
104
+ this.cloudAccount = {
105
+ deviceId: payload.deviceId,
106
+ email: payload.email,
107
+ apiKey: account.apiKey || null,
108
+ };
109
+ this.authState = account.apiKey ? 'connected' : 'logged_out';
110
+ this.onChange?.();
111
+ return this.cloudAccount;
112
+ }
113
+
114
+ async clearCloudAccount() {
115
+ this.cloudAccount = {
116
+ deviceId: crypto.randomUUID(),
117
+ email: null,
118
+ apiKey: null,
119
+ };
120
+ this.cloudEnvironments = [];
121
+ this.authState = 'logged_out';
122
+ await fs.rm(this.storePath, { force: true });
123
+ this.onChange?.();
124
+ }
125
+
126
+ async invalidateCloudAccount() {
127
+ this.cloudEnvironments = [];
128
+ if (!this.cloudAccount) {
129
+ this.cloudAccount = {
130
+ deviceId: crypto.randomUUID(),
131
+ email: null,
132
+ apiKey: null,
133
+ };
134
+ } else {
135
+ this.cloudAccount = {
136
+ ...this.cloudAccount,
137
+ apiKey: null,
138
+ };
139
+ }
140
+ this.authState = this.cloudAccount.email ? 'expired' : 'logged_out';
141
+ const payload = {
142
+ deviceId: this.cloudAccount.deviceId,
143
+ email: this.cloudAccount.email || null,
144
+ apiKey: null,
145
+ };
146
+ await fs.mkdir(path.dirname(this.storePath), { recursive: true });
147
+ await fs.writeFile(this.storePath, JSON.stringify(payload, null, 2), 'utf8');
148
+ this.onChange?.();
149
+ }
150
+
151
+ async cloudApi(pathname, options = {}) {
152
+ if (!this.cloudAccount?.apiKey) {
153
+ throw new Error('Connect your CloudCLI account first.');
154
+ }
155
+
156
+ const controller = new AbortController();
157
+ const timeout = setTimeout(() => controller.abort(), CLOUD_API_TIMEOUT_MS);
158
+ let response;
159
+
160
+ try {
161
+ response = await fetch(`${this.controlPlaneUrl}${pathname}`, {
162
+ ...options,
163
+ signal: options.signal || controller.signal,
164
+ headers: {
165
+ 'Content-Type': 'application/json',
166
+ 'X-API-Key': this.cloudAccount.apiKey,
167
+ ...(options.headers || {}),
168
+ },
169
+ });
170
+ } catch (error) {
171
+ if (error?.name === 'AbortError') {
172
+ throw new Error(`CloudCLI API request timed out after ${Math.round(CLOUD_API_TIMEOUT_MS / 1000)} seconds.`);
173
+ }
174
+ throw error;
175
+ } finally {
176
+ clearTimeout(timeout);
177
+ }
178
+
179
+ const body = await response.json().catch(() => ({}));
180
+ if (!response.ok) {
181
+ if (response.status === 401 || response.status === 403) {
182
+ await this.invalidateCloudAccount();
183
+ }
184
+ throw new Error(body.error || `CloudCLI API request failed: ${response.status}`);
185
+ }
186
+
187
+ return body;
188
+ }
189
+
190
+ async refreshCloudEnvironments() {
191
+ if (!this.cloudAccount?.apiKey) {
192
+ this.cloudEnvironments = [];
193
+ this.onChange?.();
194
+ return [];
195
+ }
196
+
197
+ const data = await this.cloudApi('/api/v1/environments');
198
+ this.cloudEnvironments = data.environments || [];
199
+ this.onChange?.();
200
+ return this.cloudEnvironments;
201
+ }
202
+
203
+ async startEnvironment(environment) {
204
+ await this.cloudApi(`/api/v1/environments/${encodeURIComponent(environment.id)}/start`, {
205
+ method: 'POST',
206
+ });
207
+ }
208
+
209
+ async stopEnvironment(environment) {
210
+ await this.cloudApi(`/api/v1/environments/${encodeURIComponent(environment.id)}/stop`, {
211
+ method: 'POST',
212
+ });
213
+ }
214
+
215
+ async getEnvironmentCredentials(environment) {
216
+ return this.cloudApi(`/api/v1/environments/${encodeURIComponent(environment.id)}/credentials`);
217
+ }
218
+
219
+ async startEnvironmentAndWait(environment, timeoutMs) {
220
+ await this.startEnvironment(environment);
221
+
222
+ const startedAt = Date.now();
223
+ while (Date.now() - startedAt < timeoutMs) {
224
+ const environments = await this.refreshCloudEnvironments();
225
+ const current = environments.find((env) => env.id === environment.id);
226
+ if (current?.status === 'running') {
227
+ return current;
228
+ }
229
+ await new Promise((resolve) => setTimeout(resolve, 2000));
230
+ }
231
+
232
+ throw new Error(`${environment.name} did not become ready in time.`);
233
+ }
234
+
235
+ buildConnectUrl() {
236
+ if (!this.cloudAccount?.deviceId) {
237
+ this.cloudAccount = {
238
+ deviceId: crypto.randomUUID(),
239
+ email: null,
240
+ apiKey: null,
241
+ };
242
+ }
243
+
244
+ const connectUrl = new URL('/auth/app-connect', this.controlPlaneUrl);
245
+ connectUrl.searchParams.set('device_id', this.cloudAccount.deviceId);
246
+ connectUrl.searchParams.set('callback_url', this.callbackUrl);
247
+ connectUrl.searchParams.set('app_surface', 'cloudcli_desktop');
248
+ connectUrl.searchParams.set('client_platform', 'desktop');
249
+ return connectUrl.toString();
250
+ }
251
+
252
+ async saveFromCallback({ apiKey, email }) {
253
+ await this.saveCloudAccount({
254
+ deviceId: this.cloudAccount?.deviceId || crypto.randomUUID(),
255
+ email,
256
+ apiKey,
257
+ });
258
+ return this.cloudAccount;
259
+ }
260
+ }
@@ -0,0 +1,290 @@
1
+ import { spawn } from 'node:child_process';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+
5
+ const IPC_PREFIX = '@@CUAGENT@@';
6
+ const TARGET_STATUS_TIMEOUT_MS = 5000;
7
+
8
+ function getDesktopPath() {
9
+ const currentPath = process.env.PATH || '';
10
+ const commonPaths = process.platform === 'win32'
11
+ ? []
12
+ : ['/opt/homebrew/bin', '/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin'];
13
+ return [...commonPaths, currentPath].filter(Boolean).join(path.delimiter);
14
+ }
15
+
16
+ function getNodeRuntime(isPackaged) {
17
+ if (isPackaged && process.versions.electron) {
18
+ return { command: process.execPath, env: { ELECTRON_RUN_AS_NODE: '1' } };
19
+ }
20
+ if (process.env.npm_node_execpath) {
21
+ return { command: process.env.npm_node_execpath, env: {} };
22
+ }
23
+ return { command: 'node', env: {} };
24
+ }
25
+
26
+ function toAgentWsUrl(httpUrl) {
27
+ try {
28
+ const parsed = new URL(httpUrl);
29
+ parsed.protocol = parsed.protocol === 'http:' ? 'ws:' : 'wss:';
30
+ parsed.pathname = '/desktop-agent';
31
+ parsed.search = '';
32
+ parsed.hash = '';
33
+ return parsed.toString();
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ async function isComputerUseEnabledTarget(httpUrl, apiKey) {
40
+ let statusUrl;
41
+ try {
42
+ statusUrl = new URL('/api/computer-use/status', httpUrl).toString();
43
+ } catch {
44
+ return false;
45
+ }
46
+
47
+ const controller = new AbortController();
48
+ const timeout = setTimeout(() => controller.abort(), TARGET_STATUS_TIMEOUT_MS);
49
+ try {
50
+ const response = await fetch(statusUrl, {
51
+ signal: controller.signal,
52
+ headers: apiKey ? { 'X-API-Key': apiKey } : undefined,
53
+ });
54
+ const body = await response.json().catch(() => null);
55
+ return response.ok && body?.success !== false && body?.data?.enabled === true;
56
+ } catch {
57
+ return false;
58
+ } finally {
59
+ clearTimeout(timeout);
60
+ }
61
+ }
62
+
63
+ async function filterEnabledComputerUseTargets(targets, apiKey) {
64
+ const checks = await Promise.all(targets.map(async (target) => ({
65
+ target,
66
+ enabled: await isComputerUseEnabledTarget(target, apiKey),
67
+ })));
68
+ return checks.filter((item) => item.enabled).map((item) => item.target);
69
+ }
70
+
71
+ /**
72
+ * Keeps a Computer Use desktop agent connected to running cloud environments
73
+ * while desktop access is enabled.
74
+ */
75
+ export class ComputerAgentController {
76
+ constructor({ appRoot, settingsPath, isPackaged = false, getRunningEnvironmentUrls, getApiKey, promptConsent, onChange }) {
77
+ this.appRoot = appRoot;
78
+ this.settingsPath = settingsPath;
79
+ this.isPackaged = isPackaged;
80
+ this.getRunningEnvironmentUrls = getRunningEnvironmentUrls;
81
+ this.getApiKey = getApiKey;
82
+ this.promptConsent = promptConsent;
83
+ this.onChange = onChange;
84
+ this.settings = { enabled: false, consentMode: 'ask' };
85
+ this.child = null;
86
+ this.connectedUrls = new Set();
87
+ this.currentTargets = [];
88
+ this.stdoutBuffer = '';
89
+ this.lastEvent = null;
90
+ this.lastError = null;
91
+ }
92
+
93
+ getSettings() {
94
+ return { ...this.settings };
95
+ }
96
+
97
+ getState() {
98
+ return {
99
+ enabled: this.settings.enabled,
100
+ consentMode: this.settings.consentMode,
101
+ running: Boolean(this.child),
102
+ connectedCount: this.connectedUrls.size,
103
+ targetCount: this.currentTargets.length,
104
+ targetUrls: [...this.currentTargets],
105
+ lastEvent: this.lastEvent,
106
+ lastError: this.lastError,
107
+ };
108
+ }
109
+
110
+ async loadSettings() {
111
+ try {
112
+ const raw = await fs.readFile(this.settingsPath, 'utf8');
113
+ const stored = JSON.parse(raw);
114
+ this.settings = {
115
+ enabled: Boolean(stored.enabled),
116
+ consentMode: stored.consentMode === 'auto' ? 'auto' : 'ask',
117
+ };
118
+ } catch {
119
+ this.settings = { enabled: false, consentMode: 'ask' };
120
+ }
121
+ return this.settings;
122
+ }
123
+
124
+ async saveSettings(next) {
125
+ this.settings = {
126
+ enabled: Boolean(next.enabled),
127
+ consentMode: next.consentMode === 'auto' ? 'auto' : 'ask',
128
+ };
129
+ await fs.mkdir(path.dirname(this.settingsPath), { recursive: true });
130
+ await fs.writeFile(this.settingsPath, JSON.stringify(this.settings, null, 2), 'utf8');
131
+ await this.sync();
132
+ this.onChange?.();
133
+ return this.settings;
134
+ }
135
+
136
+ async sync() {
137
+ const targets = this.settings.enabled ? (this.getRunningEnvironmentUrls?.() || []) : [];
138
+ const enabledTargets = this.settings.enabled ? await filterEnabledComputerUseTargets(targets, this.getApiKey?.() || '') : [];
139
+ const wsTargets = enabledTargets.map(toAgentWsUrl).filter(Boolean);
140
+
141
+ const sameTargets =
142
+ wsTargets.length === this.currentTargets.length &&
143
+ wsTargets.every((url) => this.currentTargets.includes(url));
144
+
145
+ if (!this.settings.enabled || wsTargets.length === 0) {
146
+ this.stop();
147
+ this.currentTargets = [];
148
+ this.lastEvent = this.settings.enabled ? 'no-targets' : 'disabled';
149
+ return;
150
+ }
151
+
152
+ if (this.child && sameTargets) {
153
+ return;
154
+ }
155
+
156
+ this.currentTargets = wsTargets;
157
+ this.lastEvent = 'restarting';
158
+ this.lastError = null;
159
+ this.restart(wsTargets);
160
+ }
161
+
162
+ restart(wsTargets) {
163
+ this.stop();
164
+
165
+ const agentEntry = process.env.CLOUDCLI_COMPUTER_AGENT_ENTRY
166
+ || path.join(this.appRoot, 'dist-server', 'server', 'computer-use-agent.js');
167
+ const runtime = getNodeRuntime(this.isPackaged);
168
+
169
+ this.child = spawn(runtime.command, [agentEntry], {
170
+ cwd: this.appRoot,
171
+ env: {
172
+ ...process.env,
173
+ ...runtime.env,
174
+ PATH: getDesktopPath(),
175
+ CLOUDCLI_DESKTOP_AGENT_URLS: wsTargets.join(','),
176
+ CLOUDCLI_DESKTOP_AGENT_API_KEY: this.getApiKey?.() || '',
177
+ CLOUDCLI_COMPUTER_USE_CONSENT_MODE: this.settings.consentMode,
178
+ },
179
+ stdio: ['pipe', 'pipe', 'pipe'],
180
+ windowsHide: true,
181
+ });
182
+
183
+ this.connectedUrls = new Set();
184
+
185
+ this.child.once('error', (error) => {
186
+ console.error('[ComputerAgent] failed to start:', error.message);
187
+ this.lastEvent = 'start-error';
188
+ this.lastError = error.message;
189
+ this.child = null;
190
+ this.onChange?.();
191
+ });
192
+
193
+ this.child.stdout?.on('data', (chunk) => this.handleStdout(String(chunk)));
194
+ this.child.stderr?.on('data', (chunk) => {
195
+ for (const line of String(chunk).split(/\r?\n/)) {
196
+ if (line.trim()) {
197
+ this.lastError = line.trim();
198
+ console.error('[ComputerAgent]', line);
199
+ }
200
+ }
201
+ });
202
+
203
+ this.child.once('exit', (code) => {
204
+ console.log(`[ComputerAgent] exited (code ${code ?? 'null'})`);
205
+ this.lastEvent = `exit:${code ?? 'null'}`;
206
+ this.child = null;
207
+ this.connectedUrls = new Set();
208
+ this.onChange?.();
209
+ });
210
+
211
+ this.onChange?.();
212
+ }
213
+
214
+ handleStdout(chunk) {
215
+ this.stdoutBuffer += chunk;
216
+ const lines = this.stdoutBuffer.split('\n');
217
+ this.stdoutBuffer = lines.pop() || '';
218
+ for (const line of lines) {
219
+ const trimmed = line.trim();
220
+ if (!trimmed.startsWith(IPC_PREFIX)) {
221
+ if (trimmed) console.log('[ComputerAgent]', trimmed);
222
+ continue;
223
+ }
224
+ let payload;
225
+ try {
226
+ payload = JSON.parse(trimmed.slice(IPC_PREFIX.length).trim());
227
+ } catch {
228
+ continue;
229
+ }
230
+ void this.handleAgentEvent(payload);
231
+ }
232
+ }
233
+
234
+ async handleAgentEvent(payload) {
235
+ switch (payload.type) {
236
+ case 'connected':
237
+ this.connectedUrls.add(payload.url);
238
+ this.lastEvent = 'connected';
239
+ this.lastError = null;
240
+ this.onChange?.();
241
+ break;
242
+ case 'disconnected':
243
+ this.connectedUrls.delete(payload.url);
244
+ this.lastEvent = 'disconnected';
245
+ this.onChange?.();
246
+ if (payload.reason && /computer use.*disabled/i.test(payload.reason)) {
247
+ void this.sync().catch((error) => {
248
+ this.lastError = error instanceof Error ? error.message : 'Failed to sync Computer Use targets.';
249
+ this.onChange?.();
250
+ });
251
+ }
252
+ break;
253
+ case 'starting':
254
+ this.lastEvent = 'starting';
255
+ this.lastError = null;
256
+ this.onChange?.();
257
+ break;
258
+ case 'error':
259
+ this.lastEvent = 'error';
260
+ this.lastError = payload.message || 'Computer agent error.';
261
+ this.onChange?.();
262
+ break;
263
+ case 'consent-request': {
264
+ const allow = await this.promptConsent?.(payload.sessionId);
265
+ this.sendToChild({ type: 'consent-response', sessionId: payload.sessionId, allow: Boolean(allow) });
266
+ break;
267
+ }
268
+ default:
269
+ break;
270
+ }
271
+ }
272
+
273
+ sendToChild(message) {
274
+ if (this.child?.stdin?.writable) {
275
+ this.child.stdin.write(`${IPC_PREFIX} ${JSON.stringify(message)}\n`);
276
+ }
277
+ }
278
+
279
+ revokeSession(sessionId) {
280
+ this.sendToChild({ type: 'revoke-session', sessionId });
281
+ }
282
+
283
+ stop() {
284
+ if (!this.child) return;
285
+ const child = this.child;
286
+ this.child = null;
287
+ this.connectedUrls = new Set();
288
+ try { child.kill('SIGTERM'); } catch { /* noop */ }
289
+ }
290
+ }