@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,331 @@
1
+ import { BrowserView } from 'electron';
2
+
3
+ const TARGET_LOAD_TIMEOUT_MS = 20000;
4
+
5
+ function escapeHtml(value) {
6
+ return String(value == null ? '' : value)
7
+ .replace(/&/g, '&')
8
+ .replace(/</g, '&lt;')
9
+ .replace(/>/g, '&gt;')
10
+ .replace(/"/g, '&quot;');
11
+ }
12
+
13
+ function buildPlaceholderHtml(title, message, logs = []) {
14
+ const logHtml = logs.length
15
+ ? `<pre>${logs.map(escapeHtml).join('\n')}</pre>`
16
+ : '<pre>Waiting for process output...</pre>';
17
+ return [
18
+ '<!doctype html><meta charset="utf-8">',
19
+ '<style>',
20
+ 'html,body{margin:0;height:100%;background:#0a0a0a;color:#fafafa;font:14px -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}',
21
+ 'body{padding:28px;overflow:hidden}',
22
+ '.shell{height:100%;display:flex;flex-direction:column;gap:16px}',
23
+ '.box{display:flex;align-items:center;gap:10px;color:#d4d4d4;flex:0 0 auto}',
24
+ '.dot{width:8px;height:8px;border-radius:50%;background:#0b60ea;box-shadow:0 0 0 6px rgba(11,96,234,.15)}',
25
+ 'pre{margin:0;flex:1;overflow:auto;border:1px solid #262626;border-radius:10px;background:#050505;color:#d4d4d4;padding:14px;font:12px/1.55 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;user-select:text}',
26
+ '</style>',
27
+ '<div class="shell">',
28
+ `<div class="box"><span class="dot"></span><span>${escapeHtml(message || `Opening ${title}...`)}</span></div>`,
29
+ logHtml,
30
+ '</div>',
31
+ ].join('');
32
+ }
33
+
34
+ function isHttpUrl(url) {
35
+ try {
36
+ const parsed = new URL(url);
37
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+
43
+ async function loadUrlWithTimeout(webContents, url, timeoutMs = TARGET_LOAD_TIMEOUT_MS) {
44
+ let timedOut = false;
45
+ let timeout = null;
46
+ const loadPromise = webContents.loadURL(url);
47
+ const timeoutPromise = new Promise((_, reject) => {
48
+ timeout = setTimeout(() => {
49
+ timedOut = true;
50
+ try {
51
+ webContents.stop();
52
+ } catch {
53
+ // Ignore teardown races while reporting the original timeout.
54
+ }
55
+ reject(new Error(`Timed out loading ${url} after ${Math.round(timeoutMs / 1000)} seconds.`));
56
+ }, timeoutMs);
57
+ });
58
+
59
+ try {
60
+ await Promise.race([loadPromise, timeoutPromise]);
61
+ } catch (error) {
62
+ if (timedOut) {
63
+ loadPromise.catch(() => {});
64
+ }
65
+ throw error;
66
+ } finally {
67
+ if (timeout) clearTimeout(timeout);
68
+ }
69
+ }
70
+
71
+ export class ViewHost {
72
+ constructor({ appName, getMainWindow, getContentViewBounds, getPreloadPath, openExternalUrl, showError }) {
73
+ this.appName = appName;
74
+ this.getMainWindow = getMainWindow;
75
+ this.getContentViewBounds = getContentViewBounds;
76
+ this.getPreloadPath = getPreloadPath;
77
+ this.openExternalUrl = openExternalUrl;
78
+ this.showError = showError;
79
+ this.activeContentView = null;
80
+ this.tabViews = new Map();
81
+ }
82
+
83
+ configureChildWebContents(webContents) {
84
+ webContents.setWindowOpenHandler(({ url }) => {
85
+ void this.openExternalUrl(url).catch((error) => this.showError('Could not open external link', error));
86
+ return { action: 'deny' };
87
+ });
88
+ }
89
+
90
+ detachAll() {
91
+ const mainWindow = this.getMainWindow();
92
+ if (!mainWindow || mainWindow.isDestroyed()) return;
93
+ try {
94
+ for (const view of mainWindow.getBrowserViews()) {
95
+ mainWindow.removeBrowserView(view);
96
+ }
97
+ } catch {
98
+ // BrowserViews may already be gone during BrowserWindow teardown.
99
+ }
100
+ this.activeContentView = null;
101
+ }
102
+
103
+ detachActiveView() {
104
+ const mainWindow = this.getMainWindow();
105
+ const view = this.activeContentView;
106
+ if (!mainWindow || mainWindow.isDestroyed() || !view) return false;
107
+ try {
108
+ if (mainWindow.getBrowserViews().includes(view)) {
109
+ mainWindow.removeBrowserView(view);
110
+ }
111
+ } catch {
112
+ return false;
113
+ }
114
+ this.activeContentView = null;
115
+ return true;
116
+ }
117
+
118
+ getActiveView() {
119
+ const view = this.activeContentView;
120
+ if (!view || view.webContents.isDestroyed()) return null;
121
+ return view;
122
+ }
123
+
124
+ openActiveViewDevTools() {
125
+ const view = this.getActiveView();
126
+ if (!view) return false;
127
+ view.webContents.openDevTools({ mode: 'detach' });
128
+ return true;
129
+ }
130
+
131
+ reloadActiveView() {
132
+ const view = this.getActiveView();
133
+ if (!view) return false;
134
+ view.webContents.reloadIgnoringCache();
135
+ return true;
136
+ }
137
+
138
+ async readLocalStorageValueForOrigin(originUrl, key) {
139
+ let targetOrigin;
140
+ try {
141
+ targetOrigin = new URL(originUrl).origin;
142
+ } catch {
143
+ return null;
144
+ }
145
+
146
+ for (const view of this.tabViews.values()) {
147
+ if (!view || view.webContents.isDestroyed()) continue;
148
+ let viewOrigin;
149
+ try {
150
+ viewOrigin = new URL(view.webContents.getURL()).origin;
151
+ } catch {
152
+ continue;
153
+ }
154
+ if (viewOrigin !== targetOrigin) continue;
155
+
156
+ try {
157
+ const value = await view.webContents.executeJavaScript(
158
+ `window.localStorage.getItem(${JSON.stringify(key)})`,
159
+ true
160
+ );
161
+ return typeof value === 'string' && value ? value : null;
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+
167
+ return null;
168
+ }
169
+
170
+ getTabViewDiagnostics() {
171
+ const mainWindow = this.getMainWindow();
172
+ const attachedViews = new Set();
173
+ if (mainWindow && !mainWindow.isDestroyed()) {
174
+ try {
175
+ for (const view of mainWindow.getBrowserViews()) {
176
+ attachedViews.add(view);
177
+ }
178
+ } catch {
179
+ // Ignore teardown races while gathering best-effort diagnostics.
180
+ }
181
+ }
182
+
183
+ return Array.from(this.tabViews.entries()).map(([tabId, view]) => {
184
+ const { webContents } = view;
185
+ const destroyed = webContents.isDestroyed();
186
+ return {
187
+ tabId,
188
+ webContentsId: destroyed ? null : webContents.id,
189
+ url: destroyed ? null : webContents.getURL(),
190
+ title: destroyed ? null : webContents.getTitle(),
191
+ osProcessId: destroyed || typeof webContents.getOSProcessId !== 'function' ? null : webContents.getOSProcessId(),
192
+ processId: destroyed || typeof webContents.getProcessId !== 'function' ? null : webContents.getProcessId(),
193
+ attached: attachedViews.has(view),
194
+ active: this.activeContentView === view,
195
+ destroyed,
196
+ };
197
+ });
198
+ }
199
+
200
+ getOrCreateTabView(tabId) {
201
+ let view = this.tabViews.get(tabId);
202
+ if (view) return view;
203
+
204
+ view = new BrowserView({
205
+ webPreferences: {
206
+ contextIsolation: true,
207
+ nodeIntegration: false,
208
+ sandbox: true,
209
+ preload: this.getPreloadPath(),
210
+ },
211
+ });
212
+ this.configureChildWebContents(view.webContents);
213
+ this.tabViews.set(tabId, view);
214
+ return view;
215
+ }
216
+
217
+ attach(view) {
218
+ const mainWindow = this.getMainWindow();
219
+ if (!mainWindow || mainWindow.isDestroyed()) return;
220
+ if (this.activeContentView && this.activeContentView !== view) {
221
+ this.detachAll();
222
+ }
223
+ this.activeContentView = view;
224
+ try {
225
+ if (!mainWindow.getBrowserViews().includes(view)) {
226
+ mainWindow.addBrowserView(view);
227
+ }
228
+ } catch {
229
+ return;
230
+ }
231
+ view.setBounds(this.getContentViewBounds());
232
+ view.setAutoResize({ width: true, height: true });
233
+ }
234
+
235
+ resizeActiveView() {
236
+ if (this.activeContentView) {
237
+ this.activeContentView.setBounds(this.getContentViewBounds());
238
+ }
239
+ }
240
+
241
+ async showTabPlaceholder(tabId, target, message) {
242
+ const view = this.getOrCreateTabView(tabId);
243
+ this.attach(view);
244
+ const html = buildPlaceholderHtml(target.name || this.appName, message);
245
+ await view.webContents.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`);
246
+ view.__cloudcliStartupHtml = html;
247
+ view.__cloudcliLoadedUrl = null;
248
+ }
249
+
250
+ async showLocalStartupTarget(tabId, target, logs) {
251
+ const view = this.getOrCreateTabView(tabId);
252
+ if (view.__cloudcliLoadingUrl) return;
253
+ this.attach(view);
254
+ const html = buildPlaceholderHtml(target.name || this.appName, 'Starting Local CloudCLI...', logs);
255
+ if (view.__cloudcliStartupHtml === html) return;
256
+ await view.webContents.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`);
257
+ view.__cloudcliStartupHtml = html;
258
+ view.__cloudcliLoadedUrl = null;
259
+ }
260
+
261
+ async showContentTarget(tabId, target) {
262
+ const loadUrl = target.loadUrl || target.url;
263
+ if (!isHttpUrl(loadUrl)) {
264
+ throw new Error(`Refusing to load unsupported app URL: ${loadUrl}`);
265
+ }
266
+ const view = this.getOrCreateTabView(tabId);
267
+ this.attach(view);
268
+ if (target.forceLoad || view.__cloudcliLoadedUrl !== target.url) {
269
+ view.__cloudcliLoadingUrl = loadUrl;
270
+ try {
271
+ await loadUrlWithTimeout(view.webContents, loadUrl);
272
+ view.__cloudcliLoadedUrl = target.url;
273
+ view.__cloudcliStartupHtml = null;
274
+ delete target.loadUrl;
275
+ delete target.forceLoad;
276
+ } finally {
277
+ if (view.__cloudcliLoadingUrl === loadUrl) {
278
+ view.__cloudcliLoadingUrl = null;
279
+ }
280
+ }
281
+ }
282
+ return view.webContents.getURL();
283
+ }
284
+
285
+ reloadTab(tabId) {
286
+ const view = this.tabViews.get(tabId);
287
+ if (!view || view.webContents.isDestroyed()) return false;
288
+ view.webContents.reloadIgnoringCache();
289
+ return true;
290
+ }
291
+
292
+ async navigateActiveView(url) {
293
+ const view = this.getActiveView();
294
+ if (!view) return false;
295
+ await loadUrlWithTimeout(view.webContents, url);
296
+ view.__cloudcliLoadedUrl = url;
297
+ view.__cloudcliStartupHtml = null;
298
+ return true;
299
+ }
300
+
301
+ destroyTabView(tabId) {
302
+ const view = this.tabViews.get(tabId);
303
+ if (!view) return;
304
+ const mainWindow = this.getMainWindow();
305
+ if (mainWindow && !mainWindow.isDestroyed()) {
306
+ try {
307
+ if (mainWindow.getBrowserViews().includes(view)) {
308
+ mainWindow.removeBrowserView(view);
309
+ }
310
+ } catch {
311
+ // Ignore teardown races; Electron owns final destruction during quit.
312
+ }
313
+ }
314
+ if (this.activeContentView === view) {
315
+ this.activeContentView = null;
316
+ }
317
+ try {
318
+ if (!view.webContents.isDestroyed()) {
319
+ view.webContents.destroy();
320
+ }
321
+ } catch {
322
+ // The view may already be destroyed by its parent BrowserWindow.
323
+ }
324
+ this.tabViews.delete(tabId);
325
+ }
326
+
327
+ clear() {
328
+ this.tabViews.clear();
329
+ this.activeContentView = null;
330
+ }
331
+ }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcli-ai/cloudcli",
3
- "version": "1.33.3",
3
+ "version": "1.35.0",
4
+ "productName": "CloudCLI",
4
5
  "description": "A web-based UI for Claude Code CLI",
5
6
  "type": "module",
6
7
  "main": "dist-server/server/index.js",
@@ -8,10 +9,10 @@
8
9
  "cloudcli": "dist-server/server/cli.js"
9
10
  },
10
11
  "files": [
12
+ "electron/",
11
13
  "server/",
12
14
  "shared/",
13
15
  "public/api-docs.html",
14
- "public/modelConstants.js",
15
16
  "dist/",
16
17
  "dist-server/",
17
18
  "scripts/",
@@ -28,13 +29,26 @@
28
29
  "scripts": {
29
30
  "dev": "concurrently --kill-others \"npm run server:dev\" \"npm run client\"",
30
31
  "server": "node dist-server/server/index.js",
32
+ "preserver:dev": "npm run build:semantics",
31
33
  "server:dev": "tsx --tsconfig server/tsconfig.json server/index.js",
34
+ "preserver:dev-watch": "npm run build:semantics",
32
35
  "server:dev-watch": "tsx watch --tsconfig server/tsconfig.json server/index.js",
33
36
  "client": "vite",
34
- "build": "npm run build:client && npm run build:server",
37
+ "desktop": "electron electron/main.js",
38
+ "predesktop:dev": "npm run build:semantics",
39
+ "desktop:dev": "cross-env ELECTRON_DEV_URL=http://127.0.0.1:5173 electron electron/main.js",
40
+ "desktop:stage": "node scripts/release/prepare-desktop-app.js",
41
+ "desktop:pack": "npm run build && npm run desktop:stage && electron-builder --projectDir .desktop-build/desktop-app --dir",
42
+ "desktop:dist:mac": "npm run build && npm run desktop:stage && electron-builder --projectDir .desktop-build/desktop-app --mac dmg",
43
+ "desktop:dist:win": "npm run build && npm run desktop:stage && electron-builder --projectDir .desktop-build/desktop-app --win nsis",
44
+ "server:bundle": "npm run build && node scripts/release/build-server-bundle.js",
45
+ "desktop:icon:mac": "node electron/scripts/generate-macos-icon.js",
46
+ "build": "npm run build:semantics && npm run build:client && npm run build:server",
35
47
  "build:client": "vite build",
48
+ "build:semantics": "node scripts/build-computer-semantics.mjs",
36
49
  "prebuild:server": "node -e \"require('node:fs').rmSync('dist-server', { recursive: true, force: true })\"",
37
50
  "build:server": "tsc -p server/tsconfig.json && tsc-alias -p server/tsconfig.json",
51
+ "postbuild:server": "node scripts/copy-computer-semantics-bin.mjs",
38
52
  "preview": "vite preview",
39
53
  "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p server/tsconfig.json",
40
54
  "lint": "eslint src/ server/",
@@ -42,10 +56,70 @@
42
56
  "start": "npm run build && npm run server",
43
57
  "release": "./release.sh",
44
58
  "prepublishOnly": "npm run build",
45
- "postinstall": "node scripts/fix-node-pty.js",
59
+ "postinstall": "node scripts/fix-node-pty.js && npm run build:semantics",
46
60
  "prepare": "husky",
47
61
  "update:platform": "./update-platform.sh"
48
62
  },
63
+ "build": {
64
+ "appId": "ai.cloudcli.desktop",
65
+ "productName": "CloudCLI",
66
+ "asar": false,
67
+ "artifactName": "cloudcli-desktop-${version}-${os}-${arch}.${ext}",
68
+ "directories": {
69
+ "output": "release/desktop"
70
+ },
71
+ "extraMetadata": {
72
+ "main": "electron/main.js"
73
+ },
74
+ "files": [
75
+ "electron/",
76
+ "public/",
77
+ "dist/",
78
+ "dist-server/",
79
+ "shared/",
80
+ "server/",
81
+ "package.json",
82
+ "!**/node_modules/@anthropic-ai/claude-agent-sdk-{darwin,linux,win32}-*/**"
83
+ ],
84
+ "protocols": [
85
+ {
86
+ "name": "CloudCLI",
87
+ "schemes": [
88
+ "cloudcli"
89
+ ]
90
+ }
91
+ ],
92
+ "mac": {
93
+ "category": "public.app-category.developer-tools",
94
+ "icon": "electron/assets/logo-macos.icns",
95
+ "notarize": true,
96
+ "target": [
97
+ "dmg"
98
+ ],
99
+ "extendInfo": {
100
+ "CFBundleName": "CloudCLI",
101
+ "CFBundleDisplayName": "CloudCLI",
102
+ "CFBundleURLTypes": [
103
+ {
104
+ "CFBundleURLName": "CloudCLI",
105
+ "CFBundleURLSchemes": [
106
+ "cloudcli"
107
+ ]
108
+ }
109
+ ]
110
+ }
111
+ },
112
+ "win": {
113
+ "icon": "electron/assets/logo-windows.ico",
114
+ "target": [
115
+ "nsis"
116
+ ]
117
+ },
118
+ "nsis": {
119
+ "installerIcon": "electron/assets/logo-windows.ico",
120
+ "uninstallerIcon": "electron/assets/logo-windows.ico"
121
+ }
122
+ },
49
123
  "keywords": [
50
124
  "claude code",
51
125
  "claude-code",
@@ -78,7 +152,7 @@
78
152
  "@codemirror/theme-one-dark": "^6.1.2",
79
153
  "@iarna/toml": "^2.2.5",
80
154
  "@octokit/rest": "^22.0.0",
81
- "@openai/codex-sdk": "^0.125.0",
155
+ "@openai/codex-sdk": "^0.141.0",
82
156
  "@replit/codemirror-minimap": "^0.5.2",
83
157
  "@tailwindcss/typography": "^0.5.16",
84
158
  "@uiw/react-codemirror": "^4.23.13",
@@ -142,6 +216,9 @@
142
216
  "auto-changelog": "^2.5.0",
143
217
  "autoprefixer": "^10.4.16",
144
218
  "concurrently": "^8.2.2",
219
+ "cross-env": "^10.1.0",
220
+ "electron": "^38.0.0",
221
+ "electron-builder": "^26.15.3",
145
222
  "eslint": "^9.39.3",
146
223
  "eslint-import-resolver-typescript": "^4.4.4",
147
224
  "eslint-plugin-boundaries": "^6.0.2",
@@ -168,5 +245,9 @@
168
245
  "lint-staged": {
169
246
  "src/**/*.{ts,tsx,js,jsx}": "eslint",
170
247
  "server/**/*.{js,ts}": "eslint"
248
+ },
249
+ "optionalDependencies": {
250
+ "@nut-tree-fork/nut-js": "^4.2.6",
251
+ "screenshot-desktop": "^1.15.4"
171
252
  }
172
253
  }
@@ -820,31 +820,49 @@ data: {"type":"done"}</code></pre>
820
820
  </div>
821
821
  </div>
822
822
 
823
- <script type="module">
824
- // Import model constants
825
- import { PROVIDERS } from './modelConstants.js';
826
-
823
+ <script>
827
824
  // Dynamic URL replacement
828
825
  const apiUrl = window.location.origin;
829
826
  document.querySelectorAll('.api-url').forEach(el => {
830
827
  el.textContent = apiUrl;
831
828
  });
832
829
 
833
- // Dynamically populate model documentation
834
- window.addEventListener('DOMContentLoaded', () => {
830
+ // Populate model documentation from the live provider API
831
+ const PROVIDER_ORDER = [
832
+ { id: 'claude', name: 'Anthropic' },
833
+ { id: 'codex', name: 'OpenAI' },
834
+ { id: 'gemini', name: 'Google' },
835
+ { id: 'cursor', name: 'Cursor' },
836
+ { id: 'opencode', name: 'OpenCode' },
837
+ ];
838
+
839
+ async function populateModels() {
835
840
  const modelCell = document.getElementById('model-options-cell');
836
- if (modelCell) {
837
- const providerModels = PROVIDERS.map(provider => {
838
- const models = provider.models.OPTIONS.map(m => `<code>${m.value}</code>`).join(', ');
839
- return `<strong>${provider.name}:</strong> ${models} (default: <code>${provider.models.DEFAULT}</code>)`;
840
- }).join('<br><br>');
841
-
842
- modelCell.innerHTML = `
843
- Model identifier for the AI provider:<br><br>
844
- ${providerModels}
845
- `;
846
- }
847
- });
841
+ if (!modelCell) return;
842
+
843
+ const token = localStorage.getItem('auth-token');
844
+ const headers = token ? { Authorization: `Bearer ${token}` } : {};
845
+
846
+ const results = await Promise.allSettled(
847
+ PROVIDER_ORDER.map(({ id }) =>
848
+ fetch(`/api/providers/${id}/models`, { headers }).then(r => r.json())
849
+ )
850
+ );
851
+
852
+ const providerModels = results.map((result, i) => {
853
+ const { name } = PROVIDER_ORDER[i];
854
+ if (result.status === 'rejected' || !result.value?.data?.models) {
855
+ return `<strong>${name}:</strong> <em>unavailable</em>`;
856
+ }
857
+ const { OPTIONS, DEFAULT } = result.value.data.models;
858
+ const models = OPTIONS.map(m => `<code>${m.value}</code>`).join(', ');
859
+ return `<strong>${name}:</strong> ${models} (default: <code>${DEFAULT}</code>)`;
860
+ }).join('<br><br>');
861
+
862
+ modelCell.innerHTML = `Model identifier for the AI provider:<br><br>${providerModels}`;
863
+ }
864
+
865
+ document.addEventListener('DOMContentLoaded', populateModels);
848
866
 
849
867
  // Tab switching
850
868
  window.showTab = function(tabName) {
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
3
+ import fs from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ const rootDir = path.resolve(__dirname, '..');
9
+ const platform = process.env.CLOUDCLI_SEMANTICS_PLATFORM || process.platform;
10
+ const arch = process.env.CLOUDCLI_SEMANTICS_ARCH || process.arch;
11
+ const platformArch = `${platform}-${arch}`;
12
+ const semanticsRoot = path.join(rootDir, 'server', 'modules', 'computer-use', 'semantics');
13
+ const outDir = path.join(semanticsRoot, 'bin', platformArch);
14
+ const requireBuild = process.env.CLOUDCLI_SEMANTICS_BUILD_REQUIRED === '1';
15
+
16
+ function run(command, args, options = {}) {
17
+ return new Promise((resolve, reject) => {
18
+ const child = spawn(command, args, {
19
+ stdio: 'inherit',
20
+ shell: process.platform === 'win32',
21
+ ...options,
22
+ });
23
+ child.once('error', reject);
24
+ child.once('exit', (code) => {
25
+ if (code === 0) resolve();
26
+ else reject(new Error(`${command} ${args.join(' ')} exited with code ${code}`));
27
+ });
28
+ });
29
+ }
30
+
31
+ function commandExists(command) {
32
+ return new Promise((resolve) => {
33
+ const child = spawn(command, ['--version'], {
34
+ stdio: 'ignore',
35
+ shell: process.platform === 'win32',
36
+ });
37
+ child.once('error', () => resolve(false));
38
+ child.once('exit', (code) => resolve(code === 0));
39
+ });
40
+ }
41
+
42
+ async function pathExists(filePath) {
43
+ try {
44
+ await fs.access(filePath);
45
+ return true;
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ async function isUpToDate(output, inputs) {
52
+ if (!(await pathExists(output))) {
53
+ return false;
54
+ }
55
+
56
+ const outputStat = await fs.stat(output);
57
+ for (const input of inputs) {
58
+ const inputStat = await fs.stat(input);
59
+ if (inputStat.mtimeMs > outputStat.mtimeMs) {
60
+ return false;
61
+ }
62
+ }
63
+ return true;
64
+ }
65
+
66
+ async function ensureCommand(command, helpText) {
67
+ if (await commandExists(command)) {
68
+ return true;
69
+ }
70
+
71
+ const message = `${command} was not found. ${helpText}`;
72
+ if (requireBuild) {
73
+ throw new Error(message);
74
+ }
75
+ console.log(`Skipping semantic helper build: ${message}`);
76
+ return false;
77
+ }
78
+
79
+ if (platform === 'darwin') {
80
+ const source = path.join(semanticsRoot, 'helpers', 'macos', 'CloudCLISemantics.swift');
81
+ const output = path.join(outDir, 'CloudCLISemantics');
82
+
83
+ if (!(await ensureCommand('swiftc', 'Install Xcode Command Line Tools to compile the macOS helper.'))) {
84
+ process.exit(0);
85
+ }
86
+ if (await isUpToDate(output, [source])) {
87
+ console.log(`Semantic helper is up to date: ${path.relative(rootDir, output)}`);
88
+ process.exit(0);
89
+ }
90
+
91
+ await fs.mkdir(outDir, { recursive: true });
92
+ await run('swiftc', [
93
+ source,
94
+ '-o',
95
+ output,
96
+ '-framework',
97
+ 'AppKit',
98
+ '-framework',
99
+ 'ApplicationServices',
100
+ ]);
101
+ await fs.chmod(output, 0o755);
102
+ console.log(`Built ${path.relative(rootDir, output)}`);
103
+ } else if (platform === 'win32') {
104
+ const project = path.join(semanticsRoot, 'helpers', 'windows', 'CloudCLISemantics.csproj');
105
+ const source = path.join(semanticsRoot, 'helpers', 'windows', 'Program.cs');
106
+ const output = path.join(outDir, 'CloudCLISemantics.exe');
107
+
108
+ if (!(await ensureCommand('dotnet', '.NET SDK is required to compile the Windows helper.'))) {
109
+ process.exit(0);
110
+ }
111
+ if (await isUpToDate(output, [project, source])) {
112
+ console.log(`Semantic helper is up to date: ${path.relative(rootDir, output)}`);
113
+ process.exit(0);
114
+ }
115
+
116
+ await fs.mkdir(outDir, { recursive: true });
117
+ await run('dotnet', [
118
+ 'publish',
119
+ project,
120
+ '-c',
121
+ 'Release',
122
+ '-r',
123
+ arch === 'arm64' ? 'win-arm64' : 'win-x64',
124
+ '--self-contained',
125
+ 'false',
126
+ '-p:PublishSingleFile=true',
127
+ '-o',
128
+ outDir,
129
+ ]);
130
+ console.log(`Built ${path.relative(rootDir, output)}`);
131
+ } else {
132
+ console.log(`Semantic helper build is not supported for ${platform}-${arch}.`);
133
+ }