@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
@@ -346,6 +346,84 @@ export function createNormalizedMessage(fields: NormalizedMessageInput): Normali
346
346
  };
347
347
  }
348
348
 
349
+ /**
350
+ * Build the unified terminal `complete` lifecycle message.
351
+ *
352
+ * Contract: every provider run ends with exactly one `complete` (the
353
+ * abort-session handler emits it on behalf of cancelled runs, so aborted runs
354
+ * must NOT emit their own). The frontend treats `complete` as the only
355
+ * terminal signal and never needs provider-specific handling:
356
+ *
357
+ * - `sessionId` — the id the client knows this run by ('' if never discovered)
358
+ * - `actualSessionId` — canonical id after the run; equals `sessionId` unless
359
+ * the provider rewrote it mid-run
360
+ * - `exitCode` — 0 on success; a missing/null code (e.g. killed process)
361
+ * is reported as failure
362
+ * - `success` — exitCode === 0 and not aborted
363
+ * - `aborted` — run was cancelled by the user
364
+ */
365
+ export function createCompleteMessage(opts: {
366
+ provider: NormalizedMessage['provider'];
367
+ sessionId?: string | null;
368
+ actualSessionId?: string | null;
369
+ exitCode?: number | null;
370
+ aborted?: boolean;
371
+ }): NormalizedMessage {
372
+ const exitCode = typeof opts.exitCode === 'number' ? opts.exitCode : 1;
373
+ const aborted = Boolean(opts.aborted);
374
+
375
+ return createNormalizedMessage({
376
+ kind: 'complete',
377
+ provider: opts.provider,
378
+ sessionId: opts.sessionId || null,
379
+ actualSessionId: opts.actualSessionId || opts.sessionId || null,
380
+ exitCode,
381
+ success: exitCode === 0 && !aborted,
382
+ aborted,
383
+ });
384
+ }
385
+
386
+ // ---------------------------
387
+ //----------------- CONVERSATION HISTORY PAGINATION UTILITIES ------------
388
+ /**
389
+ * Slices one page from the END of a chronologically ordered message list.
390
+ *
391
+ * This is the single pagination contract for conversation history across all
392
+ * providers: `offset = 0` returns the most recent `limit` items, increasing
393
+ * offsets walk backwards in time (for "scroll up to load older" UIs), and a
394
+ * `null` limit returns everything. Items must already be sorted oldest-first;
395
+ * the returned page preserves that order.
396
+ *
397
+ * Every provider history reader must use this helper instead of slicing
398
+ * manually so `offset`/`limit` query params behave identically regardless of
399
+ * which provider produced the session.
400
+ */
401
+ export function sliceTailPage<T>(
402
+ items: T[],
403
+ limit: number | null,
404
+ offset: number,
405
+ ): { page: T[]; hasMore: boolean } {
406
+ const total = items.length;
407
+ const normalizedOffset = Math.max(0, offset);
408
+
409
+ if (limit === null) {
410
+ // A null limit returns the full list; offset still trims newest entries
411
+ // so "everything before the page I already have" stays expressible.
412
+ const end = Math.max(0, total - normalizedOffset);
413
+ return {
414
+ page: items.slice(0, end),
415
+ hasMore: false,
416
+ };
417
+ }
418
+
419
+ const end = Math.max(0, total - normalizedOffset);
420
+ const start = Math.max(0, end - Math.max(0, limit));
421
+ return {
422
+ page: items.slice(start, end),
423
+ hasMore: start > 0,
424
+ };
425
+ }
426
+
349
427
  // ---------------------------
350
428
  //----------------- MCP CONFIG PARSING UTILITIES ------------
