@cloudcli-ai/cloudcli 1.36.3 → 1.37.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 (535) hide show
  1. package/dist/assets/index-DSlds633.css +32 -0
  2. package/dist/assets/{index-CcCsKitq.js → index-eGqPeIEu.js} +375 -267
  3. package/dist/index.html +2 -2
  4. package/dist-server/server/constants/config.js.map +1 -1
  5. package/dist-server/server/index.js +73 -1224
  6. package/dist-server/server/index.js.map +1 -1
  7. package/dist-server/server/load-env.js +17 -4
  8. package/dist-server/server/load-env.js.map +1 -1
  9. package/dist-server/server/modules/agent/agent.module.js +37 -0
  10. package/dist-server/server/modules/agent/agent.module.js.map +1 -0
  11. package/dist-server/server/modules/agent/agent.routes.js +1161 -0
  12. package/dist-server/server/modules/agent/agent.routes.js.map +1 -0
  13. package/dist-server/server/modules/agent/index.js +3 -0
  14. package/dist-server/server/modules/agent/index.js.map +1 -0
  15. package/dist-server/server/modules/agent/tests/agent.routes.test.js +176 -0
  16. package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -0
  17. package/dist-server/server/modules/assets/assets.routes.js +56 -15
  18. package/dist-server/server/modules/assets/assets.routes.js.map +1 -1
  19. package/dist-server/server/modules/assets/index.js +2 -2
  20. package/dist-server/server/modules/assets/index.js.map +1 -1
  21. package/dist-server/server/modules/assets/services/image-assets.service.js +39 -1
  22. package/dist-server/server/modules/assets/services/image-assets.service.js.map +1 -1
  23. package/dist-server/server/modules/assets/tests/image-assets.service.test.js +21 -1
  24. package/dist-server/server/modules/assets/tests/image-assets.service.test.js.map +1 -1
  25. package/dist-server/server/{middleware/auth.js → modules/auth/auth.middleware.js} +30 -8
  26. package/dist-server/server/modules/auth/auth.middleware.js.map +1 -0
  27. package/dist-server/server/modules/auth/auth.module.js +29 -0
  28. package/dist-server/server/modules/auth/auth.module.js.map +1 -0
  29. package/dist-server/server/modules/auth/auth.routes.js +45 -0
  30. package/dist-server/server/modules/auth/auth.routes.js.map +1 -0
  31. package/dist-server/server/modules/auth/auth.service.js +113 -0
  32. package/dist-server/server/modules/auth/auth.service.js.map +1 -0
  33. package/dist-server/server/modules/auth/index.js +9 -0
  34. package/dist-server/server/modules/auth/index.js.map +1 -0
  35. package/dist-server/server/modules/auth/tests/auth.service.test.js +80 -0
  36. package/dist-server/server/modules/auth/tests/auth.service.test.js.map +1 -0
  37. package/dist-server/server/{browser-use-mcp.js → modules/browser-use/browser-use-mcp.js} +3 -1
  38. package/dist-server/server/modules/browser-use/browser-use-mcp.js.map +1 -0
  39. package/dist-server/server/modules/browser-use/browser-use.service.js +3 -4
  40. package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
  41. package/dist-server/server/modules/browser-use/index.js +9 -0
  42. package/dist-server/server/modules/browser-use/index.js.map +1 -0
  43. package/dist-server/server/modules/cli/cli.js +11 -0
  44. package/dist-server/server/modules/cli/cli.js.map +1 -0
  45. package/dist-server/server/modules/cli/cli.module.js +86 -0
  46. package/dist-server/server/modules/cli/cli.module.js.map +1 -0
  47. package/dist-server/server/modules/cli/cli.service.js +244 -0
  48. package/dist-server/server/modules/cli/cli.service.js.map +1 -0
  49. package/dist-server/server/modules/cli/index.js +3 -0
  50. package/dist-server/server/modules/cli/index.js.map +1 -0
  51. package/dist-server/server/modules/cli/sandbox.service.js +332 -0
  52. package/dist-server/server/modules/cli/sandbox.service.js.map +1 -0
  53. package/dist-server/server/modules/cli/tests/cli.service.test.js +78 -0
  54. package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -0
  55. package/dist-server/server/modules/cli/tests/sandbox.service.test.js +55 -0
  56. package/dist-server/server/modules/cli/tests/sandbox.service.test.js.map +1 -0
  57. package/dist-server/server/modules/commands/commands.module.js +20 -0
  58. package/dist-server/server/modules/commands/commands.module.js.map +1 -0
  59. package/dist-server/server/modules/commands/commands.routes.js +497 -0
  60. package/dist-server/server/modules/commands/commands.routes.js.map +1 -0
  61. package/dist-server/server/modules/commands/index.js +3 -0
  62. package/dist-server/server/modules/commands/index.js.map +1 -0
  63. package/dist-server/server/modules/commands/tests/commands.test.js +96 -0
  64. package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -0
  65. package/dist-server/server/modules/database/index.js +1 -0
  66. package/dist-server/server/modules/database/index.js.map +1 -1
  67. package/dist-server/server/modules/database/migrations.js +13 -0
  68. package/dist-server/server/modules/database/migrations.js.map +1 -1
  69. package/dist-server/server/modules/database/repositories/sessions.db.js +14 -1
  70. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  71. package/dist-server/server/modules/database/schema.js +4 -0
  72. package/dist-server/server/modules/database/schema.js.map +1 -1
  73. package/dist-server/server/modules/file-tree/file-tree.module.js +91 -0
  74. package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -0
  75. package/dist-server/server/modules/file-tree/file-tree.routes.js +208 -0
  76. package/dist-server/server/modules/file-tree/file-tree.routes.js.map +1 -0
  77. package/dist-server/server/modules/file-tree/file-tree.service.js +544 -0
  78. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -0
  79. package/dist-server/server/modules/file-tree/index.js +3 -0
  80. package/dist-server/server/modules/file-tree/index.js.map +1 -0
  81. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js +123 -0
  82. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js.map +1 -0
  83. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +184 -0
  84. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -0
  85. package/dist-server/server/modules/git/git-parsing.service.js +61 -0
  86. package/dist-server/server/modules/git/git-parsing.service.js.map +1 -0
  87. package/dist-server/server/modules/git/git.module.js +14 -0
  88. package/dist-server/server/modules/git/git.module.js.map +1 -0
  89. package/dist-server/server/modules/git/git.routes.js +1339 -0
  90. package/dist-server/server/modules/git/git.routes.js.map +1 -0
  91. package/dist-server/server/modules/git/index.js +3 -0
  92. package/dist-server/server/modules/git/index.js.map +1 -0
  93. package/dist-server/server/modules/git/tests/git-init.routes.test.js +48 -0
  94. package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -0
  95. package/dist-server/server/{routes → modules/git/tests}/git.test.js +1 -1
  96. package/dist-server/server/modules/git/tests/git.test.js.map +1 -0
  97. package/dist-server/server/modules/notifications/index.js +15 -1
  98. package/dist-server/server/modules/notifications/index.js.map +1 -1
  99. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js +44 -0
  100. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js.map +1 -0
  101. package/dist-server/server/{services/vapid-keys.js → modules/notifications/vapid-keys.service.js} +3 -2
  102. package/dist-server/server/modules/notifications/vapid-keys.service.js.map +1 -0
  103. package/dist-server/server/modules/plugins/index.js +9 -0
  104. package/dist-server/server/modules/plugins/index.js.map +1 -0
  105. package/dist-server/server/{utils/plugin-process-manager.js → modules/plugins/plugin-process.service.js} +3 -2
  106. package/dist-server/server/modules/plugins/plugin-process.service.js.map +1 -0
  107. package/dist-server/server/{utils/plugin-loader.js → modules/plugins/plugin-registry.service.js} +2 -1
  108. package/dist-server/server/modules/plugins/plugin-registry.service.js.map +1 -0
  109. package/dist-server/server/modules/plugins/plugins.module.js +30 -0
  110. package/dist-server/server/modules/plugins/plugins.module.js.map +1 -0
  111. package/dist-server/server/modules/plugins/plugins.routes.js +70 -0
  112. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -0
  113. package/dist-server/server/modules/plugins/plugins.service.js +123 -0
  114. package/dist-server/server/modules/plugins/plugins.service.js.map +1 -0
  115. package/dist-server/server/modules/plugins/tests/plugins.service.test.js +28 -0
  116. package/dist-server/server/modules/plugins/tests/plugins.service.test.js.map +1 -0
  117. package/dist-server/server/modules/projects/index.js +5 -0
  118. package/dist-server/server/modules/projects/index.js.map +1 -1
  119. package/dist-server/server/modules/providers/index.js +3 -0
  120. package/dist-server/server/modules/providers/index.js.map +1 -1
  121. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +6 -0
  122. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  123. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +1 -4
  124. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
  125. package/dist-server/server/{claude-sdk.js → modules/providers/list/claude/claude-runtime.provider.js} +62 -41
  126. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -0
  127. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +6 -4
  128. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  129. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +23 -4
  130. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  131. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  132. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  133. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +1 -4
  134. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
  135. package/dist-server/server/{openai-codex.js → modules/providers/list/codex/codex-runtime.provider.js} +48 -34
  136. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -0
  137. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +290 -6
  138. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  139. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +5 -0
  140. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -1
  141. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  142. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  143. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +1 -4
  144. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -1
  145. package/dist-server/server/{cursor-cli.js → modules/providers/list/cursor/cursor-runtime.provider.js} +40 -28
  146. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -0
  147. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +21 -14
  148. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  149. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
  150. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
  151. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +7 -5
  152. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
  153. package/dist-server/server/{opencode-cli.js → modules/providers/list/opencode/opencode-runtime.provider.js} +38 -25
  154. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -0
  155. package/dist-server/server/{opencode-cli.test.js → modules/providers/list/opencode/opencode-runtime.provider.test.js} +27 -4
  156. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js.map +1 -0
  157. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +11 -5
  158. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
  159. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +2 -0
  160. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -1
  161. package/dist-server/server/modules/providers/provider.routes.js +33 -9
  162. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  163. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +5 -1
  164. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
  165. package/dist-server/server/modules/providers/services/provider-models.service.js +110 -15
  166. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
  167. package/dist-server/server/modules/providers/services/provider-runtime.service.js +66 -0
  168. package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -0
  169. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +268 -0
  170. package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -0
  171. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +2 -0
  172. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  173. package/dist-server/server/modules/providers/services/sessions.service.js +54 -0
  174. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  175. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +2 -3
  176. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
  177. package/dist-server/server/modules/providers/tests/claude-auth.test.js +122 -0
  178. package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -0
  179. package/dist-server/server/modules/providers/tests/claude-sessions.test.js +44 -0
  180. package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -0
  181. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +36 -0
  182. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
  183. package/dist-server/server/modules/providers/tests/{provider-image-history.test.js → provider-attachment-history.test.js} +60 -2
  184. package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js.map +1 -0
  185. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +148 -61
  186. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
  187. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js +130 -0
  188. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js.map +1 -0
  189. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +165 -0
  190. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -0
  191. package/dist-server/server/modules/providers/tests/sessions-details.test.js +62 -0
  192. package/dist-server/server/modules/providers/tests/sessions-details.test.js.map +1 -0
  193. package/dist-server/server/modules/providers/tests/skills.test.js +4 -2
  194. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
  195. package/dist-server/server/modules/settings/index.js +3 -0
  196. package/dist-server/server/modules/settings/index.js.map +1 -0
  197. package/dist-server/server/modules/settings/settings.module.js +35 -0
  198. package/dist-server/server/modules/settings/settings.module.js.map +1 -0
  199. package/dist-server/server/modules/settings/settings.routes.js +34 -0
  200. package/dist-server/server/modules/settings/settings.routes.js.map +1 -0
  201. package/dist-server/server/modules/settings/settings.service.js +116 -0
  202. package/dist-server/server/modules/settings/settings.service.js.map +1 -0
  203. package/dist-server/server/modules/settings/tests/settings.service.test.js +48 -0
  204. package/dist-server/server/modules/settings/tests/settings.service.test.js.map +1 -0
  205. package/dist-server/server/modules/system/index.js +3 -0
  206. package/dist-server/server/modules/system/index.js.map +1 -0
  207. package/dist-server/server/modules/system/system.module.js +44 -0
  208. package/dist-server/server/modules/system/system.module.js.map +1 -0
  209. package/dist-server/server/modules/system/system.routes.js +16 -0
  210. package/dist-server/server/modules/system/system.routes.js.map +1 -0
  211. package/dist-server/server/modules/system/system.service.js +45 -0
  212. package/dist-server/server/modules/system/system.service.js.map +1 -0
  213. package/dist-server/server/modules/system/tests/system.service.test.js +100 -0
  214. package/dist-server/server/modules/system/tests/system.service.test.js.map +1 -0
  215. package/dist-server/server/modules/taskmaster/index.js +3 -0
  216. package/dist-server/server/modules/taskmaster/index.js.map +1 -0
  217. package/dist-server/server/modules/taskmaster/taskmaster.module.js +20 -0
  218. package/dist-server/server/modules/taskmaster/taskmaster.module.js.map +1 -0
  219. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +1372 -0
  220. package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -0
  221. package/dist-server/server/modules/taskmaster/taskmaster.service.js +107 -0
  222. package/dist-server/server/modules/taskmaster/taskmaster.service.js.map +1 -0
  223. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +132 -0
  224. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -0
  225. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js +85 -0
  226. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js.map +1 -0
  227. package/dist-server/server/modules/user/index.js +3 -0
  228. package/dist-server/server/modules/user/index.js.map +1 -0
  229. package/dist-server/server/modules/user/tests/user.service.test.js +53 -0
  230. package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -0
  231. package/dist-server/server/modules/user/user.module.js +47 -0
  232. package/dist-server/server/modules/user/user.module.js.map +1 -0
  233. package/dist-server/server/modules/user/user.routes.js +44 -0
  234. package/dist-server/server/modules/user/user.routes.js.map +1 -0
  235. package/dist-server/server/modules/user/user.service.js +59 -0
  236. package/dist-server/server/modules/user/user.service.js.map +1 -0
  237. package/dist-server/server/modules/voice/index.js +3 -0
  238. package/dist-server/server/modules/voice/index.js.map +1 -0
  239. package/dist-server/server/modules/voice/tests/voice.service.test.js +86 -0
  240. package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -0
  241. package/dist-server/server/modules/voice/voice.module.js +44 -0
  242. package/dist-server/server/modules/voice/voice.module.js.map +1 -0
  243. package/dist-server/server/modules/voice/voice.routes.js +87 -0
  244. package/dist-server/server/modules/voice/voice.routes.js.map +1 -0
  245. package/dist-server/server/modules/voice/voice.service.js +148 -0
  246. package/dist-server/server/modules/voice/voice.service.js.map +1 -0
  247. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +2 -2
  248. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +40 -29
  249. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
  250. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +76 -8
  251. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
  252. package/dist-server/server/modules/websocket/services/websocket-server.service.js +51 -20
  253. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -1
  254. package/dist-server/server/modules/websocket/tests/{chat-image-filter.test.js → chat-attachment-filter.test.js} +10 -3
  255. package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js.map +1 -0
  256. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +97 -0
  257. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -0
  258. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js +61 -0
  259. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js.map +1 -0
  260. package/dist-server/server/modules/worktrees/index.js +3 -0
  261. package/dist-server/server/modules/worktrees/index.js.map +1 -0
  262. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js +37 -0
  263. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js.map +1 -0
  264. package/dist-server/server/modules/worktrees/services/worktree-create.service.js +67 -0
  265. package/dist-server/server/modules/worktrees/services/worktree-create.service.js.map +1 -0
  266. package/dist-server/server/modules/worktrees/services/worktree-git.service.js +172 -0
  267. package/dist-server/server/modules/worktrees/services/worktree-git.service.js.map +1 -0
  268. package/dist-server/server/modules/worktrees/services/worktree-list.service.js +91 -0
  269. package/dist-server/server/modules/worktrees/services/worktree-list.service.js.map +1 -0
  270. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js +118 -0
  271. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js.map +1 -0
  272. package/dist-server/server/modules/worktrees/services/worktree-open.service.js +58 -0
  273. package/dist-server/server/modules/worktrees/services/worktree-open.service.js.map +1 -0
  274. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +65 -0
  275. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js.map +1 -0
  276. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js +58 -0
  277. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js.map +1 -0
  278. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js +85 -0
  279. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js.map +1 -0
  280. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js +58 -0
  281. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js.map +1 -0
  282. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js +34 -0
  283. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js.map +1 -0
  284. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js +137 -0
  285. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js.map +1 -0
  286. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js +99 -0
  287. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js.map +1 -0
  288. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js +157 -0
  289. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js.map +1 -0
  290. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js +167 -0
  291. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js.map +1 -0
  292. package/dist-server/server/modules/worktrees/worktrees.module.js +97 -0
  293. package/dist-server/server/modules/worktrees/worktrees.module.js.map +1 -0
  294. package/dist-server/server/modules/worktrees/worktrees.routes.js +84 -0
  295. package/dist-server/server/modules/worktrees/worktrees.routes.js.map +1 -0
  296. package/dist-server/server/shared/image-attachments.js +90 -17
  297. package/dist-server/server/shared/image-attachments.js.map +1 -1
  298. package/dist-server/server/shared/tests/image-attachments.test.js +43 -1
  299. package/dist-server/server/shared/tests/image-attachments.test.js.map +1 -1
  300. package/dist-server/server/shared/utils.js +66 -142
  301. package/dist-server/server/shared/utils.js.map +1 -1
  302. package/package.json +8 -4
  303. package/server/index.ts +401 -0
  304. package/server/{load-env.js → load-env.ts} +18 -5
  305. package/server/modules/agent/agent.module.ts +51 -0
  306. package/server/modules/agent/agent.routes.ts +1287 -0
  307. package/server/modules/agent/index.ts +2 -0
  308. package/server/modules/agent/tests/agent.routes.test.ts +205 -0
  309. package/server/modules/assets/assets.routes.ts +63 -16
  310. package/server/modules/assets/index.ts +2 -2
  311. package/server/modules/assets/services/image-assets.service.ts +46 -1
  312. package/server/modules/assets/tests/image-assets.service.test.ts +28 -0
  313. package/server/{middleware/auth.js → modules/auth/auth.middleware.ts} +38 -7
  314. package/server/modules/auth/auth.module.ts +38 -0
  315. package/server/modules/auth/auth.routes.ts +57 -0
  316. package/server/modules/auth/auth.service.ts +155 -0
  317. package/server/modules/auth/index.ts +9 -0
  318. package/server/modules/auth/tests/auth.service.test.ts +95 -0
  319. package/server/{browser-use-mcp.ts → modules/browser-use/browser-use-mcp.ts} +3 -1
  320. package/server/modules/browser-use/browser-use.service.ts +3 -4
  321. package/server/modules/browser-use/index.ts +8 -0
  322. package/server/modules/cli/cli.module.ts +96 -0
  323. package/server/modules/cli/cli.service.ts +281 -0
  324. package/server/modules/cli/cli.ts +13 -0
  325. package/server/modules/cli/index.ts +2 -0
  326. package/server/modules/cli/sandbox.service.ts +413 -0
  327. package/server/modules/cli/tests/cli.service.test.ts +91 -0
  328. package/server/modules/cli/tests/sandbox.service.test.ts +61 -0
  329. package/server/modules/commands/commands.module.ts +22 -0
  330. package/server/{routes/commands.js → modules/commands/commands.routes.ts} +44 -36
  331. package/server/modules/commands/index.ts +2 -0
  332. package/server/modules/commands/tests/commands.test.ts +119 -0
  333. package/server/modules/database/index.ts +1 -0
  334. package/server/modules/database/migrations.ts +15 -0
  335. package/server/modules/database/repositories/sessions.db.ts +19 -1
  336. package/server/modules/database/schema.ts +4 -0
  337. package/server/modules/file-tree/file-tree.module.ts +112 -0
  338. package/server/modules/file-tree/file-tree.routes.ts +258 -0
  339. package/server/modules/file-tree/file-tree.service.ts +616 -0
  340. package/server/modules/file-tree/index.ts +2 -0
  341. package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -0
  342. package/server/modules/file-tree/tests/file-tree.service.test.ts +220 -0
  343. package/server/modules/git/git-parsing.service.ts +66 -0
  344. package/server/modules/git/git.module.ts +22 -0
  345. package/server/{routes/git.js → modules/git/git.routes.ts} +91 -132
  346. package/server/modules/git/index.ts +2 -0
  347. package/server/modules/git/tests/git-init.routes.test.ts +52 -0
  348. package/server/{routes/git.test.js → modules/git/tests/git.test.ts} +3 -3
  349. package/server/modules/notifications/index.ts +9 -0
  350. package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -0
  351. package/server/{services/vapid-keys.js → modules/notifications/vapid-keys.service.ts} +3 -1
  352. package/server/modules/plugins/index.ts +9 -0
  353. package/server/{utils/plugin-process-manager.js → modules/plugins/plugin-process.service.ts} +3 -1
  354. package/server/{utils/plugin-loader.js → modules/plugins/plugin-registry.service.ts} +1 -0
  355. package/server/modules/plugins/plugins.module.ts +33 -0
  356. package/server/modules/plugins/plugins.routes.ts +66 -0
  357. package/server/modules/plugins/plugins.service.ts +147 -0
  358. package/server/modules/plugins/tests/plugins.service.test.ts +32 -0
  359. package/server/modules/projects/index.ts +5 -0
  360. package/server/modules/providers/README.md +41 -9
  361. package/server/modules/providers/index.ts +4 -0
  362. package/server/modules/providers/list/claude/claude-auth.provider.ts +8 -0
  363. package/server/modules/providers/list/claude/claude-models.provider.ts +1 -12
  364. package/server/{claude-sdk.js → modules/providers/list/claude/claude-runtime.provider.js} +66 -44
  365. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +6 -4
  366. package/server/modules/providers/list/claude/claude-sessions.provider.ts +27 -4
  367. package/server/modules/providers/list/claude/claude.provider.ts +3 -0
  368. package/server/modules/providers/list/codex/codex-models.provider.ts +0 -9
  369. package/server/{openai-codex.js → modules/providers/list/codex/codex-runtime.provider.js} +54 -36
  370. package/server/modules/providers/list/codex/codex-sessions.provider.ts +331 -7
  371. package/server/modules/providers/list/codex/codex-skills.provider.ts +5 -0
  372. package/server/modules/providers/list/codex/codex.provider.ts +3 -0
  373. package/server/modules/providers/list/cursor/cursor-models.provider.ts +0 -9
  374. package/server/{cursor-cli.js → modules/providers/list/cursor/cursor-runtime.provider.js} +58 -27
  375. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +26 -15
  376. package/server/modules/providers/list/cursor/cursor.provider.ts +3 -0
  377. package/server/modules/providers/list/opencode/opencode-models.provider.ts +7 -10
  378. package/server/{opencode-cli.js → modules/providers/list/opencode/opencode-runtime.provider.js} +56 -28
  379. package/server/{opencode-cli.test.js → modules/providers/list/opencode/opencode-runtime.provider.test.js} +41 -3
  380. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +13 -5
  381. package/server/modules/providers/list/opencode/opencode.provider.ts +3 -0
  382. package/server/modules/providers/provider.routes.ts +47 -10
  383. package/server/modules/providers/services/provider-capabilities.service.ts +7 -1
  384. package/server/modules/providers/services/provider-models.service.ts +131 -23
  385. package/server/modules/providers/services/provider-runtime.service.ts +109 -0
  386. package/server/modules/providers/services/provider-token-usage.service.ts +357 -0
  387. package/server/modules/providers/services/sessions-watcher.service.ts +2 -0
  388. package/server/modules/providers/services/sessions.service.ts +79 -0
  389. package/server/modules/providers/shared/base/abstract.provider.ts +4 -3
  390. package/server/modules/providers/tests/claude-auth.test.ts +150 -0
  391. package/server/modules/providers/tests/claude-sessions.test.ts +61 -0
  392. package/server/modules/providers/tests/codex-sessions.test.ts +40 -0
  393. package/server/modules/providers/tests/{provider-image-history.test.ts → provider-attachment-history.test.ts} +68 -1
  394. package/server/modules/providers/tests/provider-models.service.test.ts +450 -349
  395. package/server/modules/providers/tests/provider-runtime.service.test.ts +142 -0
  396. package/server/modules/providers/tests/provider-token-usage.service.test.ts +185 -0
  397. package/server/modules/providers/tests/sessions-details.test.ts +73 -0
  398. package/server/modules/providers/tests/skills.test.ts +9 -2
  399. package/server/modules/settings/index.ts +2 -0
  400. package/server/modules/settings/settings.module.ts +50 -0
  401. package/server/modules/settings/settings.routes.ts +51 -0
  402. package/server/modules/settings/settings.service.ts +186 -0
  403. package/server/modules/settings/tests/settings.service.test.ts +54 -0
  404. package/server/modules/system/index.ts +2 -0
  405. package/server/modules/system/system.module.ts +62 -0
  406. package/server/modules/system/system.routes.ts +21 -0
  407. package/server/modules/system/system.service.ts +76 -0
  408. package/server/modules/system/tests/system.service.test.ts +118 -0
  409. package/server/modules/taskmaster/index.ts +2 -0
  410. package/server/modules/taskmaster/taskmaster.module.ts +24 -0
  411. package/server/modules/taskmaster/taskmaster.routes.ts +1482 -0
  412. package/server/modules/taskmaster/taskmaster.service.ts +132 -0
  413. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +144 -0
  414. package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -0
  415. package/server/modules/user/index.ts +2 -0
  416. package/server/modules/user/tests/user.service.test.ts +61 -0
  417. package/server/modules/user/user.module.ts +58 -0
  418. package/server/modules/user/user.routes.ts +50 -0
  419. package/server/modules/user/user.service.ts +85 -0
  420. package/server/modules/voice/index.ts +2 -0
  421. package/server/modules/voice/tests/voice.service.test.ts +98 -0
  422. package/server/modules/voice/voice.module.ts +47 -0
  423. package/server/modules/voice/voice.routes.ts +113 -0
  424. package/server/modules/voice/voice.service.ts +192 -0
  425. package/server/modules/websocket/README.md +7 -7
  426. package/server/modules/websocket/services/chat-session-writer.service.ts +2 -2
  427. package/server/modules/websocket/services/chat-websocket.service.ts +73 -61
  428. package/server/modules/websocket/services/shell-websocket.service.ts +88 -12
  429. package/server/modules/websocket/services/websocket-server.service.ts +63 -19
  430. package/server/modules/websocket/tests/{chat-image-filter.test.ts → chat-attachment-filter.test.ts} +17 -2
  431. package/server/modules/websocket/tests/shell-websocket.service.test.ts +119 -0
  432. package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -0
  433. package/server/modules/worktrees/index.ts +2 -0
  434. package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -0
  435. package/server/modules/worktrees/services/worktree-create.service.ts +104 -0
  436. package/server/modules/worktrees/services/worktree-git.service.ts +207 -0
  437. package/server/modules/worktrees/services/worktree-list.service.ts +143 -0
  438. package/server/modules/worktrees/services/worktree-merge.service.ts +157 -0
  439. package/server/modules/worktrees/services/worktree-open.service.ts +85 -0
  440. package/server/modules/worktrees/services/worktree-remove.service.ts +88 -0
  441. package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -0
  442. package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -0
  443. package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -0
  444. package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -0
  445. package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -0
  446. package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -0
  447. package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -0
  448. package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -0
  449. package/server/modules/worktrees/worktrees.module.ts +113 -0
  450. package/server/modules/worktrees/worktrees.routes.ts +116 -0
  451. package/server/shared/image-attachments.ts +112 -18
  452. package/server/shared/interfaces.ts +29 -19
  453. package/server/shared/tests/image-attachments.test.ts +55 -0
  454. package/server/shared/types.ts +658 -21
  455. package/server/shared/utils.ts +77 -212
  456. package/dist/assets/index-DLmhQ15L.css +0 -32
  457. package/dist-server/server/browser-use-mcp.js.map +0 -1
  458. package/dist-server/server/claude-sdk.js.map +0 -1
  459. package/dist-server/server/cli.js +0 -647
  460. package/dist-server/server/cli.js.map +0 -1
  461. package/dist-server/server/cursor-cli.js.map +0 -1
  462. package/dist-server/server/middleware/auth.js.map +0 -1
  463. package/dist-server/server/modules/providers/tests/provider-image-history.test.js.map +0 -1
  464. package/dist-server/server/modules/websocket/tests/chat-image-filter.test.js.map +0 -1
  465. package/dist-server/server/openai-codex.js.map +0 -1
  466. package/dist-server/server/opencode-cli.js.map +0 -1
  467. package/dist-server/server/opencode-cli.test.js.map +0 -1
  468. package/dist-server/server/routes/agent.js +0 -1155
  469. package/dist-server/server/routes/agent.js.map +0 -1
  470. package/dist-server/server/routes/auth.js +0 -119
  471. package/dist-server/server/routes/auth.js.map +0 -1
  472. package/dist-server/server/routes/commands.js +0 -492
  473. package/dist-server/server/routes/commands.js.map +0 -1
  474. package/dist-server/server/routes/cursor.js +0 -49
  475. package/dist-server/server/routes/cursor.js.map +0 -1
  476. package/dist-server/server/routes/git.js +0 -1389
  477. package/dist-server/server/routes/git.js.map +0 -1
  478. package/dist-server/server/routes/git.test.js.map +0 -1
  479. package/dist-server/server/routes/mcp-utils.js +0 -29
  480. package/dist-server/server/routes/mcp-utils.js.map +0 -1
  481. package/dist-server/server/routes/plugins.js +0 -266
  482. package/dist-server/server/routes/plugins.js.map +0 -1
  483. package/dist-server/server/routes/settings.js +0 -249
  484. package/dist-server/server/routes/settings.js.map +0 -1
  485. package/dist-server/server/routes/taskmaster.js +0 -1362
  486. package/dist-server/server/routes/taskmaster.js.map +0 -1
  487. package/dist-server/server/routes/tests/commands.test.js +0 -76
  488. package/dist-server/server/routes/tests/commands.test.js.map +0 -1
  489. package/dist-server/server/routes/user.js +0 -116
  490. package/dist-server/server/routes/user.js.map +0 -1
  491. package/dist-server/server/services/notification-orchestrator.js +0 -2
  492. package/dist-server/server/services/notification-orchestrator.js.map +0 -1
  493. package/dist-server/server/services/tests/notification-orchestrator.test.js +0 -64
  494. package/dist-server/server/services/tests/notification-orchestrator.test.js.map +0 -1
  495. package/dist-server/server/services/vapid-keys.js.map +0 -1
  496. package/dist-server/server/utils/colors.js +0 -20
  497. package/dist-server/server/utils/colors.js.map +0 -1
  498. package/dist-server/server/utils/commandParser.js +0 -255
  499. package/dist-server/server/utils/commandParser.js.map +0 -1
  500. package/dist-server/server/utils/gitConfig.js +0 -37
  501. package/dist-server/server/utils/gitConfig.js.map +0 -1
  502. package/dist-server/server/utils/mcp-detector.js +0 -134
  503. package/dist-server/server/utils/mcp-detector.js.map +0 -1
  504. package/dist-server/server/utils/plugin-loader.js.map +0 -1
  505. package/dist-server/server/utils/plugin-process-manager.js.map +0 -1
  506. package/dist-server/server/utils/runtime-paths.js +0 -30
  507. package/dist-server/server/utils/runtime-paths.js.map +0 -1
  508. package/dist-server/server/utils/taskmaster-websocket.js +0 -124
  509. package/dist-server/server/utils/taskmaster-websocket.js.map +0 -1
  510. package/dist-server/server/utils/url-detection.js +0 -58
  511. package/dist-server/server/utils/url-detection.js.map +0 -1
  512. package/dist-server/server/voice-proxy.js +0 -226
  513. package/dist-server/server/voice-proxy.js.map +0 -1
  514. package/server/cli.js +0 -695
  515. package/server/index.js +0 -1651
  516. package/server/routes/agent.js +0 -1257
  517. package/server/routes/auth.js +0 -137
  518. package/server/routes/cursor.js +0 -52
  519. package/server/routes/mcp-utils.js +0 -31
  520. package/server/routes/plugins.js +0 -307
  521. package/server/routes/settings.js +0 -282
  522. package/server/routes/taskmaster.js +0 -1470
  523. package/server/routes/tests/commands.test.js +0 -82
  524. package/server/routes/user.js +0 -124
  525. package/server/services/notification-orchestrator.js +0 -7
  526. package/server/services/tests/notification-orchestrator.test.js +0 -80
  527. package/server/utils/colors.js +0 -21
  528. package/server/utils/commandParser.js +0 -305
  529. package/server/utils/gitConfig.js +0 -35
  530. package/server/utils/mcp-detector.js +0 -147
  531. package/server/utils/runtime-paths.js +0 -37
  532. package/server/utils/taskmaster-websocket.js +0 -135
  533. package/server/utils/url-detection.js +0 -71
  534. package/server/voice-proxy.js +0 -224
  535. /package/server/constants/{config.js → config.ts} +0 -0
