@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
@@ -1,5 +1,5 @@
1
1
  import assert from 'node:assert/strict';
2
- import { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises';
2
+ import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import test from 'node:test';
@@ -12,6 +12,11 @@ const findEnvKey = (name) =>
12
12
  async function createFakeOpenCodeExecutable(binDir) {
13
13
  const scriptPath = path.join(binDir, 'opencode.js');
14
14
  await writeFile(scriptPath, `
15
+ const capturePath = process.env.OPENCODE_ARGS_CAPTURE;
16
+ if (capturePath) {
17
+ require('node:fs').writeFileSync(capturePath, JSON.stringify(process.argv.slice(2)));
18
+ }
19
+
15
20
  const events = [
16
21
  { type: 'text', sessionID: 'open-live-1', text: 'assistant response' },
17
22
  { type: 'step_finish', sessionID: 'open-live-1' },
@@ -35,10 +40,12 @@ for (const event of events) {
35
40
 
36
41
  test('spawnOpenCode emits session_created before normalized live messages for new sessions', async () => {
37
42
  const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'opencode-cli-live-'));
43
+ const argsCapturePath = path.join(tempRoot, 'opencode-args.json');
38
44
  const pathKey = findEnvKey('PATH');
39
45
  const pathExtKey = findEnvKey('PATHEXT');
40
46
  const previousPath = process.env[pathKey];
41
47
  const previousPathExt = process.env[pathExtKey];
48
+ const previousArgsCapture = process.env.OPENCODE_ARGS_CAPTURE;
42
49
  const messages = [];
43
50
  const writer = {
44
51
  userId: null,
@@ -54,6 +61,7 @@ test('spawnOpenCode emits session_created before normalized live messages for ne
54
61
  try {
55
62
  await createFakeOpenCodeExecutable(tempRoot);
56
63
  process.env[pathKey] = `${tempRoot}${path.delimiter}${previousPath || ''}`;
64
+ process.env.OPENCODE_ARGS_CAPTURE = argsCapturePath;
57
65
  if (process.platform === 'win32') {
58
66
  process.env[pathExtKey] = previousPathExt?.toUpperCase().includes('.CMD')
59
67
  ? previousPathExt
@@ -77,6 +85,11 @@ test('spawnOpenCode emits session_created before normalized live messages for ne
77
85
  assert.equal(streamEnd?.sessionId, 'open-live-1');
78
86
  assert.equal(complete?.sessionId, 'open-live-1');
79
87
  assert.equal(messages.some((message) => message.kind === 'error'), false);
88
+
89
+ const launchedArgs = JSON.parse(await readFile(argsCapturePath, 'utf8'));
90
+ assert.ok(Array.isArray(launchedArgs));
91
+ assert.deepEqual(launchedArgs.slice(0, 4), ['run', '--format', 'json', '--dir']);
92
+ assert.equal(launchedArgs[4], tempRoot);
80
93
  } finally {
81
94
  if (previousPath === undefined) {
82
95
  delete process.env[pathKey];
@@ -90,6 +103,12 @@ test('spawnOpenCode emits session_created before normalized live messages for ne
90
103
  process.env[pathExtKey] = previousPathExt;
91
104
  }
92
105
 
106
+ if (previousArgsCapture === undefined) {
107
+ delete process.env.OPENCODE_ARGS_CAPTURE;
108
+ } else {
109
+ process.env.OPENCODE_ARGS_CAPTURE = previousArgsCapture;
110
+ }
111
+
93
112
  await rm(tempRoot, { recursive: true, force: true });
94
113
  }
95
114
  });
@@ -646,7 +646,7 @@ class ResponseCollector {
646
646
  *
647
647
  * @param {string} model - (Optional) Model identifier for providers.
648
648
  *
649
- * Claude models: 'sonnet' (default), 'opus', 'haiku', 'opusplan', 'sonnet[1m]'
649
+ * Claude models: 'sonnet' (default), 'opus', 'haiku', 'opusplan', 'sonnet[1m]', 'fable'
650
650
  * Cursor models: 'gpt-5' (default), 'gpt-5.2', 'gpt-5.2-high', 'sonnet-4.5', 'opus-4.5',
651
651
  * 'gemini-3-pro', 'composer-1', 'auto', 'gpt-5.1', 'gpt-5.1-high',
652
652
  * 'gpt-5.1-codex', 'gpt-5.1-codex-high', 'gpt-5.1-codex-max',
@@ -1,6 +1,11 @@
1
1
  import express from 'express';
2
2
 
3
- import { apiKeysDb, credentialsDb, notificationPreferencesDb, pushSubscriptionsDb } from '../modules/database/index.js';
3
+ import {
4
+ apiKeysDb,
5
+ credentialsDb,
6
+ notificationPreferencesDb,
7
+ pushSubscriptionsDb,
8
+ } from '../modules/database/index.js';
4
9
  import { getPublicKey } from '../services/vapid-keys.js';
5
10
  import { createNotificationEvent, notifyUserIfEnabled } from '../services/notification-orchestrator.js';
6
11
 
@@ -1,228 +1,7 @@
1
- import webPush from 'web-push';
2
-
3
- import { notificationPreferencesDb, pushSubscriptionsDb, sessionsDb } from '../modules/database/index.js';
4
-
5
- const KIND_TO_PREF_KEY = {
6
- action_required: 'actionRequired',
7
- stop: 'stop',
8
- error: 'error'
9
- };
10
-
11
- const PROVIDER_LABELS = {
12
- claude: 'Claude',
13
- cursor: 'Cursor',
14
- codex: 'Codex',
15
- gemini: 'Gemini',
16
- system: 'System'
17
- };
18
-
19
- const recentEventKeys = new Map();
20
- const DEDUPE_WINDOW_MS = 20000;
21
-
22
- const cleanupOldEventKeys = () => {
23
- const now = Date.now();
24
- for (const [key, timestamp] of recentEventKeys.entries()) {
25
- if (now - timestamp > DEDUPE_WINDOW_MS) {
26
- recentEventKeys.delete(key);
27
- }
28
- }
29
- };
30
-
31
- function shouldSendPush(preferences, event) {
32
- const webPushEnabled = Boolean(preferences?.channels?.webPush);
33
- const prefEventKey = KIND_TO_PREF_KEY[event.kind];
34
- const eventEnabled = prefEventKey ? Boolean(preferences?.events?.[prefEventKey]) : true;
35
-
36
- return webPushEnabled && eventEnabled;
37
- }
38
-
39
- function isDuplicate(event) {
40
- cleanupOldEventKeys();
41
- const key = event.dedupeKey || `${event.provider}:${event.kind || 'info'}:${event.code || 'generic'}:${event.sessionId || 'none'}`;
42
- if (recentEventKeys.has(key)) {
43
- return true;
44
- }
45
- recentEventKeys.set(key, Date.now());
46
- return false;
47
- }
48
-
49
- function createNotificationEvent({
50
- provider,
51
- sessionId = null,
52
- kind = 'info',
53
- code = 'generic.info',
54
- meta = {},
55
- severity = 'info',
56
- dedupeKey = null,
57
- requiresUserAction = false
58
- }) {
59
- return {
60
- provider,
61
- sessionId,
62
- kind,
63
- code,
64
- meta,
65
- severity,
66
- requiresUserAction,
67
- dedupeKey,
68
- createdAt: new Date().toISOString()
69
- };
70
- }
71
-
72
- function normalizeErrorMessage(error) {
73
- if (typeof error === 'string') {
74
- return error;
75
- }
76
-
77
- if (error && typeof error.message === 'string') {
78
- return error.message;
79
- }
80
-
81
- if (error == null) {
82
- return 'Unknown error';
83
- }
84
-
85
- return String(error);
86
- }
87
-
88
- function normalizeSessionName(sessionName) {
89
- if (typeof sessionName !== 'string') {
90
- return null;
91
- }
92
-
93
- const normalized = sessionName.replace(/\s+/g, ' ').trim();
94
- if (!normalized) {
95
- return null;
96
- }
97
-
98
- return normalized.length > 80 ? `${normalized.slice(0, 77)}...` : normalized;
99
- }
100
-
101
- function resolveSessionName(event) {
102
- const explicitSessionName = normalizeSessionName(event.meta?.sessionName);
103
- if (explicitSessionName) {
104
- return explicitSessionName;
105
- }
106
-
107
- if (!event.sessionId || !event.provider) {
108
- return null;
109
- }
110
-
111
- return normalizeSessionName(sessionsDb.getSessionName(event.sessionId, event.provider));
112
- }
113
-
114
- function buildPushBody(event) {
115
- const CODE_MAP = {
116
- 'permission.required': event.meta?.toolName
117
- ? `Action Required: Tool "${event.meta.toolName}" needs approval`
118
- : 'Action Required: A tool needs your approval',
119
- 'run.stopped': event.meta?.stopReason || 'Run Stopped: The run has stopped',
120
- 'run.failed': event.meta?.error ? `Run Failed: ${event.meta.error}` : 'Run Failed: The run encountered an error',
121
- 'agent.notification': event.meta?.message ? String(event.meta.message) : 'You have a new notification',
122
- 'push.enabled': 'Push notifications are now enabled!'
123
- };
124
- const providerLabel = PROVIDER_LABELS[event.provider] || 'Assistant';
125
- const sessionName = resolveSessionName(event);
126
- const message = CODE_MAP[event.code] || 'You have a new notification';
127
-
128
- return {
129
- title: sessionName || 'CloudCLI',
130
- body: `${providerLabel}: ${message}`,
131
- data: {
132
- sessionId: event.sessionId || null,
133
- code: event.code,
134
- provider: event.provider || null,
135
- sessionName,
136
- tag: `${event.provider || 'assistant'}:${event.sessionId || 'none'}:${event.code}`
137
- }
138
- };
139
- }
140
-
141
- async function sendWebPush(userId, event) {
142
- const subscriptions = pushSubscriptionsDb.getSubscriptions(userId);
143
- if (!subscriptions.length) return;
144
-
145
- const payload = JSON.stringify(buildPushBody(event));
146
-
147
- const results = await Promise.allSettled(
148
- subscriptions.map((sub) =>
149
- webPush.sendNotification(
150
- {
151
- endpoint: sub.endpoint,
152
- keys: {
153
- p256dh: sub.keys_p256dh,
154
- auth: sub.keys_auth
155
- }
156
- },
157
- payload
158
- )
159
- )
160
- );
161
-
162
- // Clean up gone subscriptions (410 Gone or 404)
163
- results.forEach((result, index) => {
164
- if (result.status === 'rejected') {
165
- const statusCode = result.reason?.statusCode;
166
- if (statusCode === 410 || statusCode === 404) {
167
- pushSubscriptionsDb.removeSubscription(subscriptions[index].endpoint);
168
- }
169
- }
170
- });
171
- }
172
-
173
- function notifyUserIfEnabled({ userId, event }) {
174
- if (!userId || !event) {
175
- return;
176
- }
177
-
178
- const preferences = notificationPreferencesDb.getPreferences(userId);
179
- if (!shouldSendPush(preferences, event)) {
180
- return;
181
- }
182
- if (isDuplicate(event)) {
183
- return;
184
- }
185
-
186
- sendWebPush(userId, event).catch((err) => {
187
- console.error('Web push send error:', err);
188
- });
189
- }
190
-
191
- function notifyRunStopped({ userId, provider, sessionId = null, stopReason = 'completed', sessionName = null }) {
192
- notifyUserIfEnabled({
193
- userId,
194
- event: createNotificationEvent({
195
- provider,
196
- sessionId,
197
- kind: 'stop',
198
- code: 'run.stopped',
199
- meta: { stopReason, sessionName },
200
- severity: 'info',
201
- dedupeKey: `${provider}:run:stop:${sessionId || 'none'}:${stopReason}`
202
- })
203
- });
204
- }
205
-
206
- function notifyRunFailed({ userId, provider, sessionId = null, error, sessionName = null }) {
207
- const errorMessage = normalizeErrorMessage(error);
208
-
209
- notifyUserIfEnabled({
210
- userId,
211
- event: createNotificationEvent({
212
- provider,
213
- sessionId,
214
- kind: 'error',
215
- code: 'run.failed',
216
- meta: { error: errorMessage, sessionName },
217
- severity: 'error',
218
- dedupeKey: `${provider}:run:error:${sessionId || 'none'}:${errorMessage}`
219
- })
220
- });
221
- }
222
-
223
1
  export {
2
+ buildNotificationPayload,
224
3
  createNotificationEvent,
225
4
  notifyUserIfEnabled,
226
5
  notifyRunStopped,
227
- notifyRunFailed
228
- };
6
+ notifyRunFailed,
7
+ } from '../modules/notifications/services/notification-orchestrator.service.js';
@@ -0,0 +1,80 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtemp, rm } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import path from 'node:path';
5
+ import test from 'node:test';
6
+
7
+ import webPush from 'web-push';
8
+
9
+ import {
10
+ closeConnection,
11
+ initializeDatabase,
12
+ notificationPreferencesDb,
13
+ pushSubscriptionsDb,
14
+ sessionsDb,
15
+ userDb,
16
+ } from '../../modules/database/index.js';
17
+
18
+ import { notifyRunStopped } from '../notification-orchestrator.js';
19
+
20
+ async function withIsolatedDatabase(runTest) {
21
+ const previousDatabasePath = process.env.DATABASE_PATH;
22
+ const tempDirectory = await mkdtemp(path.join(tmpdir(), 'notification-orchestrator-'));
23
+ const databasePath = path.join(tempDirectory, 'auth.db');
24
+
25
+ closeConnection();
26
+ process.env.DATABASE_PATH = databasePath;
27
+ await initializeDatabase();
28
+
29
+ try {
30
+ await runTest();
31
+ } finally {
32
+ closeConnection();
33
+ if (previousDatabasePath === undefined) {
34
+ delete process.env.DATABASE_PATH;
35
+ } else {
36
+ process.env.DATABASE_PATH = previousDatabasePath;
37
+ }
38
+ await rm(tempDirectory, { recursive: true, force: true });
39
+ }
40
+ }
41
+
42
+ test('push payload uses the app session id when notified with a provider session id', async () => {
43
+ const originalSendNotification = webPush.sendNotification;
44
+ const sentPayloads = [];
45
+
46
+ webPush.sendNotification = async (_subscription, payload) => {
47
+ sentPayloads.push(JSON.parse(payload));
48
+ return {};
49
+ };
50
+
51
+ try {
52
+ await withIsolatedDatabase(async () => {
53
+ const user = userDb.createUser('notify-user', 'hash');
54
+ const userId = Number(user.id);
55
+
56
+ notificationPreferencesDb.updatePreferences(userId, {
57
+ channels: { webPush: true },
58
+ events: { actionRequired: true, stop: true, error: true },
59
+ });
60
+ pushSubscriptionsDb.saveSubscription(userId, 'https://example.test/push', 'p256dh', 'auth');
61
+ sessionsDb.createAppSession('app-session-1', 'claude', '/workspace/demo');
62
+ sessionsDb.assignProviderSessionId('app-session-1', 'claude-native-1');
63
+
64
+ notifyRunStopped({
65
+ userId,
66
+ provider: 'claude',
67
+ sessionId: 'claude-native-1',
68
+ stopReason: 'completed',
69
+ });
70
+
71
+ await new Promise((resolve) => setImmediate(resolve));
72
+
73
+ assert.equal(sentPayloads.length, 1);
74
+ assert.equal(sentPayloads[0]?.data?.sessionId, 'app-session-1');
75
+ assert.match(sentPayloads[0]?.data?.tag, /app-session-1/);
76
+ });
77
+ } finally {
78
+ webPush.sendNotification = originalSendNotification;
79
+ }
80
+ });
@@ -12,6 +12,8 @@ import type {
12
12
  ProviderModelsDefinition,
13
13
  ProviderMcpServer,
14
14
  ProviderSessionActiveModelChange,
15
+ ProviderSkillCreateInput,
16
+ ProviderSkillRemoveInput,
15
17
  UpsertProviderMcpServerInput,
16
18
  } from '@/shared/types.js';
17
19
 
@@ -101,6 +103,19 @@ export interface IProviderSkills {
101
103
  * Lists all skills visible to this provider for the optional workspace.
102
104
  */
103
105
  listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]>;
106
+
107
+ /**
108
+ * Writes one or more global user-scoped skills for this provider.
109
+ *
110
+ * Implementations should install the supplied markdown entries into the
111
+ * provider's writable user skill folder and return the normalized skill
112
+ * records that were written.
113
+ */
114
+ addSkills(input: ProviderSkillCreateInput): Promise<ProviderSkill[]>;
115
+
116
+ removeSkill(
117
+ input: ProviderSkillRemoveInput,
118
+ ): Promise<{ removed: boolean; provider: LLMProvider; directoryName: string }>;
104
119
  }
105
120
 
106
121
  // ---------------------------
@@ -0,0 +1,42 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { sliceTailPage } from '@/shared/utils.js';
5
+
6
+ const ITEMS = ['a', 'b', 'c', 'd', 'e'];
7
+
8
+ test('offset 0 returns the most recent page', () => {
9
+ const { page, hasMore } = sliceTailPage(ITEMS, 2, 0);
10
+ assert.deepEqual(page, ['d', 'e']);
11
+ assert.equal(hasMore, true);
12
+ });
13
+
14
+ test('increasing offsets walk backwards in time', () => {
15
+ const { page, hasMore } = sliceTailPage(ITEMS, 2, 2);
16
+ assert.deepEqual(page, ['b', 'c']);
17
+ assert.equal(hasMore, true);
18
+ });
19
+
20
+ test('the oldest page reports hasMore false', () => {
21
+ const { page, hasMore } = sliceTailPage(ITEMS, 2, 4);
22
+ assert.deepEqual(page, ['a']);
23
+ assert.equal(hasMore, false);
24
+ });
25
+
26
+ test('null limit returns everything', () => {
27
+ const { page, hasMore } = sliceTailPage(ITEMS, null, 0);
28
+ assert.deepEqual(page, ITEMS);
29
+ assert.equal(hasMore, false);
30
+ });
31
+
32
+ test('offsets past the start return an empty page', () => {
33
+ const { page, hasMore } = sliceTailPage(ITEMS, 3, 10);
34
+ assert.deepEqual(page, []);
35
+ assert.equal(hasMore, false);
36
+ });
37
+
38
+ test('zero limit returns an empty page but keeps hasMore accurate', () => {
39
+ const { page, hasMore } = sliceTailPage(ITEMS, 0, 0);
40
+ assert.deepEqual(page, []);
41
+ assert.equal(hasMore, true);
42
+ });
@@ -68,7 +68,7 @@ export type AuthenticatedWebSocketRequest = IncomingMessage & {
68
68
  export type LLMProvider = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode';
69
69
 
70
70
  /**
71
- * One selectable model row (matches the documentation `public/modelConstants.js` option shape).
71
+ * One selectable model row in a provider model catalog.
72
72
  */
73
73
  export type ProviderModelOption = {
74
74
  value: string;
@@ -175,6 +175,30 @@ export type MessageKind =
175
175
  | 'interactive_prompt'
176
176
  | 'task_notification';
177
177
 
178
+ /**
179
+ * Event kinds added by the chat gateway layer on top of provider message kinds.
180
+ *
181
+ * These are app-level realtime events (subscription acks, sidebar deltas,
182
+ * project loading progress, protocol failures) that are not produced by any
183
+ * provider adapter. Together with `MessageKind` they form the complete set of
184
+ * `kind` values a websocket client can receive, so the frontend only ever
185
+ * needs one kind-based switch.
186
+ */
187
+ export type GatewayEventKind =
188
+ | 'chat_subscribed'
189
+ | 'session_upserted'
190
+ | 'loading_progress'
191
+ | 'protocol_error';
192
+
193
+ /**
194
+ * Complete set of `kind` values emitted to websocket clients.
195
+ *
196
+ * Every server-to-client websocket frame carries a `kind` from this union.
197
+ * Provider runtimes emit `MessageKind` values; gateway services emit
198
+ * `GatewayEventKind` values.
199
+ */
200
+ export type ServerEventKind = MessageKind | GatewayEventKind;
201
+
178
202
  /**
179
203
  * Provider-neutral message envelope used in REST responses and realtime channels.
180
204
  *
@@ -187,6 +211,13 @@ export type NormalizedMessage = {
187
211
  timestamp: string;
188
212
  provider: LLMProvider;
189
213
  kind: MessageKind;
214
+ /**
215
+ * Monotonic per-run sequence number assigned by the chat run registry when a
216
+ * live event is forwarded to the websocket. History messages loaded over
217
+ * REST do not carry it. Clients use it with `chat.subscribe` to replay only
218
+ * the live events they missed across websocket reconnects.
219
+ */
220
+ seq?: number;
190
221
  role?: 'user' | 'assistant';
191
222
  content?: string;
192
223
  /**
@@ -237,11 +268,18 @@ export type NormalizedMessage = {
237
268
  *
238
269
  * Consumers should pass provider-specific lookup hints (`projectPath`) only
239
270
  * when the selected provider requires them.
271
+ *
272
+ * `providerSessionId` is the provider-native session id from the sessions
273
+ * index (transcript file name / provider database key). Provider adapters
274
+ * must use it — never the app-facing session id they were called with — when
275
+ * matching transcript rows on disk, because app-created sessions use an
276
+ * app-allocated id that the provider has never seen.
240
277
  */
241
278
  export type FetchHistoryOptions = {
242
279
  projectPath?: string;
243
280
  limit?: number | null;
244
281
  offset?: number;
282
+ providerSessionId?: string;
245
283
  };
246
284
 
247
285
  /**
@@ -282,6 +320,51 @@ export type ProviderSkillListOptions = {
282
320
  workspacePath?: string;
283
321
  };
284
322
 
323
+ /**
324
+ * One supporting file bundled with an uploaded provider skill.
325
+ *
326
+ * `relativePath` is resolved below the installed skill directory and must never
327
+ * be absolute or contain traversal segments. Text files may use `utf8`; binary
328
+ * scripts and assets should use `base64` so JSON transport does not corrupt
329
+ * their bytes.
330
+ */
331
+ export type ProviderSkillCreateFile = {
332
+ relativePath: string;
333
+ content: string;
334
+ encoding: 'utf8' | 'base64';
335
+ };
336
+
337
+ /**
338
+ * One skill markdown payload submitted for provider-managed installation.
339
+ *
340
+ * `content` is the raw markdown body that will be written to `SKILL.md`.
341
+ * `directoryName` lets callers control the target folder name explicitly when
342
+ * they want stable filesystem paths that differ from the markdown front matter
343
+ * `name` field. `fileName` is optional upload metadata used only as a final
344
+ * fallback when no directory name or front matter name is present. `files`
345
+ * carries scripts, references, and other files from a complete skill folder.
346
+ */
347
+ export type ProviderSkillCreateEntry = {
348
+ content: string;
349
+ directoryName?: string;
350
+ fileName?: string;
351
+ files?: ProviderSkillCreateFile[];
352
+ };
353
+
354
+ /**
355
+ * Shared input accepted by provider skill creation operations.
356
+ *
357
+ * The service layer batches multiple skill definitions in one request. Each
358
+ * entry can contain only markdown or a complete skill folder.
359
+ */
360
+ export type ProviderSkillCreateInput = {
361
+ entries: ProviderSkillCreateEntry[];
362
+ };
363
+
364
+ export type ProviderSkillRemoveInput = {
365
+ directoryName: string;
366
+ };
367
+
285
368
  /**
286
369
  * Normalized skill record returned by provider skill adapters.
287
370
  *