351
429
  /**
@@ -879,9 +957,25 @@ export async function readProviderSkillMarkdownDefinition(
879
957
  skillPath: string,
880
958
  ): Promise<{ name: string; description: string }> {
881
959
  const content = await readFile(skillPath, 'utf8');
960
+ return readProviderSkillMarkdownDefinitionFromContent(
961
+ content,
962
+ path.basename(path.dirname(skillPath)),
963
+ );
964
+ }
965
+
966
+ /**
967
+ * Reads the `name` and `description` fields from raw skill markdown content.
968
+ *
969
+ * This keeps filesystem discovery and newly uploaded skill creation aligned on
970
+ * the same front matter parsing rules. `fallbackName` is used when the markdown
971
+ * omits a `name` field so callers still get a stable, non-empty skill id.
972
+ */
973
+ export function readProviderSkillMarkdownDefinitionFromContent(
974
+ content: string,
975
+ fallbackName: string,
976
+ ): { name: string; description: string } {
882
977
  const parsed = parseFrontMatter(content);
883
978
  const data = readObjectRecord(parsed.data) ?? {};
884
- const fallbackName = path.basename(path.dirname(skillPath));
885
979
 
886
980
  return {
887
981
  name: readOptionalString(data.name) ?? fallbackName,
@@ -0,0 +1,224 @@
1
+ // Optional voice proxy — forwards STT/TTS to an OpenAI-compatible audio backend.
2
+ //
3
+ // The backend is whatever the user points at: OpenAI, Groq, or a local server
4
+ // (LocalAI / Speaches / Kokoro-FastAPI / openedai-speech / etc.). It must expose the
5
+ // standard OpenAI audio endpoints:
6
+ // POST {base}/audio/transcriptions (multipart 'file' + 'model') -> { text }
7
+ // POST {base}/audio/speech ({ model, voice, input }) -> audio bytes
8
+ //
9
+ // Config is resolved per-request from headers (set by the client's voice settings),
10
+ // falling back to server env defaults. Mounted at /api/voice behind authenticateToken.
11
+ import { Readable } from 'node:stream';
12
+
13
+ import express from 'express';
14
+
15
+ const ENV = {
16
+ baseUrl: (process.env.VOICE_API_BASE_URL || '').replace(/\/$/, ''),
17
+ apiKey: process.env.VOICE_API_KEY || '',
18
+ sttModel: process.env.VOICE_STT_MODEL || 'whisper-1',
19
+ ttsModel: process.env.VOICE_TTS_MODEL || 'tts-1',
20
+ ttsVoice: process.env.VOICE_TTS_VOICE || 'alloy',
21
+ };
22
+
23
+ /**
24
+ * Resolve the voice backend config for a request. Client headers (set from the
25
+ * user's in-app voice settings) take precedence over the server env defaults.
26
+ * @param {import('express').Request} req
27
+ * @returns {{baseUrl: string, apiKey: string, sttModel: string, ttsModel: string, ttsVoice: string, ttsFormat: string}}
28
+ */
29
+ function resolveConfig(req) {
30
+ const h = req.headers;
31
+ return {
32
+ // Security: do not allow clients to control the outbound backend host.
33
+ // Always use the server-side configured base URL.
34
+ baseUrl: ENV.baseUrl,
35
+ apiKey: String(h['x-voice-api-key'] || '') || ENV.apiKey,
36
+ sttModel: String(h['x-voice-stt-model'] || '') || ENV.sttModel,
37
+ ttsModel: String(h['x-voice-tts-model'] || '') || ENV.ttsModel,
38
+ ttsVoice: String(h['x-voice-tts-voice'] || '') || ENV.ttsVoice,
39
+ ttsFormat: String(h['x-voice-tts-format'] || '').trim(),
40
+ };
41
+ }
42
+
43
+ const router = express.Router();
44
+
45
+ // Generous by default — local TTS can synthesize long messages at ~real-time on CPU.
46
+ // Guard against a non-numeric/zero override that would make setTimeout fire immediately.
47
+ const DEFAULT_VOICE_TIMEOUT_MS = 300000;
48
+ const _parsedTimeout = Number(process.env.VOICE_TIMEOUT_MS);
49
+ const VOICE_TIMEOUT_MS = Number.isFinite(_parsedTimeout) && _parsedTimeout > 0
50
+ ? _parsedTimeout
51
+ : DEFAULT_VOICE_TIMEOUT_MS;
52
+
53
+ /**
54
+ * fetch() with an AbortController timeout so a stalled backend can't hold the
55
+ * request open indefinitely. Aborts after VOICE_TIMEOUT_MS.
56
+ * @param {string} url
57
+ * @param {RequestInit} [options]
58
+ * @returns {Promise<Response>}
59
+ */
60
+ async function fetchWithTimeout(url, options = {}) {
61
+ const parsed = new URL(url);
62
+ if (!['http:', 'https:'].includes(parsed.protocol) || !isAllowedBackendUrl(parsed.origin)) {
63
+ throw new Error('Blocked outbound voice backend URL');
64
+ }
65
+ const controller = new AbortController();
66
+ const timer = setTimeout(() => controller.abort(), VOICE_TIMEOUT_MS);
67
+ try {
68
+ return await fetch(parsed.toString(), { redirect: 'manual', ...options, signal: controller.signal });
69
+ } finally {
70
+ clearTimeout(timer);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Turn a backend fetch failure into a clear, actionable client response:
76
+ * 504 on timeout (AbortError), 502 otherwise.
77
+ * @param {import('express').Response} res
78
+ * @param {Error} e
79
+ */
80
+ function backendError(res, e) {
81
+ if (e && e.name === 'AbortError') {
82
+ return res.status(504).json({
83
+ error: `Voice backend timed out after ${Math.round(VOICE_TIMEOUT_MS / 1000)}s. Check your voice backend.`,
84
+ });
85
+ }
86
+ return res.status(502).json({ error: `Voice backend unreachable: ${e.message}` });
87
+ }
88
+
89
+ /**
90
+ * SSRF guard for the user-configurable backend URL: allow http/https only and
91
+ * block the link-local / cloud-metadata range (169.254.x). localhost and private
92
+ * ranges are allowed on purpose so users can point at a local voice server
93
+ * (LocalAI, Speaches, Kokoro-FastAPI, etc.).
94
+ * @param {string} raw
95
+ * @returns {boolean}
96
+ */
97
+ function isAllowedBackendUrl(raw) {
98
+ let u;
99
+ try {
100
+ u = new URL(raw);
101
+ } catch {
102
+ return false;
103
+ }
104
+ if (u.protocol !== 'http:' && u.protocol !== 'https:') return false;
105
+ if (u.hostname === '169.254.169.254' || u.hostname.startsWith('169.254.')) return false;
106
+ return true;
107
+ }
108
+
109
+ /**
110
+ * Relay an upstream (backend) error to the client without making an upstream
111
+ * 401/403 look like the user's own app login failed.
112
+ * @param {import('express').Response} res
113
+ * @param {number} status
114
+ * @param {string} [text]
115
+ */
116
+ function upstreamError(res, status, text) {
117
+ if (status === 401 || status === 403) {
118
+ return res.status(502).json({ error: 'Voice backend rejected the request (check the API key).' });
119
+ }
120
+ return res.status(status).json({ error: text || 'voice backend error' });
121
+ }
122
+
123
+ let _upload = null;
124
+ /**
125
+ * Lazily build a memory-storage multer instance (25 MB cap) for audio uploads,
126
+ * so multer is only imported when the voice feature is actually used.
127
+ * @returns {Promise<import('multer').Multer>}
128
+ */
129
+ async function getUpload() {
130
+ if (!_upload) {
131
+ const multer = (await import('multer')).default;
132
+ _upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 25 * 1024 * 1024 } });
133
+ }
134
+ return _upload;
135
+ }
136
+
137
+ /**
138
+ * Build the Authorization header for the backend, or an empty object when no
139
+ * key is configured (e.g. a local server that needs none).
140
+ * @param {string} apiKey
141
+ * @returns {Record<string, string>}
142
+ */
143
+ function authHeader(apiKey) {
144
+ return apiKey ? { Authorization: `Bearer ${apiKey}` } : {};
145
+ }
146
+
147
+ /**
148
+ * GET /api/voice/health -> { configured } (true when a backend base URL is set).
149
+ */
150
+ router.get('/health', (req, res) => {
151
+ res.json({ configured: Boolean(resolveConfig(req).baseUrl) });
152
+ });
153
+
154
+ /**
155
+ * POST /api/voice/transcribe (multipart 'audio') -> { text }.
156
+ * Forwards the uploaded audio to the backend's /audio/transcriptions endpoint.
157
+ */
158
+ router.post('/transcribe', async (req, res) => {
159
+ const cfg = resolveConfig(req);
160
+ if (!cfg.baseUrl) return res.status(503).json({ error: 'No voice backend configured' });
161
+ if (!isAllowedBackendUrl(cfg.baseUrl)) return res.status(400).json({ error: 'Invalid voice backend URL.' });
162
+ const upload = await getUpload();
163
+ upload.single('audio')(req, res, async (err) => {
164
+ if (err) return res.status(400).json({ error: err.message });
165
+ if (!req.file) return res.status(400).json({ error: 'No audio uploaded' });
166
+ try {
167
+ const fd = new FormData();
168
+ fd.append(
169
+ 'file',
170
+ new Blob([req.file.buffer], { type: req.file.mimetype || 'audio/webm' }),
171
+ req.file.originalname || 'recording.webm',
172
+ );
173
+ fd.append('model', cfg.sttModel);
174
+ const r = await fetchWithTimeout(`${cfg.baseUrl}/audio/transcriptions`, {
175
+ method: 'POST',
176
+ headers: authHeader(cfg.apiKey),
177
+ body: fd,
178
+ });
179
+ const text = await r.text();
180
+ if (!r.ok) return upstreamError(res, r.status, text);
181
+ let data;
182
+ try { data = JSON.parse(text); } catch { data = { text }; }
183
+ res.json({ text: data.text ?? '' });
184
+ } catch (e) {
185
+ backendError(res, e);
186
+ }
187
+ });
188
+ });
189
+
190
+ /**
191
+ * POST /api/voice/tts { text } -> audio bytes.
192
+ * Forwards the text to the backend's /audio/speech endpoint and streams the audio back.
193
+ */
194
+ router.post('/tts', async (req, res) => {
195
+ const cfg = resolveConfig(req);
196
+ if (!cfg.baseUrl) return res.status(503).json({ error: 'No voice backend configured' });
197
+ if (!isAllowedBackendUrl(cfg.baseUrl)) return res.status(400).json({ error: 'Invalid voice backend URL.' });
198
+ const text = req.body?.text;
199
+ if (typeof text !== 'string' || !text.trim()) return res.status(400).json({ error: 'text required' });
200
+ try {
201
+ const r = await fetchWithTimeout(`${cfg.baseUrl}/audio/speech`, {
202
+ method: 'POST',
203
+ headers: { 'Content-Type': 'application/json', ...authHeader(cfg.apiKey) },
204
+ body: JSON.stringify({
205
+ model: cfg.ttsModel,
206
+ voice: cfg.ttsVoice,
207
+ input: text,
208
+ ...(cfg.ttsFormat ? { response_format: cfg.ttsFormat } : {}),
209
+ }),
210
+ });
211
+ if (!r.ok) {
212
+ const errText = await r.text().catch(() => 'tts failed');
213
+ return upstreamError(res, r.status, errText);
214
+ }
215
+ res.setHeader('Content-Type', r.headers.get('content-type') || 'audio/mpeg');
216
+ res.setHeader('Cache-Control', 'no-store');
217
+ if (!r.body) return res.end();
218
+ Readable.fromWeb(r.body).on('error', (error) => res.destroy(error)).pipe(res);
219
+ } catch (e) {
220
+ backendError(res, e);
221
+ }
222
+ });
223
+
224
+ export default router;