@@ -0,0 +1,357 @@
1
+ import fsSync, { type Dirent } from 'node:fs';
2
+ import fsp from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ import Database from 'better-sqlite3';
7
+
8
+ import { sessionsDb } from '@/modules/database/index.js';
9
+ import type { AnyRecord } from '@/shared/types.js';
10
+ import { AppError, getOpenCodeDatabasePath } from '@/shared/utils.js';
11
+
12
+ type SessionRow = NonNullable<ReturnType<typeof sessionsDb.getSessionById>>;
13
+
14
+ type ProviderTokenUsageServiceDependencies = {
15
+ getSessionById: (sessionId: string) => SessionRow | null | undefined;
16
+ getHomeDirectory: () => string;
17
+ getOpenCodeDatabasePath: () => string;
18
+ fileExists: (filePath: string) => boolean;
19
+ readDirectory: (directoryPath: string) => Promise<Dirent[]>;
20
+ readTextFile: (filePath: string) => Promise<string>;
21
+ getClaudeContextWindow: () => string | undefined;
22
+ };
23
+
24
+ type TokenUsageResult = {
25
+ used: number;
26
+ total?: number;
27
+ inputTokens: number;
28
+ outputTokens: number;
29
+ cacheReadTokens?: number;
30
+ cacheCreationTokens?: number;
31
+ cacheTokens?: number;
32
+ breakdown: {
33
+ input: number;
34
+ output: number;
35
+ };
36
+ unsupported?: boolean;
37
+ message?: string;
38
+ };
39
+
40
+ type OpenCodeTokenRow = {
41
+ inputTokens: number | null;
42
+ outputTokens: number | null;
43
+ reasoningTokens: number | null;
44
+ cacheReadTokens: number | null;
45
+ cacheWriteTokens: number | null;
46
+ };
47
+
48
+ const defaultDependencies: ProviderTokenUsageServiceDependencies = {
49
+ getSessionById: (sessionId) => sessionsDb.getSessionById(sessionId),
50
+ getHomeDirectory: () => os.homedir(),
51
+ getOpenCodeDatabasePath,
52
+ fileExists: (filePath) => fsSync.existsSync(filePath),
53
+ readDirectory: (directoryPath) => fsp.readdir(directoryPath, { withFileTypes: true }),
54
+ readTextFile: (filePath) => fsp.readFile(filePath, 'utf8'),
55
+ getClaudeContextWindow: () => process.env.CONTEXT_WINDOW,
56
+ };
57
+
58
+ function readUsageNumber(value: unknown): number {
59
+ const parsedValue = Number(value);
60
+ return Number.isFinite(parsedValue) ? parsedValue : 0;
61
+ }
62
+
63
+ async function findCodexSessionFile(
64
+ directoryPath: string,
65
+ providerSessionId: string,
66
+ dependencies: ProviderTokenUsageServiceDependencies,
67
+ ): Promise<string | null> {
68
+ let entries: Dirent[];
69
+ try {
70
+ entries = await dependencies.readDirectory(directoryPath);
71
+ } catch {
72
+ // Codex session folders are date-partitioned and can disappear while a
73
+ // cleanup is running. An unreadable branch is simply not a match.
74
+ return null;
75
+ }
76
+
77
+ for (const entry of entries) {
78
+ const entryPath = path.join(directoryPath, entry.name);
79
+ if (entry.isDirectory()) {
80
+ const nestedMatch = await findCodexSessionFile(entryPath, providerSessionId, dependencies);
81
+ if (nestedMatch) {
82
+ return nestedMatch;
83
+ }
84
+ continue;
85
+ }
86
+
87
+ if (entry.name.includes(providerSessionId) && entry.name.endsWith('.jsonl')) {
88
+ return entryPath;
89
+ }
90
+ }
91
+
92
+ return null;
93
+ }
94
+
95
+ function readCodexTokenUsage(fileContent: string): TokenUsageResult {
96
+ let inputTokens = 0;
97
+ let outputTokens = 0;
98
+ let totalTokens = 0;
99
+ let contextWindow = 200_000;
100
+ const lines = fileContent.trim().split('\n');
101
+
102
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
103
+ try {
104
+ const entry = JSON.parse(lines[index]) as AnyRecord;
105
+ const tokenInfo = entry.type === 'event_msg' && entry.payload?.type === 'token_count'
106
+ ? entry.payload.info
107
+ : null;
108
+ if (!tokenInfo) {
109
+ continue;
110
+ }
111
+
112
+ if (tokenInfo.total_token_usage) {
113
+ inputTokens = readUsageNumber(tokenInfo.total_token_usage.input_tokens);
114
+ outputTokens = readUsageNumber(tokenInfo.total_token_usage.output_tokens);
115
+ totalTokens = readUsageNumber(tokenInfo.total_token_usage.total_tokens)
116
+ || inputTokens + outputTokens;
117
+ }
118
+ contextWindow = readUsageNumber(tokenInfo.model_context_window) || contextWindow;
119
+ break;
120
+ } catch {
121
+ // A provider may be writing the last JSONL line while this read happens.
122
+ }
123
+ }
124
+
125
+ return {
126
+ used: totalTokens,
127
+ total: contextWindow,
128
+ inputTokens,
129
+ outputTokens,
130
+ breakdown: { input: inputTokens, output: outputTokens },
131
+ };
132
+ }
133
+
134
+ function readClaudeTokenUsage(fileContent: string, configuredContextWindow: string | undefined): TokenUsageResult {
135
+ let inputTokens = 0;
136
+ let outputTokens = 0;
137
+ let cacheReadTokens = 0;
138
+ let cacheCreationTokens = 0;
139
+ const lines = fileContent.trim().split('\n');
140
+
141
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
142
+ try {
143
+ const entry = JSON.parse(lines[index]) as AnyRecord;
144
+ const usage = entry.type === 'assistant' ? entry.message?.usage : null;
145
+ if (!usage) {
146
+ continue;
147
+ }
148
+
149
+ const directInputTokens = readUsageNumber(usage.input_tokens ?? usage.inputTokens);
150
+ cacheReadTokens = readUsageNumber(
151
+ usage.cache_read_input_tokens ?? usage.cacheReadInputTokens ?? usage.cacheReadTokens,
152
+ );
153
+ cacheCreationTokens = readUsageNumber(
154
+ usage.cache_creation_input_tokens
155
+ ?? usage.cacheCreationInputTokens
156
+ ?? usage.cacheCreationTokens,
157
+ );
158
+ inputTokens = directInputTokens + cacheReadTokens + cacheCreationTokens;
159
+ outputTokens = readUsageNumber(usage.output_tokens ?? usage.outputTokens);
160
+ break;
161
+ } catch {
162
+ // Skip malformed lines without discarding usage from earlier messages.
163
+ }
164
+ }
165
+
166
+ const parsedContextWindow = Number.parseInt(configuredContextWindow ?? '', 10);
167
+ const contextWindow = Number.isFinite(parsedContextWindow) ? parsedContextWindow : 160_000;
168
+ const cacheTokens = cacheReadTokens + cacheCreationTokens;
169
+
170
+ return {
171
+ used: inputTokens + outputTokens,
172
+ total: contextWindow,
173
+ inputTokens,
174
+ outputTokens,
175
+ cacheReadTokens,
176
+ cacheCreationTokens,
177
+ cacheTokens,
178
+ breakdown: { input: inputTokens, output: outputTokens },
179
+ };
180
+ }
181
+
182
+ function readOpenCodeTokenUsage(databasePath: string, providerSessionId: string): TokenUsageResult {
183
+ const database = new Database(databasePath, { readonly: true, fileMustExist: true });
184
+ try {
185
+ const columns = database.prepare('PRAGMA table_info(session)').all() as Array<{ name: string }>;
186
+ const columnNames = new Set(columns.map((column) => column.name));
187
+ const requiredColumns = [
188
+ 'tokens_input',
189
+ 'tokens_output',
190
+ 'tokens_reasoning',
191
+ 'tokens_cache_read',
192
+ 'tokens_cache_write',
193
+ ];
194
+
195
+ if (!requiredColumns.every((column) => columnNames.has(column))) {
196
+ return {
197
+ used: 0,
198
+ inputTokens: 0,
199
+ outputTokens: 0,
200
+ breakdown: { input: 0, output: 0 },
201
+ unsupported: true,
202
+ message: 'Token usage tracking is not available in this OpenCode database schema',
203
+ };
204
+ }
205
+
206
+ const row = database.prepare(`
207
+ SELECT
208
+ tokens_input AS inputTokens,
209
+ tokens_output AS outputTokens,
210
+ tokens_reasoning AS reasoningTokens,
211
+ tokens_cache_read AS cacheReadTokens,
212
+ tokens_cache_write AS cacheWriteTokens
213
+ FROM session
214
+ WHERE id = ?
215
+ `).get(providerSessionId) as OpenCodeTokenRow | undefined;
216
+
217
+ if (!row) {
218
+ throw new AppError('OpenCode session was not found.', {
219
+ code: 'OPENCODE_SESSION_NOT_FOUND',
220
+ statusCode: 404,
221
+ });
222
+ }
223
+
224
+ const inputTokens = readUsageNumber(row.inputTokens) + readUsageNumber(row.cacheReadTokens);
225
+ const outputTokens = readUsageNumber(row.outputTokens);
226
+ const used = readUsageNumber(row.inputTokens)
227
+ + outputTokens
228
+ + readUsageNumber(row.reasoningTokens)
229
+ + readUsageNumber(row.cacheReadTokens)
230
+ + readUsageNumber(row.cacheWriteTokens);
231
+
232
+ return {
233
+ used,
234
+ inputTokens,
235
+ outputTokens,
236
+ breakdown: { input: inputTokens, output: outputTokens },
237
+ };
238
+ } finally {
239
+ database.close();
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Creates the provider token-usage service used by the provider routes. The
245
+ * provider test suite supplies isolated filesystem and session dependencies so
246
+ * every calculator can be exercised without touching a developer's real data.
247
+ */
248
+ export function createProviderTokenUsageService(
249
+ dependencyOverrides: Partial<ProviderTokenUsageServiceDependencies> = {},
250
+ ) {
251
+ const dependencies = { ...defaultDependencies, ...dependencyOverrides };
252
+
253
+ return {
254
+ /**
255
+ * Resolves all provider-specific storage details from one app-facing
256
+ * session id, then returns the latest usage snapshot for that provider.
257
+ */
258
+ async getSessionTokenUsage(sessionId: string): Promise<TokenUsageResult> {
259
+ const session = dependencies.getSessionById(sessionId);
260
+ if (!session) {
261
+ throw new AppError(`Session "${sessionId}" was not found.`, {
262
+ code: 'SESSION_NOT_FOUND',
263
+ statusCode: 404,
264
+ });
265
+ }
266
+
267
+ const providerSessionId = session.provider_session_id || sessionId;
268
+
269
+ if (session.provider === 'cursor') {
270
+ return {
271
+ used: 0,
272
+ total: 0,
273
+ inputTokens: 0,
274
+ outputTokens: 0,
275
+ breakdown: { input: 0, output: 0 },
276
+ unsupported: true,
277
+ message: 'Token usage tracking not available for Cursor sessions',
278
+ };
279
+ }
280
+
281
+ if (session.provider === 'opencode') {
282
+ const databasePath = dependencies.getOpenCodeDatabasePath();
283
+ if (!dependencies.fileExists(databasePath)) {
284
+ throw new AppError('OpenCode database was not found.', {
285
+ code: 'OPENCODE_DATABASE_NOT_FOUND',
286
+ statusCode: 404,
287
+ });
288
+ }
289
+
290
+ return readOpenCodeTokenUsage(databasePath, providerSessionId);
291
+ }
292
+
293
+ if (session.provider === 'codex') {
294
+ const indexedFilePath = session.jsonl_path && dependencies.fileExists(session.jsonl_path)
295
+ ? session.jsonl_path
296
+ : null;
297
+ const sessionFilePath = indexedFilePath ?? await findCodexSessionFile(
298
+ path.join(dependencies.getHomeDirectory(), '.codex', 'sessions'),
299
+ providerSessionId,
300
+ dependencies,
301
+ );
302
+
303
+ if (!sessionFilePath) {
304
+ throw new AppError(`Codex session file for "${sessionId}" was not found.`, {
305
+ code: 'CODEX_SESSION_FILE_NOT_FOUND',
306
+ statusCode: 404,
307
+ });
308
+ }
309
+
310
+ const fileContent = await dependencies.readTextFile(sessionFilePath);
311
+ return readCodexTokenUsage(fileContent);
312
+ }
313
+
314
+ let sessionFilePath = session.jsonl_path;
315
+ if (!sessionFilePath) {
316
+ if (!session.project_path) {
317
+ throw new AppError(`Session file for "${sessionId}" was not found.`, {
318
+ code: 'SESSION_FILE_NOT_FOUND',
319
+ statusCode: 404,
320
+ });
321
+ }
322
+
323
+ const encodedProjectPath = session.project_path.replace(/[^a-zA-Z0-9-]/g, '-');
324
+ const projectDirectory = path.join(
325
+ dependencies.getHomeDirectory(),
326
+ '.claude',
327
+ 'projects',
328
+ encodedProjectPath,
329
+ );
330
+ sessionFilePath = path.join(projectDirectory, `${providerSessionId}.jsonl`);
331
+
332
+ const relativePath = path.relative(path.resolve(projectDirectory), path.resolve(sessionFilePath));
333
+ if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
334
+ throw new AppError('Resolved session path is invalid.', {
335
+ code: 'INVALID_SESSION_PATH',
336
+ statusCode: 400,
337
+ });
338
+ }
339
+ }
340
+
341
+ if (!dependencies.fileExists(sessionFilePath)) {
342
+ throw new AppError(`Session file for "${sessionId}" was not found.`, {
343
+ code: 'SESSION_FILE_NOT_FOUND',
344
+ statusCode: 404,
345
+ });
346
+ }
347
+
348
+ const fileContent = await dependencies.readTextFile(sessionFilePath);
349
+ return readClaudeTokenUsage(fileContent, dependencies.getClaudeContextWindow());
350
+ },
351
+ };
352
+ }
353
+
354
+ /**
355
+ * Used by the provider routes to serve token usage from only an app session id.
356
+ */
357
+ export const providerTokenUsageService = createProviderTokenUsageService();
@@ -36,6 +36,8 @@ const WATCHER_IGNORED_PATTERNS = [
36
36
  '**/.git/**',
37
37
  '**/dist/**',
38
38
  '**/build/**',
39
+ '**/subagents/**',
40
+ '**/tool-results/**',
39
41
  '**/*.tmp',
40
42
  '**/*.swp',
41
43
  '**/.DS_Store',
@@ -32,6 +32,25 @@ type ArchivedSessionListItem = {
32
32
  isProjectArchived: boolean;
33
33
  };
34
34
 
35
+ type SessionDetails = {
36
+ /** Canonical app-facing session id (may differ from the looked-up id when a provider-native id was given). */
37
+ sessionId: string;
38
+ provider: LLMProvider;
39
+ summary: string;
40
+ createdAt: string | null;
41
+ updatedAt: string | null;
42
+ lastActivity: string | null;
43
+ isArchived: boolean;
44
+ project: {
45
+ projectId: string;
46
+ path: string;
47
+ fullPath: string;
48
+ displayName: string;
49
+ isStarred: boolean;
50
+ isArchived: boolean;
51
+ } | null;
52
+ };
53
+
35
54
  /**
36
55
  * Removes one file if it exists.
37
56
  */
@@ -100,6 +119,23 @@ export const sessionsService = {
100
119
  return chatRunRegistry.listRunningRuns();
101
120
  },
102
121
 
122
+ /**
123
+ * Resolves the provider-native session id a runtime needs for resume.
124
+ *
125
+ * Callers hand provider runtimes the stable app session id; the provider
126
+ * CLIs/SDKs only understand their own native id, which lives on the session
127
+ * row. Ids without a row are assumed to be provider-native already (direct
128
+ * API callers that reference sessions the watcher has not indexed yet).
129
+ */
130
+ resolveProviderSessionId(sessionId: string | null | undefined): string | null {
131
+ if (!sessionId) {
132
+ return null;
133
+ }
134
+
135
+ const session = sessionsDb.getSessionById(sessionId);
136
+ return session ? session.provider_session_id : sessionId;
137
+ },
138
+
103
139
  /**
104
140
  * Normalizes one provider-native event into frontend session message events.
105
141
  */
@@ -189,6 +225,49 @@ export const sessionsService = {
189
225
  };
190
226
  },
191
227
 
228
+ /**
229
+ * Resolves one session (by app id, falling back to the provider-native id)
230
+ * to its metadata plus the owning project.
231
+ *
232
+ * This backs deep links like `/session/:sessionId`: the frontend's paginated
233
+ * project payloads only carry each project's first session page, so a
234
+ * session opened directly by URL may not be present client-side at all —
235
+ * this lookup is the authoritative way to learn which project owns it.
236
+ */
237
+ getSessionDetailsById(sessionId: string): SessionDetails {
238
+ const session =
239
+ sessionsDb.getSessionById(sessionId) ?? sessionsDb.getSessionByProviderSessionId(sessionId);
240
+ if (!session) {
241
+ throw new AppError(`Session "${sessionId}" was not found.`, {
242
+ code: 'SESSION_NOT_FOUND',
243
+ statusCode: 404,
244
+ });
245
+ }
246
+
247
+ const projectPath = session.project_path?.trim() ? session.project_path : null;
248
+ const project = projectPath ? projectsDb.getProjectPath(projectPath) : null;
249
+
250
+ return {
251
+ sessionId: session.session_id,
252
+ provider: session.provider as LLMProvider,
253
+ summary: session.custom_name?.trim() || '',
254
+ createdAt: session.created_at ?? null,
255
+ updatedAt: session.updated_at ?? null,
256
+ lastActivity: session.updated_at ?? session.created_at ?? null,
257
+ isArchived: Boolean(session.isArchived),
258
+ project: project && projectPath
259
+ ? {
260
+ projectId: project.project_id,
261
+ path: projectPath,
262
+ fullPath: projectPath,
263
+ displayName: resolveProjectDisplayName(projectPath, project.custom_project_name),
264
+ isStarred: Boolean(project.isStarred),
265
+ isArchived: Boolean(project.isArchived),
266
+ }
267
+ : null,
268
+ };
269
+ },
270
+
192
271
  /**
193
272
  * Returns archived sessions with enough project metadata for the sidebar to
194
273
  * group, filter, open, and restore them without a per-row follow-up query.
@@ -3,6 +3,7 @@ import type {
3
3
  IProviderAuth,
4
4
  IProviderMcp,
5
5
  IProviderModels,
6
+ IProviderRuntime,
6
7
  IProviderSessionSynchronizer,
7
8
  IProviderSkills,
8
9
  IProviderSessions,
@@ -12,12 +13,12 @@ import type { LLMProvider } from '@/shared/types.js';
12
13
  /**
13
14
  * Shared provider base.
14
15
  *
15
- * Concrete providers must expose auth/MCP handlers and implement message
16
- * normalization/history loading because those behaviors depend on native
17
- * SDK/CLI formats.
16
+ * Concrete providers expose their live runtime plus model, auth, MCP, skill,
17
+ * session, and synchronization facets behind one registry-owned object.
18
18
  */
19
19
  export abstract class AbstractProvider implements IProvider {
20
20
  readonly id: LLMProvider;
21
+ abstract readonly runtime: IProviderRuntime;
21
22
  abstract readonly models: IProviderModels;
22
23
  abstract readonly mcp: IProviderMcp;
23
24
  abstract readonly auth: IProviderAuth;
@@ -0,0 +1,150 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import test from 'node:test';
6
+
7
+ import { ClaudeProviderAuth } from '@/modules/providers/list/claude/claude-auth.provider.js';
8
+
9
+ // checkCredentials() is private, but unlike getStatus() it never shells out to the
10
+ // `claude` CLI — it only reads env vars and ~/.claude files. Calling it directly
11
+ // (TypeScript's `private` has no runtime effect) tests the priority order without
12
+ // depending on `claude` being installed in the test environment.
13
+ type CheckCredentialsResult = {
14
+ authenticated: boolean;
15
+ email: string | null;
16
+ method: string | null;
17
+ error?: string;
18
+ };
19
+
20
+ const checkCredentials = (auth: ClaudeProviderAuth): Promise<CheckCredentialsResult> =>
21
+ (auth as unknown as { checkCredentials: () => Promise<CheckCredentialsResult> }).checkCredentials();
22
+
23
+ const ENV_KEYS = ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'] as const;
24
+
25
+ const withEnv = async (
26
+ overrides: Partial<Record<(typeof ENV_KEYS)[number], string>>,
27
+ fn: () => Promise<void>,
28
+ ) => {
29
+ const original: Partial<Record<(typeof ENV_KEYS)[number], string>> = {};
30
+ for (const key of ENV_KEYS) {
31
+ original[key] = process.env[key];
32
+ const value = overrides[key];
33
+ if (value === undefined) {
34
+ delete process.env[key];
35
+ } else {
36
+ process.env[key] = value;
37
+ }
38
+ }
39
+ try {
40
+ await fn();
41
+ } finally {
42
+ for (const key of ENV_KEYS) {
43
+ if (original[key] === undefined) {
44
+ delete process.env[key];
45
+ } else {
46
+ process.env[key] = original[key];
47
+ }
48
+ }
49
+ }
50
+ };
51
+
52
+ const withTempHome = async (fn: (homeDir: string) => Promise<void>) => {
53
+ const homeDir = await mkdtemp(path.join(os.tmpdir(), 'claude-auth-test-'));
54
+ const originalHome = process.env.HOME;
55
+ process.env.HOME = homeDir;
56
+ try {
57
+ await fn(homeDir);
58
+ } finally {
59
+ if (originalHome === undefined) {
60
+ delete process.env.HOME;
61
+ } else {
62
+ process.env.HOME = originalHome;
63
+ }
64
+ await rm(homeDir, { recursive: true, force: true });
65
+ }
66
+ };
67
+
68
+ const writeCredentialsFile = async (homeDir: string, body: unknown) => {
69
+ const claudeDir = path.join(homeDir, '.claude');
70
+ await mkdir(claudeDir, { recursive: true });
71
+ await writeFile(path.join(claudeDir, '.credentials.json'), JSON.stringify(body));
72
+ };
73
+
74
+ const writeSettingsFile = async (homeDir: string, env: Record<string, string>) => {
75
+ const claudeDir = path.join(homeDir, '.claude');
76
+ await mkdir(claudeDir, { recursive: true });
77
+ await writeFile(path.join(claudeDir, 'settings.json'), JSON.stringify({ env }));
78
+ };
79
+
80
+ test('checkCredentials: CLAUDE_CODE_OAUTH_TOKEN set is authenticated via environment, even with a stale credentials file', async () => {
81
+ await withTempHome(async (homeDir) => {
82
+ await writeCredentialsFile(homeDir, {
83
+ claudeAiOauth: { accessToken: 'stale-token', expiresAt: 1_000_000_000_000 }, // long expired
84
+ });
85
+
86
+ await withEnv({ CLAUDE_CODE_OAUTH_TOKEN: 'test-oauth-token' }, async () => {
87
+ const status = await checkCredentials(new ClaudeProviderAuth());
88
+ assert.equal(status.authenticated, true);
89
+ assert.equal(status.method, 'environment');
90
+ });
91
+ });
92
+ });
93
+
94
+ test('checkCredentials: CLAUDE_CODE_OAUTH_TOKEN configured via settings.json env block is authenticated via environment', async () => {
95
+ await withTempHome(async (homeDir) => {
96
+ await writeSettingsFile(homeDir, { CLAUDE_CODE_OAUTH_TOKEN: 'test-oauth-token-from-settings' });
97
+ await writeCredentialsFile(homeDir, {
98
+ claudeAiOauth: { accessToken: 'stale-token', expiresAt: 1_000_000_000_000 }, // long expired
99
+ });
100
+
101
+ await withEnv({}, async () => {
102
+ const status = await checkCredentials(new ClaudeProviderAuth());
103
+ assert.equal(status.authenticated, true);
104
+ assert.equal(status.method, 'environment');
105
+ });
106
+ });
107
+ });
108
+
109
+ test('checkCredentials: no CLAUDE_CODE_OAUTH_TOKEN, valid credentials file falls back to credentials_file', async () => {
110
+ await withTempHome(async (homeDir) => {
111
+ await writeCredentialsFile(homeDir, {
112
+ claudeAiOauth: { accessToken: 'valid-token', expiresAt: Date.now() + 60 * 60 * 1000 },
113
+ email: 'someone@example.com',
114
+ });
115
+
116
+ await withEnv({}, async () => {
117
+ const status = await checkCredentials(new ClaudeProviderAuth());
118
+ assert.equal(status.authenticated, true);
119
+ assert.equal(status.method, 'credentials_file');
120
+ assert.equal(status.email, 'someone@example.com');
121
+ });
122
+ });
123
+ });
124
+
125
+ test('checkCredentials: no CLAUDE_CODE_OAUTH_TOKEN, expired credentials file reports not authenticated', async () => {
126
+ await withTempHome(async (homeDir) => {
127
+ await writeCredentialsFile(homeDir, {
128
+ claudeAiOauth: { accessToken: 'stale-token', expiresAt: 1_000_000_000_000 },
129
+ });
130
+
131
+ await withEnv({}, async () => {
132
+ const status = await checkCredentials(new ClaudeProviderAuth());
133
+ assert.equal(status.authenticated, false);
134
+ assert.match(status.error ?? '', /expired/i);
135
+ });
136
+ });
137
+ });
138
+
139
+ test('checkCredentials: ANTHROPIC_API_KEY takes precedence over CLAUDE_CODE_OAUTH_TOKEN', async () => {
140
+ await withTempHome(async () => {
141
+ await withEnv(
142
+ { ANTHROPIC_API_KEY: 'test-api-key', CLAUDE_CODE_OAUTH_TOKEN: 'test-oauth-token' },
143
+ async () => {
144
+ const status = await checkCredentials(new ClaudeProviderAuth());
145
+ assert.equal(status.authenticated, true);
146
+ assert.equal(status.method, 'api_key');
147
+ },
148
+ );
149
+ });
150
+ });
@@ -0,0 +1,61 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { ClaudeSessionsProvider } from '@/modules/providers/list/claude/claude-sessions.provider.js';
5
+
6
+ const SESSION_ID = 'session-1';
7
+
8
+ const SKILL_BODY = [
9
+ 'Base directory for this skill: /tmp/claude/bundled-skills/2.1.220/abc123/claude-api',
10
+ '',
11
+ '# Building LLM-Powered Applications with Claude',
12
+ '',
13
+ 'This skill helps you build LLM-powered applications with Claude.',
14
+ ].join('\n');
15
+
16
+ test('claude: injected skill bodies are hidden even without the isMeta flag', () => {
17
+ const provider = new ClaudeSessionsProvider();
18
+
19
+ // The live SDK stream omits `isMeta`, so the payload has to be recognised by
20
+ // its content or it renders as a giant user bubble mid-run.
21
+ const live = provider.normalizeMessage(
22
+ {
23
+ uuid: 'u1',
24
+ timestamp: '2026-07-28T10:00:00.000Z',
25
+ message: { role: 'user', content: [{ type: 'text', text: SKILL_BODY }] },
26
+ },
27
+ SESSION_ID,
28
+ );
29
+ assert.deepEqual(live, []);
30
+
31
+ const persisted = provider.normalizeMessage(
32
+ {
33
+ uuid: 'u2',
34
+ timestamp: '2026-07-28T10:00:00.000Z',
35
+ isMeta: true,
36
+ message: { role: 'user', content: [{ type: 'text', text: SKILL_BODY }] },
37
+ },
38
+ SESSION_ID,
39
+ );
40
+ assert.deepEqual(persisted, []);
41
+ });
42
+
43
+ test('claude: the Skill tool result itself still reaches the UI', () => {
44
+ const provider = new ClaudeSessionsProvider();
45
+
46
+ const messages = provider.normalizeMessage(
47
+ {
48
+ uuid: 'u3',
49
+ timestamp: '2026-07-28T10:00:00.000Z',
50
+ message: {
51
+ role: 'user',
52
+ content: [{ type: 'tool_result', tool_use_id: 'toolu_1', content: 'Launching skill: claude-api' }],
53
+ },
54
+ },
55
+ SESSION_ID,
56
+ );
57
+
58
+ assert.equal(messages.length, 1);
59
+ assert.equal(messages[0].kind, 'tool_result');
60
+ assert.equal(messages[0].toolId, 'toolu_1');
61
+ });