@cloudcli-ai/cloudcli 1.33.3 → 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 (329) 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 +26 -6
  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-models.provider.js +5 -0
  113. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  114. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +24 -1
  115. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  116. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +9 -12
  117. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  118. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +7 -0
  119. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -1
  120. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +7 -3
  121. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  122. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +3 -9
  123. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  124. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +7 -0
  125. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -1
  126. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +13 -22
  127. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  128. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +7 -0
  129. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -1
  130. package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js +5 -8
  131. package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js.map +1 -1
  132. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +6 -6
  133. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -1
  134. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +7 -0
  135. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -1
  136. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +17 -3
  137. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
  138. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +9 -10
  139. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
  140. package/dist-server/server/modules/providers/provider.routes.js +123 -1
  141. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  142. package/dist-server/server/modules/providers/services/mcp.service.js +23 -0
  143. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -1
  144. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +65 -0
  145. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -0
  146. package/dist-server/server/modules/providers/services/provider-models.service.js +1 -1
  147. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  148. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +62 -23
  149. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  150. package/dist-server/server/modules/providers/services/sessions.service.js +62 -4
  151. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  152. package/dist-server/server/modules/providers/services/skills.service.js +11 -0
  153. package/dist-server/server/modules/providers/services/skills.service.js.map +1 -1
  154. package/dist-server/server/modules/providers/shared/skills/skills.provider.js +163 -1
  155. package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -1
  156. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +45 -0
  157. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
  158. package/dist-server/server/modules/providers/tests/skills.test.js +160 -0
  159. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  160. package/dist-server/server/modules/websocket/index.js +1 -0
  161. package/dist-server/server/modules/websocket/index.js.map +1 -1
  162. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +252 -0
  163. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -0
  164. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +105 -0
  165. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -0
  166. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +218 -156
  167. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  168. package/dist-server/server/modules/websocket/services/desktop-agent-websocket.service.js +39 -0
  169. package/dist-server/server/modules/websocket/services/desktop-agent-websocket.service.js.map +1 -0
  170. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +83 -31
  171. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  172. package/dist-server/server/modules/websocket/services/websocket-server.service.js +10 -0
  173. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -1
  174. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +216 -0
  175. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -0
  176. package/dist-server/server/openai-codex.js +24 -14
  177. package/dist-server/server/openai-codex.js.map +1 -1
  178. package/dist-server/server/opencode-cli.js +21 -8
  179. package/dist-server/server/opencode-cli.js.map +1 -1
  180. package/dist-server/server/opencode-cli.test.js +19 -1
  181. package/dist-server/server/opencode-cli.test.js.map +1 -1
  182. package/dist-server/server/routes/agent.js +1 -1
  183. package/dist-server/server/routes/settings.js +1 -1
  184. package/dist-server/server/routes/settings.js.map +1 -1
  185. package/dist-server/server/services/notification-orchestrator.js +1 -176
  186. package/dist-server/server/services/notification-orchestrator.js.map +1 -1
  187. package/dist-server/server/services/tests/notification-orchestrator.test.js +64 -0
  188. package/dist-server/server/services/tests/notification-orchestrator.test.js.map +1 -0
  189. package/dist-server/server/shared/{claude-cli-path.test.js → tests/claude-cli-path.test.js} +1 -1
  190. package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -0
  191. package/dist-server/server/shared/tests/slice-tail-page.test.js +35 -0
  192. package/dist-server/server/shared/tests/slice-tail-page.test.js.map +1 -0
  193. package/dist-server/server/shared/utils.js +73 -1
  194. package/dist-server/server/shared/utils.js.map +1 -1
  195. package/dist-server/server/voice-proxy.js +226 -0
  196. package/dist-server/server/voice-proxy.js.map +1 -0
  197. package/electron/assets/logo-macos.icns +0 -0
  198. package/electron/assets/logo-macos.png +0 -0
  199. package/electron/assets/logo-windows.ico +0 -0
  200. package/electron/cloud.js +260 -0
  201. package/electron/computerAgent.js +290 -0
  202. package/electron/desktopNotifications.js +378 -0
  203. package/electron/desktopWindow.js +781 -0
  204. package/electron/launcher/index.html +14 -0
  205. package/electron/launcher/launcher.css +801 -0
  206. package/electron/launcher/launcher.js +829 -0
  207. package/electron/localServer.js +550 -0
  208. package/electron/main.js +1060 -0
  209. package/electron/preload.cjs +63 -0
  210. package/electron/scripts/generate-macos-icon.js +62 -0
  211. package/electron/serverInstaller.js +277 -0
  212. package/electron/tabs.js +87 -0
  213. package/electron/viewHost.js +331 -0
  214. package/package.json +86 -5
  215. package/public/api-docs.html +36 -18
  216. package/scripts/build-computer-semantics.mjs +133 -0
  217. package/scripts/copy-computer-semantics-bin.mjs +24 -0
  218. package/scripts/release/build-server-bundle.js +176 -0
  219. package/scripts/release/prepare-desktop-app.js +158 -0
  220. package/server/browser-use-mcp.ts +384 -0
  221. package/server/claude-sdk.js +28 -6
  222. package/server/cli.js +15 -6
  223. package/server/computer-use-agent.ts +279 -0
  224. package/server/computer-use-mcp.ts +574 -0
  225. package/server/cursor-cli.js +27 -11
  226. package/server/gemini-cli.js +17 -2
  227. package/server/index.js +151 -47
  228. package/server/load-env.js +1 -1
  229. package/server/modules/browser-use/browser-use-mcp.routes.ts +120 -0
  230. package/server/modules/browser-use/browser-use.routes.ts +96 -0
  231. package/server/modules/browser-use/browser-use.service.ts +836 -0
  232. package/server/modules/browser-use/tests/browser-use.service.test.ts +10 -0
  233. package/server/modules/computer-use/actions/raw-action-dispatcher.ts +67 -0
  234. package/server/modules/computer-use/actions/raw-action-types.ts +28 -0
  235. package/server/modules/computer-use/computer-executor.ts +242 -0
  236. package/server/modules/computer-use/computer-semantics.service.ts +460 -0
  237. package/server/modules/computer-use/computer-use-mcp.routes.ts +141 -0
  238. package/server/modules/computer-use/computer-use.routes.ts +211 -0
  239. package/server/modules/computer-use/computer-use.service.ts +920 -0
  240. package/server/modules/computer-use/desktop-agent-relay.service.ts +158 -0
  241. package/server/modules/computer-use/index.ts +2 -0
  242. package/server/modules/computer-use/semantics/adapters/helper-semantic-adapter.ts +82 -0
  243. package/server/modules/computer-use/semantics/adapters/macos/macos-semantic-adapter.ts +5 -0
  244. package/server/modules/computer-use/semantics/adapters/semantic-adapter.ts +23 -0
  245. package/server/modules/computer-use/semantics/adapters/windows/windows-semantic-adapter.ts +5 -0
  246. package/server/modules/computer-use/semantics/bin/darwin-arm64/CloudCLISemantics +0 -0
  247. package/server/modules/computer-use/semantics/bin/darwin-x64/CloudCLISemantics +0 -0
  248. package/server/modules/computer-use/semantics/bin/win32-arm64/CloudCLISemantics.exe +0 -0
  249. package/server/modules/computer-use/semantics/bin/win32-x64/CloudCLISemantics.exe +0 -0
  250. package/server/modules/computer-use/semantics/helpers/macos/CloudCLISemantics.swift +467 -0
  251. package/server/modules/computer-use/semantics/helpers/semantic-helper-process.ts +124 -0
  252. package/server/modules/computer-use/semantics/helpers/semantic-helper-resolver.ts +97 -0
  253. package/server/modules/computer-use/semantics/helpers/windows/CloudCLISemantics.csproj +11 -0
  254. package/server/modules/computer-use/semantics/helpers/windows/Program.cs +534 -0
  255. package/server/modules/computer-use/semantics/semantic-session-store.ts +87 -0
  256. package/server/modules/computer-use/semantics/semantic-tool-dispatcher.ts +17 -0
  257. package/server/modules/computer-use/semantics/semantic-types.ts +58 -0
  258. package/server/modules/database/index.ts +1 -0
  259. package/server/modules/database/migrations.ts +25 -0
  260. package/server/modules/database/repositories/notification-channel-endpoints.ts +153 -0
  261. package/server/modules/database/repositories/notification-preferences.ts +12 -1
  262. package/server/modules/database/repositories/sessions.db.ts +227 -23
  263. package/server/modules/database/schema.ts +27 -0
  264. package/server/modules/database/tests/sessions-provider-mapping.test.ts +108 -0
  265. package/server/modules/database/{repositories → tests}/sessions.db.integration.test.ts +12 -0
  266. package/server/modules/notifications/index.ts +13 -0
  267. package/server/modules/notifications/notifications.routes.ts +127 -0
  268. package/server/modules/notifications/services/desktop-notification-clients.service.ts +124 -0
  269. package/server/modules/notifications/services/notification-orchestrator.service.js +288 -0
  270. package/server/modules/notifications/websocket/desktop-notifications-websocket.service.ts +109 -0
  271. package/server/modules/projects/services/project-management.service.ts +0 -8
  272. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +12 -53
  273. package/server/modules/providers/README.md +1 -1
  274. package/server/modules/providers/index.ts +1 -0
  275. package/server/modules/providers/list/claude/claude-models.provider.ts +5 -0
  276. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +26 -1
  277. package/server/modules/providers/list/claude/claude-sessions.provider.ts +9 -14
  278. package/server/modules/providers/list/claude/claude-skills.provider.ts +8 -0
  279. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +7 -3
  280. package/server/modules/providers/list/codex/codex-sessions.provider.ts +3 -12
  281. package/server/modules/providers/list/codex/codex-skills.provider.ts +8 -0
  282. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +13 -22
  283. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +8 -0
  284. package/server/modules/providers/list/gemini/gemini-models.provider.ts +5 -8
  285. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +6 -6
  286. package/server/modules/providers/list/gemini/gemini-skills.provider.ts +8 -0
  287. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +18 -4
  288. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +9 -12
  289. package/server/modules/providers/provider.routes.ts +167 -1
  290. package/server/modules/providers/services/mcp.service.ts +26 -0
  291. package/server/modules/providers/services/provider-capabilities.service.ts +91 -0
  292. package/server/modules/providers/services/provider-models.service.ts +1 -1
  293. package/server/modules/providers/services/sessions-watcher.service.ts +71 -25
  294. package/server/modules/providers/services/sessions.service.ts +79 -4
  295. package/server/modules/providers/services/skills.service.ts +25 -1
  296. package/server/modules/providers/shared/skills/skills.provider.ts +223 -0
  297. package/server/modules/providers/tests/opencode-sessions.test.ts +49 -0
  298. package/server/modules/providers/tests/skills.test.ts +212 -0
  299. package/server/modules/websocket/README.md +33 -27
  300. package/server/modules/websocket/index.ts +1 -0
  301. package/server/modules/websocket/services/chat-run-registry.service.ts +327 -0
  302. package/server/modules/websocket/services/chat-session-writer.service.ts +145 -0
  303. package/server/modules/websocket/services/chat-websocket.service.ts +292 -207
  304. package/server/modules/websocket/services/desktop-agent-websocket.service.ts +51 -0
  305. package/server/modules/websocket/services/shell-websocket.service.ts +108 -32
  306. package/server/modules/websocket/services/websocket-server.service.ts +12 -0
  307. package/server/modules/websocket/tests/chat-run-registry.test.ts +244 -0
  308. package/server/openai-codex.js +24 -14
  309. package/server/opencode-cli.js +21 -8
  310. package/server/opencode-cli.test.js +20 -1
  311. package/server/routes/agent.js +1 -1
  312. package/server/routes/settings.js +6 -1
  313. package/server/services/notification-orchestrator.js +3 -224
  314. package/server/services/tests/notification-orchestrator.test.js +80 -0
  315. package/server/shared/interfaces.ts +15 -0
  316. package/server/shared/tests/slice-tail-page.test.ts +42 -0
  317. package/server/shared/types.ts +84 -1
  318. package/server/shared/utils.ts +95 -1
  319. package/server/voice-proxy.js +224 -0
  320. package/dist/assets/index-73Xw3i9v.css +0 -32
  321. package/dist/assets/index-9n7A21AT.js +0 -1361
  322. package/dist/modelConstants.js +0 -848
  323. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +0 -1
  324. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +0 -1
  325. package/dist-server/server/shared/claude-cli-path.test.js.map +0 -1
  326. package/public/modelConstants.js +0 -848
  327. /package/dist-server/server/modules/database/{repositories → tests}/projects.db.integration.test.js +0 -0
  328. /package/server/modules/database/{repositories → tests}/projects.db.integration.test.ts +0 -0
  329. /package/server/shared/{claude-cli-path.test.ts → tests/claude-cli-path.test.ts} +0 -0
@@ -0,0 +1,550 @@
1
+ import { spawn } from 'node:child_process';
2
+ import fs from 'node:fs/promises';
3
+ import http from 'node:http';
4
+ import net from 'node:net';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+
8
+ import { ServerInstaller } from './serverInstaller.js';
9
+
10
+ const DEFAULT_PORT = 3001;
11
+ const HOST = '127.0.0.1';
12
+ const DISPLAY_HOST = 'localhost';
13
+ const HEALTH_TIMEOUT_MS = 1000;
14
+ const SERVER_START_TIMEOUT_MS = 30000;
15
+ const MAX_STARTUP_LOG_LINES = 300;
16
+ const SERVER_MARKER_PATH = path.join(os.homedir(), '.cloudcli', 'local-server.json');
17
+ const LOCAL_SERVER_URL_ENV_KEYS = [
18
+ 'CLOUDCLI_DESKTOP_LOCAL_SERVER_URL',
19
+ 'CLOUDCLI_LOCAL_SERVER_URL',
20
+ 'ELECTRON_LOCAL_SERVER_URL',
21
+ ];
22
+ const LOCAL_SERVER_PORT_ENV_KEYS = [
23
+ 'CLOUDCLI_DESKTOP_LOCAL_SERVER_PORT',
24
+ 'CLOUDCLI_SERVER_PORT',
25
+ 'SERVER_PORT',
26
+ 'PORT',
27
+ ];
28
+
29
+ function requestJson(url, timeoutMs = HEALTH_TIMEOUT_MS) {
30
+ return new Promise((resolve) => {
31
+ const req = http.get(url, { timeout: timeoutMs }, (res) => {
32
+ let body = '';
33
+
34
+ res.setEncoding('utf8');
35
+ res.on('data', (chunk) => {
36
+ body += chunk;
37
+ });
38
+ res.on('end', () => {
39
+ try {
40
+ resolve({
41
+ ok: res.statusCode >= 200 && res.statusCode < 300,
42
+ json: JSON.parse(body),
43
+ });
44
+ } catch {
45
+ resolve({ ok: false, json: null });
46
+ }
47
+ });
48
+ });
49
+
50
+ req.on('timeout', () => {
51
+ req.destroy();
52
+ resolve({ ok: false, json: null });
53
+ });
54
+ req.on('error', () => resolve({ ok: false, json: null }));
55
+ });
56
+ }
57
+
58
+ async function isCloudCliServer(baseUrl) {
59
+ const response = await requestJson(`${baseUrl}/health`);
60
+ return response.ok
61
+ && response.json?.status === 'ok'
62
+ && typeof response.json?.installMode === 'string';
63
+ }
64
+
65
+ function isPortAvailable(port, host = HOST) {
66
+ return new Promise((resolve) => {
67
+ const server = net.createServer();
68
+
69
+ server.once('error', () => resolve(false));
70
+ server.once('listening', () => {
71
+ server.close(() => resolve(true));
72
+ });
73
+ server.listen(port, host);
74
+ });
75
+ }
76
+
77
+ function getFreePort() {
78
+ return new Promise((resolve, reject) => {
79
+ const server = net.createServer();
80
+
81
+ server.once('error', reject);
82
+ server.once('listening', () => {
83
+ const address = server.address();
84
+ const port = typeof address === 'object' && address ? address.port : DEFAULT_PORT;
85
+ server.close(() => resolve(port));
86
+ });
87
+ server.listen(0, HOST);
88
+ });
89
+ }
90
+
91
+ async function chooseServerPort(host) {
92
+ if (await isPortAvailable(DEFAULT_PORT, host)) {
93
+ return DEFAULT_PORT;
94
+ }
95
+
96
+ return getFreePort();
97
+ }
98
+
99
+ function getDesktopPath() {
100
+ const currentPath = process.env.PATH || '';
101
+ const commonPaths = process.platform === 'win32'
102
+ ? []
103
+ : ['/opt/homebrew/bin', '/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin'];
104
+
105
+ return [...commonPaths, currentPath].filter(Boolean).join(path.delimiter);
106
+ }
107
+
108
+ function getNodeRuntime(usePackagedElectronRuntime) {
109
+ if (process.env.ELECTRON_NODE_PATH) {
110
+ return { command: process.env.ELECTRON_NODE_PATH, env: {}, label: 'ELECTRON_NODE_PATH' };
111
+ }
112
+
113
+ if (usePackagedElectronRuntime && process.versions.electron) {
114
+ return {
115
+ command: process.execPath,
116
+ env: { ELECTRON_RUN_AS_NODE: '1' },
117
+ label: `Electron ${process.versions.electron} Node ${process.versions.node}`,
118
+ };
119
+ }
120
+
121
+ if (process.env.npm_node_execpath) {
122
+ return { command: process.env.npm_node_execpath, env: {}, label: 'npm_node_execpath' };
123
+ }
124
+
125
+ return { command: 'node', env: {}, label: 'PATH node' };
126
+ }
127
+
128
+ function stripTrailingSlash(value) {
129
+ return value.endsWith('/') ? value.slice(0, -1) : value;
130
+ }
131
+
132
+ function addCandidateUrl(urls, rawUrl) {
133
+ if (!rawUrl) return;
134
+ try {
135
+ const parsed = new URL(String(rawUrl));
136
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return;
137
+ parsed.hash = '';
138
+ parsed.search = '';
139
+ const normalized = stripTrailingSlash(parsed.toString());
140
+ if (!urls.includes(normalized)) urls.push(normalized);
141
+ } catch {
142
+ // Ignore invalid user-provided discovery values.
143
+ }
144
+ }
145
+
146
+ function addCandidatePort(urls, rawPort) {
147
+ const port = Number.parseInt(String(rawPort || ''), 10);
148
+ if (!Number.isInteger(port) || port < 1 || port > 65535) return;
149
+ addCandidateUrl(urls, `http://${HOST}:${port}`);
150
+ }
151
+
152
+ function getPortFromUrl(baseUrl) {
153
+ try {
154
+ const parsed = new URL(baseUrl);
155
+ if (parsed.port) return Number.parseInt(parsed.port, 10);
156
+ return parsed.protocol === 'https:' ? 443 : 80;
157
+ } catch {
158
+ return null;
159
+ }
160
+ }
161
+
162
+ function getDisplayUrl(baseUrl) {
163
+ try {
164
+ const parsed = new URL(baseUrl);
165
+ if (parsed.hostname === HOST) {
166
+ parsed.hostname = DISPLAY_HOST;
167
+ }
168
+ return stripTrailingSlash(parsed.toString());
169
+ } catch {
170
+ return baseUrl;
171
+ }
172
+ }
173
+
174
+ async function pathExists(filePath) {
175
+ try {
176
+ await fs.access(filePath);
177
+ return true;
178
+ } catch {
179
+ return false;
180
+ }
181
+ }
182
+
183
+ async function readServerBundleConfig(appRoot) {
184
+ try {
185
+ const raw = await fs.readFile(path.join(appRoot, 'electron', 'server-bundle-config.json'), 'utf8');
186
+ const config = JSON.parse(raw);
187
+ return {
188
+ releaseTag: typeof config.releaseTag === 'string' && config.releaseTag.trim()
189
+ ? config.releaseTag.trim()
190
+ : '',
191
+ };
192
+ } catch {
193
+ return { releaseTag: '' };
194
+ }
195
+ }
196
+
197
+ function getServerCwd(appRoot, serverEntry) {
198
+ const normalizedEntry = path.resolve(serverEntry);
199
+ const bundledEntry = path.resolve(appRoot, 'dist-server', 'server', 'index.js');
200
+ if (normalizedEntry === bundledEntry) {
201
+ return appRoot;
202
+ }
203
+
204
+ // Installed server entries are laid out as <root>/dist-server/server/index.js.
205
+ return path.resolve(path.dirname(normalizedEntry), '..', '..');
206
+ }
207
+
208
+ async function readServerMarkerUrl() {
209
+ try {
210
+ const raw = await fs.readFile(SERVER_MARKER_PATH, 'utf8');
211
+ const marker = JSON.parse(raw);
212
+ return marker.url || (marker.port ? `http://${marker.host || HOST}:${marker.port}` : null);
213
+ } catch {
214
+ return null;
215
+ }
216
+ }
217
+
218
+ async function getExistingServerCandidateUrls(defaultUrl) {
219
+ const urls = [];
220
+
221
+ for (const key of LOCAL_SERVER_URL_ENV_KEYS) {
222
+ addCandidateUrl(urls, process.env[key]);
223
+ }
224
+
225
+ addCandidateUrl(urls, await readServerMarkerUrl());
226
+
227
+ for (const key of LOCAL_SERVER_PORT_ENV_KEYS) {
228
+ addCandidatePort(urls, process.env[key]);
229
+ }
230
+
231
+ addCandidateUrl(urls, defaultUrl);
232
+ return urls;
233
+ }
234
+
235
+ async function waitForCloudCliServer(baseUrl, timeoutMs) {
236
+ const startedAt = Date.now();
237
+
238
+ while (Date.now() - startedAt < timeoutMs) {
239
+ if (await isCloudCliServer(baseUrl)) {
240
+ return true;
241
+ }
242
+ await new Promise((resolve) => setTimeout(resolve, 300));
243
+ }
244
+
245
+ return false;
246
+ }
247
+
248
+ export class LocalServerController {
249
+ constructor({ appRoot, settingsPath, isPackaged = false, appVersion, onChange }) {
250
+ this.appRoot = appRoot;
251
+ this.settingsPath = settingsPath;
252
+ this.isPackaged = isPackaged;
253
+ this.appVersion = appVersion;
254
+ this.onChange = onChange;
255
+ this.localServerUrl = null;
256
+ this.localServerPort = null;
257
+ this.ownedServerProcess = null;
258
+ this.startupLogs = [];
259
+ this.desktopSettings = {
260
+ keepLocalServerRunning: false,
261
+ exposeLocalServerOnNetwork: false,
262
+ themeMode: 'system',
263
+ };
264
+ }
265
+
266
+ getSettings() {
267
+ return this.desktopSettings;
268
+ }
269
+
270
+ getLocalServerUrl() {
271
+ return this.localServerUrl;
272
+ }
273
+
274
+ getHealthCheckUrl() {
275
+ if (!this.localServerPort) return this.localServerUrl;
276
+ return `http://${HOST}:${this.localServerPort}`;
277
+ }
278
+
279
+ appendStartupLog(line) {
280
+ const text = String(line || '').trimEnd();
281
+ if (!text) return;
282
+ const timestamp = new Date().toLocaleTimeString();
283
+ this.startupLogs.push(`[${timestamp}] ${text}`);
284
+ if (this.startupLogs.length > MAX_STARTUP_LOG_LINES) {
285
+ this.startupLogs.splice(0, this.startupLogs.length - MAX_STARTUP_LOG_LINES);
286
+ }
287
+ this.onChange?.();
288
+ }
289
+
290
+ getStartupLogs() {
291
+ return [...this.startupLogs];
292
+ }
293
+
294
+ getPendingTarget() {
295
+ return {
296
+ kind: 'local',
297
+ name: 'Local CloudCLI',
298
+ url: this.localServerUrl || `http://${DISPLAY_HOST}:${this.localServerPort || DEFAULT_PORT}`,
299
+ };
300
+ }
301
+
302
+ getLanAddress() {
303
+ const interfaces = os.networkInterfaces();
304
+ for (const entries of Object.values(interfaces)) {
305
+ for (const entry of entries || []) {
306
+ if (entry.family === 'IPv4' && !entry.internal) {
307
+ return entry.address;
308
+ }
309
+ }
310
+ }
311
+ return null;
312
+ }
313
+
314
+ getShareableWebUrl() {
315
+ if (!this.localServerUrl || !this.localServerPort) return null;
316
+ if (this.desktopSettings.exposeLocalServerOnNetwork) {
317
+ const lanAddress = this.getLanAddress();
318
+ if (lanAddress) {
319
+ return `http://${lanAddress}:${this.localServerPort}`;
320
+ }
321
+ }
322
+ return this.getLocalServerUrl();
323
+ }
324
+
325
+ getServerBindHost() {
326
+ return this.desktopSettings.exposeLocalServerOnNetwork ? '0.0.0.0' : HOST;
327
+ }
328
+
329
+ async loadDesktopSettings() {
330
+ try {
331
+ const raw = await fs.readFile(this.settingsPath, 'utf8');
332
+ const stored = JSON.parse(raw);
333
+ this.desktopSettings = {
334
+ keepLocalServerRunning: Boolean(stored.keepLocalServerRunning),
335
+ exposeLocalServerOnNetwork: Boolean(stored.exposeLocalServerOnNetwork),
336
+ themeMode: stored.themeMode === 'light' || stored.themeMode === 'dark' ? stored.themeMode : 'system',
337
+ };
338
+ } catch {
339
+ this.desktopSettings = {
340
+ keepLocalServerRunning: false,
341
+ exposeLocalServerOnNetwork: false,
342
+ themeMode: 'system',
343
+ };
344
+ }
345
+ }
346
+
347
+ async saveDesktopSettings(nextSettings = this.desktopSettings) {
348
+ this.desktopSettings = {
349
+ keepLocalServerRunning: Boolean(nextSettings.keepLocalServerRunning),
350
+ exposeLocalServerOnNetwork: Boolean(nextSettings.exposeLocalServerOnNetwork),
351
+ themeMode: nextSettings.themeMode === 'light' || nextSettings.themeMode === 'dark' ? nextSettings.themeMode : 'system',
352
+ };
353
+ await fs.mkdir(path.dirname(this.settingsPath), { recursive: true });
354
+ await fs.writeFile(this.settingsPath, JSON.stringify(this.desktopSettings, null, 2), 'utf8');
355
+ this.onChange?.();
356
+ }
357
+
358
+ async updateDesktopSetting(key, value) {
359
+ if (!Object.prototype.hasOwnProperty.call(this.desktopSettings, key)) {
360
+ throw new Error(`Unknown desktop setting: ${key}`);
361
+ }
362
+
363
+ const wasExposeSetting = key === 'exposeLocalServerOnNetwork';
364
+ const wasLocalRunning = Boolean(this.localServerUrl);
365
+ const nextValue = key === 'themeMode' ? value : Boolean(value);
366
+ await this.saveDesktopSettings({ ...this.desktopSettings, [key]: nextValue });
367
+
368
+ return {
369
+ desktopSettings: this.desktopSettings,
370
+ requiresRestartNotice: wasExposeSetting && wasLocalRunning,
371
+ };
372
+ }
373
+
374
+ /** Resolves the local server entry, installing the matching runtime if needed. */
375
+ async resolveServerEntry() {
376
+ if (process.env.ELECTRON_SERVER_ENTRY) {
377
+ return process.env.ELECTRON_SERVER_ENTRY;
378
+ }
379
+
380
+ const bundledEntry = path.join(this.appRoot, 'dist-server', 'server', 'index.js');
381
+ if (process.env.CLOUDCLI_USE_INSTALLED_SERVER !== '1' && await pathExists(bundledEntry)) {
382
+ return bundledEntry;
383
+ }
384
+
385
+ if (!this.appVersion) {
386
+ throw new Error('Cannot install local server: app version is unknown.');
387
+ }
388
+ const bundleConfig = await readServerBundleConfig(this.appRoot);
389
+ const installer = new ServerInstaller({
390
+ version: this.appVersion,
391
+ bundleReleaseTag: bundleConfig.releaseTag,
392
+ onLog: (line) => this.appendStartupLog(line),
393
+ });
394
+ return installer.ensureInstalled();
395
+ }
396
+
397
+ startBundledServer(port, serverEntry) {
398
+ const bindHost = this.getServerBindHost();
399
+ const runtime = getNodeRuntime(this.isPackaged);
400
+ const serverCwd = getServerCwd(this.appRoot, serverEntry);
401
+
402
+ const command = `${runtime.command} ${serverEntry}`;
403
+ this.appendStartupLog(`$ ${command}`);
404
+ this.appendStartupLog(`runtime: ${runtime.label}`);
405
+ this.appendStartupLog(`cwd: ${serverCwd}`);
406
+ this.appendStartupLog(`HOST=${bindHost} SERVER_PORT=${port} NODE_ENV=production`);
407
+
408
+ this.ownedServerProcess = spawn(runtime.command, [serverEntry], {
409
+ cwd: serverCwd,
410
+ detached: true,
411
+ env: {
412
+ ...process.env,
413
+ ...runtime.env,
414
+ HOST: bindHost,
415
+ SERVER_PORT: String(port),
416
+ NODE_ENV: 'production',
417
+ PATH: getDesktopPath(),
418
+ },
419
+ stdio: ['ignore', 'pipe', 'pipe'],
420
+ windowsHide: true,
421
+ });
422
+
423
+ this.ownedServerProcess.once('error', (error) => {
424
+ this.appendStartupLog(`failed to start process: ${error.message}`);
425
+ this.ownedServerProcess = null;
426
+ });
427
+
428
+ this.ownedServerProcess.stdout?.on('data', (chunk) => {
429
+ for (const line of String(chunk).split(/\r?\n/)) {
430
+ this.appendStartupLog(line);
431
+ }
432
+ });
433
+
434
+ this.ownedServerProcess.stderr?.on('data', (chunk) => {
435
+ for (const line of String(chunk).split(/\r?\n/)) {
436
+ this.appendStartupLog(`stderr: ${line}`);
437
+ }
438
+ });
439
+
440
+ this.ownedServerProcess.once('exit', (code, signal) => {
441
+ this.appendStartupLog(`process exited with code ${code ?? 'null'} and signal ${signal ?? 'null'}`);
442
+ if (this.ownedServerProcess) {
443
+ console.error(`CloudCLI desktop server exited with code ${code ?? 'null'} and signal ${signal ?? 'null'}`);
444
+ }
445
+ this.ownedServerProcess = null;
446
+ });
447
+ }
448
+
449
+ async resolveLocalServerUrl() {
450
+ const defaultUrl = `http://${HOST}:${DEFAULT_PORT}`;
451
+ const defaultDisplayUrl = `http://${DISPLAY_HOST}:${DEFAULT_PORT}`;
452
+ const devUrl = process.env.ELECTRON_DEV_URL;
453
+ const forceOwnServer = process.env.ELECTRON_FORCE_OWN_SERVER === '1';
454
+
455
+ if (devUrl) {
456
+ const ready = await waitForCloudCliServer(defaultUrl, SERVER_START_TIMEOUT_MS);
457
+ if (!ready) {
458
+ throw new Error(`Development backend did not become ready at ${defaultDisplayUrl}`);
459
+ }
460
+ this.localServerPort = DEFAULT_PORT;
461
+ return devUrl;
462
+ }
463
+
464
+ if (!forceOwnServer) {
465
+ const candidateUrls = await getExistingServerCandidateUrls(defaultUrl);
466
+ for (const candidateUrl of candidateUrls) {
467
+ if (await isCloudCliServer(candidateUrl)) {
468
+ const displayUrl = getDisplayUrl(candidateUrl);
469
+ this.localServerPort = getPortFromUrl(candidateUrl);
470
+ this.appendStartupLog(`Using existing Local CloudCLI at ${displayUrl}`);
471
+ return displayUrl;
472
+ }
473
+ }
474
+ }
475
+
476
+ const serverEntry = await this.resolveServerEntry();
477
+
478
+ const port = await chooseServerPort(this.getServerBindHost());
479
+ const serverUrl = `http://${HOST}:${port}`;
480
+ const displayUrl = `http://${DISPLAY_HOST}:${port}`;
481
+ this.localServerPort = port;
482
+ this.startBundledServer(port, serverEntry);
483
+
484
+ const ready = await waitForCloudCliServer(serverUrl, SERVER_START_TIMEOUT_MS);
485
+ if (!ready) {
486
+ const recentLogs = this.getStartupLogs().slice(-20).join('\n');
487
+ await this.shutdownOwnedServer();
488
+ this.localServerPort = null;
489
+ throw new Error([
490
+ `Bundled backend did not become ready at ${displayUrl}.`,
491
+ recentLogs ? `Recent startup output:\n${recentLogs}` : 'No startup output was captured.',
492
+ ].join('\n\n'));
493
+ }
494
+
495
+ this.appendStartupLog(`Local CloudCLI ready at ${displayUrl}`);
496
+ this.localServerUrl = displayUrl;
497
+ return displayUrl;
498
+ }
499
+
500
+ async ensureLocalServer() {
501
+ if (!this.localServerUrl) {
502
+ this.localServerUrl = await this.resolveLocalServerUrl();
503
+ }
504
+ return this.localServerUrl;
505
+ }
506
+
507
+ async getResolvedTarget() {
508
+ await this.ensureLocalServer();
509
+ return {
510
+ kind: 'local',
511
+ name: 'Local CloudCLI',
512
+ url: this.localServerUrl,
513
+ };
514
+ }
515
+
516
+ async loadLocalTarget() {
517
+ return {
518
+ pendingTarget: this.getPendingTarget(),
519
+ target: await this.getResolvedTarget(),
520
+ };
521
+ }
522
+
523
+ hasOwnedServer() {
524
+ return Boolean(this.ownedServerProcess);
525
+ }
526
+
527
+ detachOwnedServer() {
528
+ if (!this.ownedServerProcess) return;
529
+ this.ownedServerProcess.unref();
530
+ this.ownedServerProcess = null;
531
+ }
532
+
533
+ async shutdownOwnedServer() {
534
+ if (!this.ownedServerProcess) return;
535
+
536
+ const child = this.ownedServerProcess;
537
+ this.ownedServerProcess = null;
538
+ child.kill('SIGTERM');
539
+
540
+ await new Promise((resolve) => {
541
+ const timeout = setTimeout(resolve, 3000);
542
+ child.once('exit', () => {
543
+ clearTimeout(timeout);
544
+ resolve();
545
+ });
546
+ });
547
+ }
548
+ }
549
+
550
+ export { DEFAULT_PORT, HOST };