@glwhappen/web-code 1.32.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 (479) hide show
  1. package/LICENSE +718 -0
  2. package/README.de.md +250 -0
  3. package/README.ja.md +242 -0
  4. package/README.ko.md +242 -0
  5. package/README.md +252 -0
  6. package/README.ru.md +250 -0
  7. package/README.tr.md +252 -0
  8. package/README.zh-CN.md +242 -0
  9. package/dist/api-docs.html +879 -0
  10. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  11. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  12. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  13. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  14. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  15. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  16. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  17. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  18. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  19. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  20. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  21. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  22. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  23. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  24. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  25. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  26. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  27. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  28. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  30. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  31. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  32. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  33. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  34. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  35. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  36. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  37. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  38. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  39. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  40. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  41. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  42. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  44. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  45. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  46. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  47. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  48. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  49. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  50. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  51. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  52. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  53. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  54. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  55. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  56. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  57. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  58. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  59. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  60. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  61. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  62. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  63. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  64. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  65. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  66. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  67. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  68. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  69. package/dist/assets/index-Ct6oPUQk.css +32 -0
  70. package/dist/assets/index-u6XmIqLb.js +1346 -0
  71. package/dist/assets/vendor-codemirror-OwyKSvPE.js +41 -0
  72. package/dist/assets/vendor-react-BGZc9oRE.js +59 -0
  73. package/dist/assets/vendor-xterm-CJZjLICi.js +66 -0
  74. package/dist/clear-cache.html +85 -0
  75. package/dist/convert-icons.md +53 -0
  76. package/dist/favicon.png +0 -0
  77. package/dist/favicon.svg +9 -0
  78. package/dist/generate-icons.js +49 -0
  79. package/dist/icons/claude-ai-icon.svg +1 -0
  80. package/dist/icons/codex-white.svg +3 -0
  81. package/dist/icons/codex.svg +3 -0
  82. package/dist/icons/cursor-white.svg +12 -0
  83. package/dist/icons/cursor.svg +1 -0
  84. package/dist/icons/gemini-ai-icon.svg +1 -0
  85. package/dist/icons/icon-128x128.png +0 -0
  86. package/dist/icons/icon-128x128.svg +12 -0
  87. package/dist/icons/icon-144x144.png +0 -0
  88. package/dist/icons/icon-144x144.svg +12 -0
  89. package/dist/icons/icon-152x152.png +0 -0
  90. package/dist/icons/icon-152x152.svg +12 -0
  91. package/dist/icons/icon-192x192.png +0 -0
  92. package/dist/icons/icon-192x192.svg +12 -0
  93. package/dist/icons/icon-384x384.png +0 -0
  94. package/dist/icons/icon-384x384.svg +12 -0
  95. package/dist/icons/icon-512x512.png +0 -0
  96. package/dist/icons/icon-512x512.svg +12 -0
  97. package/dist/icons/icon-72x72.png +0 -0
  98. package/dist/icons/icon-72x72.svg +12 -0
  99. package/dist/icons/icon-96x96.png +0 -0
  100. package/dist/icons/icon-96x96.svg +12 -0
  101. package/dist/icons/icon-template.svg +12 -0
  102. package/dist/index.html +52 -0
  103. package/dist/logo-128.png +0 -0
  104. package/dist/logo-256.png +0 -0
  105. package/dist/logo-32.png +0 -0
  106. package/dist/logo-512.png +0 -0
  107. package/dist/logo-64.png +0 -0
  108. package/dist/logo.svg +17 -0
  109. package/dist/manifest.json +61 -0
  110. package/dist/screenshots/cli-selection.png +0 -0
  111. package/dist/screenshots/desktop-main.png +0 -0
  112. package/dist/screenshots/mobile-chat.png +0 -0
  113. package/dist/screenshots/tools-modal.png +0 -0
  114. package/dist/sw.js +124 -0
  115. package/dist-server/server/claude-sdk.js +738 -0
  116. package/dist-server/server/claude-sdk.js.map +1 -0
  117. package/dist-server/server/cli.js +641 -0
  118. package/dist-server/server/cli.js.map +1 -0
  119. package/dist-server/server/constants/config.js +6 -0
  120. package/dist-server/server/constants/config.js.map +1 -0
  121. package/dist-server/server/cursor-cli.js +271 -0
  122. package/dist-server/server/cursor-cli.js.map +1 -0
  123. package/dist-server/server/gemini-cli.js +539 -0
  124. package/dist-server/server/gemini-cli.js.map +1 -0
  125. package/dist-server/server/gemini-response-handler.js +72 -0
  126. package/dist-server/server/gemini-response-handler.js.map +1 -0
  127. package/dist-server/server/index.js +1340 -0
  128. package/dist-server/server/index.js.map +1 -0
  129. package/dist-server/server/load-env.js +32 -0
  130. package/dist-server/server/load-env.js.map +1 -0
  131. package/dist-server/server/middleware/auth.js +117 -0
  132. package/dist-server/server/middleware/auth.js.map +1 -0
  133. package/dist-server/server/modules/database/connection.js +125 -0
  134. package/dist-server/server/modules/database/connection.js.map +1 -0
  135. package/dist-server/server/modules/database/index.js +13 -0
  136. package/dist-server/server/modules/database/index.js.map +1 -0
  137. package/dist-server/server/modules/database/init-db.js +18 -0
  138. package/dist-server/server/modules/database/init-db.js.map +1 -0
  139. package/dist-server/server/modules/database/migrations.js +419 -0
  140. package/dist-server/server/modules/database/migrations.js.map +1 -0
  141. package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
  142. package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
  143. package/dist-server/server/modules/database/repositories/app-config.js +47 -0
  144. package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
  145. package/dist-server/server/modules/database/repositories/credentials.js +68 -0
  146. package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
  147. package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
  148. package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
  149. package/dist-server/server/modules/database/repositories/notification-preferences.js +72 -0
  150. package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
  151. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js +67 -0
  152. package/dist-server/server/modules/database/repositories/projects.db.integration.test.js.map +1 -0
  153. package/dist-server/server/modules/database/repositories/projects.db.js +185 -0
  154. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
  155. package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
  156. package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
  157. package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
  158. package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
  159. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js +64 -0
  160. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +1 -0
  161. package/dist-server/server/modules/database/repositories/sessions.db.js +150 -0
  162. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
  163. package/dist-server/server/modules/database/repositories/users.js +116 -0
  164. package/dist-server/server/modules/database/repositories/users.js.map +1 -0
  165. package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
  166. package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
  167. package/dist-server/server/modules/database/schema.js +150 -0
  168. package/dist-server/server/modules/database/schema.js.map +1 -0
  169. package/dist-server/server/modules/projects/index.js +4 -0
  170. package/dist-server/server/modules/projects/index.js.map +1 -0
  171. package/dist-server/server/modules/projects/projects.routes.js +225 -0
  172. package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
  173. package/dist-server/server/modules/projects/services/project-clone.service.js +220 -0
  174. package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
  175. package/dist-server/server/modules/projects/services/project-delete.service.js +83 -0
  176. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
  177. package/dist-server/server/modules/projects/services/project-management.service.js +99 -0
  178. package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
  179. package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
  180. package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
  181. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +171 -0
  182. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
  183. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +213 -0
  184. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
  185. package/dist-server/server/modules/projects/tests/project-clone.service.test.js +129 -0
  186. package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
  187. package/dist-server/server/modules/projects/tests/project-management.service.test.js +89 -0
  188. package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
  189. package/dist-server/server/modules/projects/tests/project-star.service.test.js +99 -0
  190. package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
  191. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +88 -0
  192. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
  193. package/dist-server/server/modules/providers/index.js +5 -0
  194. package/dist-server/server/modules/providers/index.js.map +1 -0
  195. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +104 -0
  196. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
  197. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
  198. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
  199. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +116 -0
  200. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
  201. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +546 -0
  202. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
  203. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +198 -0
  204. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
  205. package/dist-server/server/modules/providers/list/claude/claude.provider.js +17 -0
  206. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
  207. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
  208. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
  209. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
  210. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
  211. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +123 -0
  212. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
  213. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +513 -0
  214. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
  215. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +82 -0
  216. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
  217. package/dist-server/server/modules/providers/list/codex/codex.provider.js +17 -0
  218. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
  219. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
  220. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
  221. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
  222. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
  223. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +105 -0
  224. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
  225. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +545 -0
  226. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
  227. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +28 -0
  228. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
  229. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +17 -0
  230. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
  231. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +254 -0
  232. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
  233. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
  234. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
  235. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +312 -0
  236. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -0
  237. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +484 -0
  238. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
  239. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +33 -0
  240. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -0
  241. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +17 -0
  242. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
  243. package/dist-server/server/modules/providers/provider.registry.js +31 -0
  244. package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
  245. package/dist-server/server/modules/providers/provider.routes.js +377 -0
  246. package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
  247. package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
  248. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
  249. package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
  250. package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
  251. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +984 -0
  252. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
  253. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +56 -0
  254. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
  255. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +269 -0
  256. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
  257. package/dist-server/server/modules/providers/services/sessions.service.js +179 -0
  258. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
  259. package/dist-server/server/modules/providers/services/skills.service.js +11 -0
  260. package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
  261. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
  262. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
  263. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
  264. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
  265. package/dist-server/server/modules/providers/shared/skills/skills.provider.js +45 -0
  266. package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
  267. package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
  268. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
  269. package/dist-server/server/modules/providers/tests/skills.test.js +226 -0
  270. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
  271. package/dist-server/server/modules/websocket/index.js +3 -0
  272. package/dist-server/server/modules/websocket/index.js.map +1 -0
  273. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +192 -0
  274. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
  275. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
  276. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
  277. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +360 -0
  278. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
  279. package/dist-server/server/modules/websocket/services/websocket-auth.service.js +32 -0
  280. package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
  281. package/dist-server/server/modules/websocket/services/websocket-server.service.js +36 -0
  282. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
  283. package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
  284. package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
  285. package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
  286. package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
  287. package/dist-server/server/openai-codex.js +418 -0
  288. package/dist-server/server/openai-codex.js.map +1 -0
  289. package/dist-server/server/routes/admin.js +109 -0
  290. package/dist-server/server/routes/admin.js.map +1 -0
  291. package/dist-server/server/routes/agent.js +1145 -0
  292. package/dist-server/server/routes/agent.js.map +1 -0
  293. package/dist-server/server/routes/auth.js +123 -0
  294. package/dist-server/server/routes/auth.js.map +1 -0
  295. package/dist-server/server/routes/commands.js +487 -0
  296. package/dist-server/server/routes/commands.js.map +1 -0
  297. package/dist-server/server/routes/cursor.js +49 -0
  298. package/dist-server/server/routes/cursor.js.map +1 -0
  299. package/dist-server/server/routes/gemini.js +25 -0
  300. package/dist-server/server/routes/gemini.js.map +1 -0
  301. package/dist-server/server/routes/git.js +1263 -0
  302. package/dist-server/server/routes/git.js.map +1 -0
  303. package/dist-server/server/routes/mcp-utils.js +29 -0
  304. package/dist-server/server/routes/mcp-utils.js.map +1 -0
  305. package/dist-server/server/routes/plugins.js +266 -0
  306. package/dist-server/server/routes/plugins.js.map +1 -0
  307. package/dist-server/server/routes/settings.js +259 -0
  308. package/dist-server/server/routes/settings.js.map +1 -0
  309. package/dist-server/server/routes/taskmaster.js +1360 -0
  310. package/dist-server/server/routes/taskmaster.js.map +1 -0
  311. package/dist-server/server/routes/user.js +115 -0
  312. package/dist-server/server/routes/user.js.map +1 -0
  313. package/dist-server/server/services/notification-orchestrator.js +177 -0
  314. package/dist-server/server/services/notification-orchestrator.js.map +1 -0
  315. package/dist-server/server/services/vapid-keys.js +27 -0
  316. package/dist-server/server/services/vapid-keys.js.map +1 -0
  317. package/dist-server/server/sessionManager.js +215 -0
  318. package/dist-server/server/sessionManager.js.map +1 -0
  319. package/dist-server/server/shared/claude-cli-path.js +103 -0
  320. package/dist-server/server/shared/claude-cli-path.js.map +1 -0
  321. package/dist-server/server/shared/claude-cli-path.test.js +45 -0
  322. package/dist-server/server/shared/claude-cli-path.test.js.map +1 -0
  323. package/dist-server/server/shared/default-user.js +29 -0
  324. package/dist-server/server/shared/default-user.js.map +1 -0
  325. package/dist-server/server/shared/frontmatter.js +16 -0
  326. package/dist-server/server/shared/frontmatter.js.map +1 -0
  327. package/dist-server/server/shared/interfaces.js +2 -0
  328. package/dist-server/server/shared/interfaces.js.map +1 -0
  329. package/dist-server/server/shared/types.js +2 -0
  330. package/dist-server/server/shared/types.js.map +1 -0
  331. package/dist-server/server/shared/utils.js +633 -0
  332. package/dist-server/server/shared/utils.js.map +1 -0
  333. package/dist-server/server/utils/colors.js +20 -0
  334. package/dist-server/server/utils/colors.js.map +1 -0
  335. package/dist-server/server/utils/commandParser.js +255 -0
  336. package/dist-server/server/utils/commandParser.js.map +1 -0
  337. package/dist-server/server/utils/gitConfig.js +36 -0
  338. package/dist-server/server/utils/gitConfig.js.map +1 -0
  339. package/dist-server/server/utils/mcp-detector.js +134 -0
  340. package/dist-server/server/utils/mcp-detector.js.map +1 -0
  341. package/dist-server/server/utils/plugin-loader.js +413 -0
  342. package/dist-server/server/utils/plugin-loader.js.map +1 -0
  343. package/dist-server/server/utils/plugin-process-manager.js +163 -0
  344. package/dist-server/server/utils/plugin-process-manager.js.map +1 -0
  345. package/dist-server/server/utils/runtime-paths.js +30 -0
  346. package/dist-server/server/utils/runtime-paths.js.map +1 -0
  347. package/dist-server/server/utils/taskmaster-websocket.js +124 -0
  348. package/dist-server/server/utils/taskmaster-websocket.js.map +1 -0
  349. package/dist-server/server/utils/url-detection.js +58 -0
  350. package/dist-server/server/utils/url-detection.js.map +1 -0
  351. package/dist-server/shared/modelConstants.js +99 -0
  352. package/dist-server/shared/modelConstants.js.map +1 -0
  353. package/dist-server/shared/networkHosts.js +20 -0
  354. package/dist-server/shared/networkHosts.js.map +1 -0
  355. package/package.json +169 -0
  356. package/scripts/fix-node-pty.js +67 -0
  357. package/server/claude-sdk.js +864 -0
  358. package/server/cli.js +688 -0
  359. package/server/constants/config.js +5 -0
  360. package/server/cursor-cli.js +334 -0
  361. package/server/gemini-cli.js +622 -0
  362. package/server/gemini-response-handler.js +79 -0
  363. package/server/index.js +1505 -0
  364. package/server/load-env.js +34 -0
  365. package/server/middleware/auth.js +142 -0
  366. package/server/modules/database/connection.ts +143 -0
  367. package/server/modules/database/index.ts +12 -0
  368. package/server/modules/database/init-db.ts +17 -0
  369. package/server/modules/database/migrations.ts +496 -0
  370. package/server/modules/database/repositories/api-keys.ts +119 -0
  371. package/server/modules/database/repositories/app-config.ts +53 -0
  372. package/server/modules/database/repositories/credentials.ts +106 -0
  373. package/server/modules/database/repositories/github-tokens.ts +100 -0
  374. package/server/modules/database/repositories/notification-preferences.ts +103 -0
  375. package/server/modules/database/repositories/projects.db.integration.test.ts +78 -0
  376. package/server/modules/database/repositories/projects.db.ts +210 -0
  377. package/server/modules/database/repositories/push-subscriptions.ts +80 -0
  378. package/server/modules/database/repositories/scan-state.db.ts +42 -0
  379. package/server/modules/database/repositories/sessions.db.integration.test.ts +78 -0
  380. package/server/modules/database/repositories/sessions.db.ts +230 -0
  381. package/server/modules/database/repositories/users.ts +186 -0
  382. package/server/modules/database/repositories/vapid-keys.ts +57 -0
  383. package/server/modules/database/schema.ts +159 -0
  384. package/server/modules/projects/index.ts +6 -0
  385. package/server/modules/projects/projects.routes.ts +292 -0
  386. package/server/modules/projects/services/project-clone.service.ts +327 -0
  387. package/server/modules/projects/services/project-delete.service.ts +95 -0
  388. package/server/modules/projects/services/project-management.service.ts +158 -0
  389. package/server/modules/projects/services/project-star.service.ts +78 -0
  390. package/server/modules/projects/services/projects-has-taskmaster.service.ts +257 -0
  391. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +355 -0
  392. package/server/modules/projects/tests/project-clone.service.test.ts +186 -0
  393. package/server/modules/projects/tests/project-management.service.test.ts +122 -0
  394. package/server/modules/projects/tests/project-star.service.test.ts +128 -0
  395. package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +107 -0
  396. package/server/modules/providers/README.md +346 -0
  397. package/server/modules/providers/index.ts +5 -0
  398. package/server/modules/providers/list/claude/claude-auth.provider.ts +124 -0
  399. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
  400. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +179 -0
  401. package/server/modules/providers/list/claude/claude-sessions.provider.ts +642 -0
  402. package/server/modules/providers/list/claude/claude-skills.provider.ts +257 -0
  403. package/server/modules/providers/list/claude/claude.provider.ts +24 -0
  404. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
  405. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
  406. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +182 -0
  407. package/server/modules/providers/list/codex/codex-sessions.provider.ts +589 -0
  408. package/server/modules/providers/list/codex/codex-skills.provider.ts +100 -0
  409. package/server/modules/providers/list/codex/codex.provider.ts +24 -0
  410. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
  411. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
  412. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +155 -0
  413. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +624 -0
  414. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +31 -0
  415. package/server/modules/providers/list/cursor/cursor.provider.ts +24 -0
  416. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +307 -0
  417. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
  418. package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +407 -0
  419. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +552 -0
  420. package/server/modules/providers/list/gemini/gemini-skills.provider.ts +36 -0
  421. package/server/modules/providers/list/gemini/gemini.provider.ts +24 -0
  422. package/server/modules/providers/provider.registry.ts +36 -0
  423. package/server/modules/providers/provider.routes.ts +488 -0
  424. package/server/modules/providers/services/mcp.service.ts +94 -0
  425. package/server/modules/providers/services/provider-auth.service.ts +26 -0
  426. package/server/modules/providers/services/session-conversations-search.service.ts +1319 -0
  427. package/server/modules/providers/services/session-synchronizer.service.ts +75 -0
  428. package/server/modules/providers/services/sessions-watcher.service.ts +318 -0
  429. package/server/modules/providers/services/sessions.service.ts +240 -0
  430. package/server/modules/providers/services/skills.service.ts +15 -0
  431. package/server/modules/providers/shared/base/abstract.provider.ts +29 -0
  432. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
  433. package/server/modules/providers/shared/skills/skills.provider.ts +64 -0
  434. package/server/modules/providers/tests/mcp.test.ts +293 -0
  435. package/server/modules/providers/tests/skills.test.ts +446 -0
  436. package/server/modules/websocket/README.md +267 -0
  437. package/server/modules/websocket/index.ts +2 -0
  438. package/server/modules/websocket/services/chat-websocket.service.ts +275 -0
  439. package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
  440. package/server/modules/websocket/services/shell-websocket.service.ts +489 -0
  441. package/server/modules/websocket/services/websocket-auth.service.ts +54 -0
  442. package/server/modules/websocket/services/websocket-server.service.ts +58 -0
  443. package/server/modules/websocket/services/websocket-state.service.ts +16 -0
  444. package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
  445. package/server/openai-codex.js +474 -0
  446. package/server/routes/admin.js +128 -0
  447. package/server/routes/agent.js +1246 -0
  448. package/server/routes/auth.js +144 -0
  449. package/server/routes/commands.js +556 -0
  450. package/server/routes/cursor.js +52 -0
  451. package/server/routes/gemini.js +30 -0
  452. package/server/routes/git.js +1493 -0
  453. package/server/routes/mcp-utils.js +31 -0
  454. package/server/routes/plugins.js +307 -0
  455. package/server/routes/settings.js +286 -0
  456. package/server/routes/taskmaster.js +1468 -0
  457. package/server/routes/user.js +123 -0
  458. package/server/services/notification-orchestrator.js +228 -0
  459. package/server/services/vapid-keys.js +36 -0
  460. package/server/sessionManager.js +248 -0
  461. package/server/shared/claude-cli-path.test.ts +61 -0
  462. package/server/shared/claude-cli-path.ts +139 -0
  463. package/server/shared/default-user.ts +30 -0
  464. package/server/shared/frontmatter.ts +18 -0
  465. package/server/shared/interfaces.ts +111 -0
  466. package/server/shared/types.ts +406 -0
  467. package/server/shared/utils.ts +763 -0
  468. package/server/tsconfig.json +36 -0
  469. package/server/utils/colors.js +21 -0
  470. package/server/utils/commandParser.js +305 -0
  471. package/server/utils/gitConfig.js +34 -0
  472. package/server/utils/mcp-detector.js +147 -0
  473. package/server/utils/plugin-loader.js +457 -0
  474. package/server/utils/plugin-process-manager.js +184 -0
  475. package/server/utils/runtime-paths.js +37 -0
  476. package/server/utils/taskmaster-websocket.js +135 -0
  477. package/server/utils/url-detection.js +71 -0
  478. package/shared/modelConstants.js +107 -0
  479. package/shared/networkHosts.js +22 -0
@@ -0,0 +1,257 @@
1
+ import { readFile, readdir, stat } from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
5
+ import { SkillsProvider } from '@/modules/providers/shared/skills/skills.provider.js';
6
+ import { parseFrontMatter } from '@/shared/frontmatter.js';
7
+ import type {
8
+ ProviderSkill,
9
+ ProviderSkillListOptions,
10
+ ProviderSkillSource,
11
+ } from '@/shared/types.js';
12
+ import {
13
+ findProviderSkillMarkdownFiles,
14
+ readJsonConfig,
15
+ readObjectRecord,
16
+ readOptionalString,
17
+ readProviderSkillMarkdownDefinition,
18
+ } from '@/shared/utils.js';
19
+
20
+ const getClaudeHomePath = (): string => path.join(os.homedir(), '.claude');
21
+
22
+ const getClaudePluginName = (pluginId: string): string | null => {
23
+ const normalizedPluginId = pluginId.trim();
24
+ if (!normalizedPluginId || normalizedPluginId === '@') {
25
+ return null;
26
+ }
27
+
28
+ const [pluginName] = normalizedPluginId.split('@');
29
+ return readOptionalString(pluginName) ?? null;
30
+ };
31
+
32
+ const stripMarkdownExtension = (filename: string): string =>
33
+ filename.replace(/\.md$/i, '');
34
+
35
+ const pathExistsAsDirectory = async (directoryPath: string): Promise<boolean> => {
36
+ try {
37
+ const directoryStats = await stat(directoryPath);
38
+ return directoryStats.isDirectory();
39
+ } catch {
40
+ return false;
41
+ }
42
+ };
43
+
44
+ const listChildDirectories = async (directoryPath: string): Promise<string[]> => {
45
+ try {
46
+ const entries = await readdir(directoryPath, { withFileTypes: true });
47
+ return entries
48
+ .filter((entry) => entry.isDirectory())
49
+ .map((entry) => path.join(directoryPath, entry.name))
50
+ .sort((left, right) => left.localeCompare(right));
51
+ } catch {
52
+ return [];
53
+ }
54
+ };
55
+
56
+ const readClaudePluginName = async (
57
+ installPath: string,
58
+ pluginId: string,
59
+ ): Promise<string | null> => {
60
+ try {
61
+ const pluginConfig = await readJsonConfig(
62
+ path.join(installPath, '.claude-plugin', 'plugin.json'),
63
+ );
64
+
65
+ // Older or partial plugin installs may not have plugin.json yet. Falling
66
+ // back keeps discovery useful without inventing a separate namespace.
67
+ return readOptionalString(pluginConfig.name) ?? getClaudePluginName(pluginId);
68
+ } catch {
69
+ return getClaudePluginName(pluginId);
70
+ }
71
+ };
72
+
73
+ export class ClaudeSkillsProvider extends SkillsProvider {
74
+ constructor() {
75
+ super('claude');
76
+ }
77
+
78
+ async listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]> {
79
+ return [
80
+ ...(await super.listSkills(options)),
81
+ ...(await this.listPluginSkills(getClaudeHomePath())),
82
+ ];
83
+ }
84
+
85
+ protected async getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]> {
86
+ const claudeHomePath = getClaudeHomePath();
87
+
88
+ return [
89
+ {
90
+ scope: 'user',
91
+ rootDir: path.join(claudeHomePath, 'skills'),
92
+ commandPrefix: '/',
93
+ },
94
+ {
95
+ scope: 'project',
96
+ rootDir: path.join(workspacePath, '.claude', 'skills'),
97
+ commandPrefix: '/',
98
+ },
99
+ ];
100
+ }
101
+
102
+ private async listPluginSkills(claudeHomePath: string): Promise<ProviderSkill[]> {
103
+ const settings = await readJsonConfig(path.join(claudeHomePath, 'settings.json'));
104
+ const enabledPlugins = readObjectRecord(settings.enabledPlugins);
105
+ if (!enabledPlugins) {
106
+ return [];
107
+ }
108
+
109
+ const installedConfig = await readJsonConfig(
110
+ path.join(claudeHomePath, 'plugins', 'installed_plugins.json'),
111
+ );
112
+ const installedPlugins = readObjectRecord(installedConfig.plugins);
113
+ if (!installedPlugins) {
114
+ return [];
115
+ }
116
+
117
+ const skills: ProviderSkill[] = [];
118
+ const visitedPluginFolders = new Set<string>();
119
+ const pluginEntries = Object.entries(enabledPlugins)
120
+ .sort(([left], [right]) => left.localeCompare(right));
121
+ for (const [pluginId, enabled] of pluginEntries) {
122
+ if (enabled !== true) {
123
+ continue;
124
+ }
125
+
126
+ const installs = installedPlugins[pluginId];
127
+ if (!Array.isArray(installs)) {
128
+ continue;
129
+ }
130
+
131
+ for (const install of installs) {
132
+ const installRecord = readObjectRecord(install);
133
+ const installPath = readOptionalString(installRecord?.installPath);
134
+ if (!installPath) {
135
+ continue;
136
+ }
137
+
138
+ // Claude's installed path points at one version folder; the usable
139
+ // plugin payloads live in the direct child folders beside it.
140
+ const pluginFolders = await listChildDirectories(path.dirname(installPath));
141
+ for (const pluginFolder of pluginFolders) {
142
+ const pluginFolderKey = `${pluginId}:${path.resolve(pluginFolder)}`;
143
+ if (visitedPluginFolders.has(pluginFolderKey)) {
144
+ continue;
145
+ }
146
+ visitedPluginFolders.add(pluginFolderKey);
147
+
148
+ const pluginName = await readClaudePluginName(pluginFolder, pluginId);
149
+ if (!pluginName) {
150
+ continue;
151
+ }
152
+
153
+ const commandsPath = path.join(pluginFolder, 'commands');
154
+ if (await pathExistsAsDirectory(commandsPath)) {
155
+ skills.push(
156
+ ...(await this.listPluginCommandSkills(commandsPath, pluginId, pluginName)),
157
+ );
158
+ continue;
159
+ }
160
+
161
+ const skillsPath = path.join(pluginFolder, 'skills');
162
+ if (!(await pathExistsAsDirectory(skillsPath))) {
163
+ continue;
164
+ }
165
+
166
+ skills.push(
167
+ ...(await this.listPluginSkillMarkdowns(pluginFolder, pluginId, pluginName)),
168
+ );
169
+ }
170
+ }
171
+ }
172
+
173
+ return skills;
174
+ }
175
+
176
+ private async listPluginCommandSkills(
177
+ commandsPath: string,
178
+ pluginId: string,
179
+ pluginName: string,
180
+ ): Promise<ProviderSkill[]> {
181
+ const skills: ProviderSkill[] = [];
182
+
183
+ try {
184
+ const entries = await readdir(commandsPath, { withFileTypes: true });
185
+ const commandFiles = entries
186
+ .filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.md'))
187
+ .sort((left, right) => left.name.localeCompare(right.name));
188
+
189
+ for (const commandFile of commandFiles) {
190
+ const sourcePath = path.join(commandsPath, commandFile.name);
191
+ try {
192
+ const definition = await this.readPluginCommandDefinition(sourcePath);
193
+ skills.push({
194
+ provider: this.provider,
195
+ name: definition.name,
196
+ description: definition.description,
197
+ command: `/${pluginName}:${definition.name}`,
198
+ scope: 'plugin',
199
+ sourcePath,
200
+ pluginName,
201
+ pluginId,
202
+ });
203
+ } catch {
204
+ // Malformed command markdown should not block sibling plugin commands.
205
+ }
206
+ }
207
+ } catch {
208
+ // Missing or unreadable command folders are treated as empty plugin command sets.
209
+ }
210
+
211
+ return skills;
212
+ }
213
+
214
+ private async readPluginCommandDefinition(
215
+ commandPath: string,
216
+ ): Promise<{ name: string; description: string }> {
217
+ const content = await readFile(commandPath, 'utf8');
218
+ const parsed = parseFrontMatter(content);
219
+ const data = readObjectRecord(parsed.data) ?? {};
220
+
221
+ return {
222
+ name: stripMarkdownExtension(path.basename(commandPath)),
223
+ description: readOptionalString(data.description) ?? '',
224
+ };
225
+ }
226
+
227
+ private async listPluginSkillMarkdowns(
228
+ installPath: string,
229
+ pluginId: string,
230
+ pluginName: string,
231
+ ): Promise<ProviderSkill[]> {
232
+ const skillFiles = await findProviderSkillMarkdownFiles(path.join(installPath, 'skills'), {
233
+ recursive: true,
234
+ });
235
+ const skills: ProviderSkill[] = [];
236
+
237
+ for (const skillPath of skillFiles) {
238
+ try {
239
+ const definition = await readProviderSkillMarkdownDefinition(skillPath);
240
+ skills.push({
241
+ provider: this.provider,
242
+ name: definition.name,
243
+ description: definition.description,
244
+ command: `/${pluginName}:${definition.name}`,
245
+ scope: 'plugin',
246
+ sourcePath: skillPath,
247
+ pluginName,
248
+ pluginId,
249
+ });
250
+ } catch {
251
+ // A bad plugin skill file should not block other installed plugin skills.
252
+ }
253
+ }
254
+
255
+ return skills;
256
+ }
257
+ }
@@ -0,0 +1,24 @@
1
+ import { AbstractProvider } from '@/modules/providers/shared/base/abstract.provider.js';
2
+ import { ClaudeProviderAuth } from '@/modules/providers/list/claude/claude-auth.provider.js';
3
+ import { ClaudeMcpProvider } from '@/modules/providers/list/claude/claude-mcp.provider.js';
4
+ import { ClaudeSessionSynchronizer } from '@/modules/providers/list/claude/claude-session-synchronizer.provider.js';
5
+ import { ClaudeSessionsProvider } from '@/modules/providers/list/claude/claude-sessions.provider.js';
6
+ import { ClaudeSkillsProvider } from '@/modules/providers/list/claude/claude-skills.provider.js';
7
+ import type {
8
+ IProviderAuth,
9
+ IProviderSessionSynchronizer,
10
+ IProviderSkills,
11
+ IProviderSessions,
12
+ } from '@/shared/interfaces.js';
13
+
14
+ export class ClaudeProvider extends AbstractProvider {
15
+ readonly mcp = new ClaudeMcpProvider();
16
+ readonly auth: IProviderAuth = new ClaudeProviderAuth();
17
+ readonly skills: IProviderSkills = new ClaudeSkillsProvider();
18
+ readonly sessions: IProviderSessions = new ClaudeSessionsProvider();
19
+ readonly sessionSynchronizer: IProviderSessionSynchronizer = new ClaudeSessionSynchronizer();
20
+
21
+ constructor() {
22
+ super('claude');
23
+ }
24
+ }
@@ -0,0 +1,100 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
5
+ import spawn from 'cross-spawn';
6
+
7
+ import type { IProviderAuth } from '@/shared/interfaces.js';
8
+ import type { ProviderAuthStatus } from '@/shared/types.js';
9
+ import { readObjectRecord, readOptionalString } from '@/shared/utils.js';
10
+
11
+ type CodexCredentialsStatus = {
12
+ authenticated: boolean;
13
+ email: string | null;
14
+ method: string | null;
15
+ error?: string;
16
+ };
17
+
18
+ export class CodexProviderAuth implements IProviderAuth {
19
+ /**
20
+ * Checks whether Codex is available to the server runtime.
21
+ */
22
+ private checkInstalled(): boolean {
23
+ try {
24
+ spawn.sync('codex', ['--version'], { stdio: 'ignore', timeout: 5000 });
25
+ return true;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Returns Codex SDK availability and credential status.
33
+ */
34
+ async getStatus(): Promise<ProviderAuthStatus> {
35
+ const installed = this.checkInstalled();
36
+ const credentials = await this.checkCredentials();
37
+
38
+ return {
39
+ installed,
40
+ provider: 'codex',
41
+ authenticated: credentials.authenticated,
42
+ email: credentials.email,
43
+ method: credentials.method,
44
+ error: credentials.authenticated ? undefined : credentials.error || 'Not authenticated',
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Reads Codex auth.json and checks OAuth tokens or an API key fallback.
50
+ */
51
+ private async checkCredentials(): Promise<CodexCredentialsStatus> {
52
+ try {
53
+ const authPath = path.join(os.homedir(), '.codex', 'auth.json');
54
+ const content = await readFile(authPath, 'utf8');
55
+ const auth = readObjectRecord(JSON.parse(content)) ?? {};
56
+ const tokens = readObjectRecord(auth.tokens) ?? {};
57
+ const idToken = readOptionalString(tokens.id_token);
58
+ const accessToken = readOptionalString(tokens.access_token);
59
+
60
+ if (idToken || accessToken) {
61
+ return {
62
+ authenticated: true,
63
+ email: idToken ? this.readEmailFromIdToken(idToken) : 'Authenticated',
64
+ method: 'credentials_file',
65
+ };
66
+ }
67
+
68
+ if (readOptionalString(auth.OPENAI_API_KEY)) {
69
+ return { authenticated: true, email: 'API Key Auth', method: 'api_key' };
70
+ }
71
+
72
+ return { authenticated: false, email: null, method: null, error: 'No valid tokens found' };
73
+ } catch (error) {
74
+ const code = (error as NodeJS.ErrnoException).code;
75
+ return {
76
+ authenticated: false,
77
+ email: null,
78
+ method: null,
79
+ error: code === 'ENOENT' ? 'Codex not configured' : error instanceof Error ? error.message : 'Failed to read Codex auth',
80
+ };
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Extracts the user email from a Codex id_token when a readable JWT payload exists.
86
+ */
87
+ private readEmailFromIdToken(idToken: string): string {
88
+ try {
89
+ const parts = idToken.split('.');
90
+ if (parts.length >= 2) {
91
+ const payload = readObjectRecord(JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8')));
92
+ return readOptionalString(payload?.email) ?? readOptionalString(payload?.user) ?? 'Authenticated';
93
+ }
94
+ } catch {
95
+ // Fall back to a generic authenticated marker if the token payload is not readable.
96
+ }
97
+
98
+ return 'Authenticated';
99
+ }
100
+ }
@@ -0,0 +1,135 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
5
+ import TOML from '@iarna/toml';
6
+
7
+ import { McpProvider } from '@/modules/providers/shared/mcp/mcp.provider.js';
8
+ import type { McpScope, ProviderMcpServer, UpsertProviderMcpServerInput } from '@/shared/types.js';
9
+ import {
10
+ AppError,
11
+ readObjectRecord,
12
+ readOptionalString,
13
+ readStringArray,
14
+ readStringRecord,
15
+ } from '@/shared/utils.js';
16
+
17
+ const readTomlConfig = async (filePath: string): Promise<Record<string, unknown>> => {
18
+ try {
19
+ const content = await readFile(filePath, 'utf8');
20
+ const parsed = TOML.parse(content) as Record<string, unknown>;
21
+ return readObjectRecord(parsed) ?? {};
22
+ } catch (error) {
23
+ const code = (error as NodeJS.ErrnoException).code;
24
+ if (code === 'ENOENT') {
25
+ return {};
26
+ }
27
+ throw error;
28
+ }
29
+ };
30
+
31
+ const writeTomlConfig = async (filePath: string, data: Record<string, unknown>): Promise<void> => {
32
+ await mkdir(path.dirname(filePath), { recursive: true });
33
+ const toml = TOML.stringify(data as never);
34
+ await writeFile(filePath, toml, 'utf8');
35
+ };
36
+
37
+ export class CodexMcpProvider extends McpProvider {
38
+ constructor() {
39
+ super('codex', ['user', 'project'], ['stdio', 'http']);
40
+ }
41
+
42
+ protected async readScopedServers(scope: McpScope, workspacePath: string): Promise<Record<string, unknown>> {
43
+ const filePath = scope === 'user'
44
+ ? path.join(os.homedir(), '.codex', 'config.toml')
45
+ : path.join(workspacePath, '.codex', 'config.toml');
46
+ const config = await readTomlConfig(filePath);
47
+ return readObjectRecord(config.mcp_servers) ?? {};
48
+ }
49
+
50
+ protected async writeScopedServers(
51
+ scope: McpScope,
52
+ workspacePath: string,
53
+ servers: Record<string, unknown>,
54
+ ): Promise<void> {
55
+ const filePath = scope === 'user'
56
+ ? path.join(os.homedir(), '.codex', 'config.toml')
57
+ : path.join(workspacePath, '.codex', 'config.toml');
58
+ const config = await readTomlConfig(filePath);
59
+ config.mcp_servers = servers;
60
+ await writeTomlConfig(filePath, config);
61
+ }
62
+
63
+ protected buildServerConfig(input: UpsertProviderMcpServerInput): Record<string, unknown> {
64
+ if (input.transport === 'stdio') {
65
+ if (!input.command?.trim()) {
66
+ throw new AppError('command is required for stdio MCP servers.', {
67
+ code: 'MCP_COMMAND_REQUIRED',
68
+ statusCode: 400,
69
+ });
70
+ }
71
+
72
+ return {
73
+ command: input.command,
74
+ args: input.args ?? [],
75
+ env: input.env ?? {},
76
+ env_vars: input.envVars ?? [],
77
+ cwd: input.cwd,
78
+ };
79
+ }
80
+
81
+ if (!input.url?.trim()) {
82
+ throw new AppError('url is required for http MCP servers.', {
83
+ code: 'MCP_URL_REQUIRED',
84
+ statusCode: 400,
85
+ });
86
+ }
87
+
88
+ return {
89
+ url: input.url,
90
+ bearer_token_env_var: input.bearerTokenEnvVar,
91
+ http_headers: input.headers ?? {},
92
+ env_http_headers: input.envHttpHeaders ?? {},
93
+ };
94
+ }
95
+
96
+ protected normalizeServerConfig(
97
+ scope: McpScope,
98
+ name: string,
99
+ rawConfig: unknown,
100
+ ): ProviderMcpServer | null {
101
+ if (!rawConfig || typeof rawConfig !== 'object') {
102
+ return null;
103
+ }
104
+
105
+ const config = rawConfig as Record<string, unknown>;
106
+ if (typeof config.command === 'string') {
107
+ return {
108
+ provider: 'codex',
109
+ name,
110
+ scope,
111
+ transport: 'stdio',
112
+ command: config.command,
113
+ args: readStringArray(config.args),
114
+ env: readStringRecord(config.env),
115
+ cwd: readOptionalString(config.cwd),
116
+ envVars: readStringArray(config.env_vars),
117
+ };
118
+ }
119
+
120
+ if (typeof config.url === 'string') {
121
+ return {
122
+ provider: 'codex',
123
+ name,
124
+ scope,
125
+ transport: 'http',
126
+ url: config.url,
127
+ headers: readStringRecord(config.http_headers),
128
+ bearerTokenEnvVar: readOptionalString(config.bearer_token_env_var),
129
+ envHttpHeaders: readStringRecord(config.env_http_headers),
130
+ };
131
+ }
132
+
133
+ return null;
134
+ }
135
+ }
@@ -0,0 +1,182 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ import { sessionsDb } from '@/modules/database/index.js';
6
+ import {
7
+ buildLookupMap,
8
+ extractFirstValidJsonlData,
9
+ findFilesRecursivelyCreatedAfter,
10
+ normalizeSessionName,
11
+ readFileTimestamps,
12
+ } from '@/shared/utils.js';
13
+ import type { IProviderSessionSynchronizer } from '@/shared/interfaces.js';
14
+
15
+ type ParsedSession = {
16
+ sessionId: string;
17
+ projectPath: string;
18
+ sessionName?: string;
19
+ };
20
+
21
+ /**
22
+ * Session indexer for Codex transcript artifacts.
23
+ */
24
+ export class CodexSessionSynchronizer implements IProviderSessionSynchronizer {
25
+ private readonly provider = 'codex' as const;
26
+ private readonly codexHome = path.join(os.homedir(), '.codex');
27
+
28
+ /**
29
+ * Scans ~/.codex/sessions and upserts discovered sessions into DB.
30
+ */
31
+ async synchronize(since: Date | undefined, ownerUserId: number): Promise<number> {
32
+ const nameMap = await buildLookupMap(path.join(this.codexHome, 'session_index.jsonl'), 'id', 'thread_name');
33
+ const files = await findFilesRecursivelyCreatedAfter(
34
+ path.join(this.codexHome, 'sessions'),
35
+ '.jsonl',
36
+ since ?? null
37
+ );
38
+
39
+ let processed = 0;
40
+ for (const filePath of files) {
41
+ const parsed = await this.processSessionFile(ownerUserId, filePath, nameMap);
42
+ if (!parsed) {
43
+ continue;
44
+ }
45
+
46
+ const existingSession = sessionsDb.getSessionById(ownerUserId, parsed.sessionId);
47
+ if (existingSession) {
48
+ // If session name is untitled and we now have a name, update it
49
+ if (existingSession.custom_name === 'Untitled Codex Session' && parsed.sessionName && parsed.sessionName !== 'Untitled Codex Session') {
50
+ sessionsDb.updateSessionCustomName(ownerUserId, parsed.sessionId, parsed.sessionName);
51
+ }
52
+ }
53
+
54
+ const timestamps = await readFileTimestamps(filePath);
55
+ sessionsDb.createSession(
56
+ ownerUserId,
57
+ parsed.sessionId,
58
+ this.provider,
59
+ parsed.projectPath,
60
+ parsed.sessionName,
61
+ timestamps.createdAt,
62
+ timestamps.updatedAt,
63
+ filePath
64
+ );
65
+ processed += 1;
66
+ }
67
+
68
+ return processed;
69
+ }
70
+
71
+ /**
72
+ * Parses and upserts one Codex session JSONL file.
73
+ */
74
+ async synchronizeFile(filePath: string, ownerUserId: number): Promise<string | null> {
75
+ if (!filePath.endsWith('.jsonl')) {
76
+ return null;
77
+ }
78
+
79
+ const nameMap = await buildLookupMap(path.join(this.codexHome, 'session_index.jsonl'), 'id', 'thread_name');
80
+ const parsed = await this.processSessionFile(ownerUserId, filePath, nameMap);
81
+ if (!parsed) {
82
+ return null;
83
+ }
84
+
85
+ const timestamps = await readFileTimestamps(filePath);
86
+ return sessionsDb.createSession(
87
+ ownerUserId,
88
+ parsed.sessionId,
89
+ this.provider,
90
+ parsed.projectPath,
91
+ parsed.sessionName,
92
+ timestamps.createdAt,
93
+ timestamps.updatedAt,
94
+ filePath
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Extracts session metadata from one Codex JSONL session file.
100
+ */
101
+ private async processSessionFile(
102
+ ownerUserId: number,
103
+ filePath: string,
104
+ nameMap: Map<string, string>
105
+ ): Promise<ParsedSession | null> {
106
+ const parsed = await extractFirstValidJsonlData(filePath, (rawData) => {
107
+ const data = rawData as Record<string, unknown>;
108
+ const payload = data.payload as Record<string, unknown> | undefined;
109
+ const sessionId = typeof payload?.id === 'string' ? payload.id : undefined;
110
+ const projectPath = typeof payload?.cwd === 'string' ? payload.cwd : undefined;
111
+
112
+ if (!sessionId || !projectPath) {
113
+ return null;
114
+ }
115
+
116
+ return {
117
+ sessionId,
118
+ projectPath,
119
+ };
120
+ });
121
+
122
+ if (!parsed) {
123
+ return null;
124
+ }
125
+
126
+ const existingSession = sessionsDb.getSessionById(ownerUserId, parsed.sessionId);
127
+ const existingSessionName = existingSession?.custom_name;
128
+ if (existingSessionName && existingSessionName !== 'Untitled Codex Session') {
129
+ return {
130
+ ...parsed,
131
+ sessionName: normalizeSessionName(existingSessionName, 'Untitled Codex Session'),
132
+ };
133
+ }
134
+
135
+ let sessionName = nameMap.get(parsed.sessionId);
136
+ if (!sessionName) {
137
+ sessionName = await this.extractLastAgentMessageFromEnd(filePath);
138
+ }
139
+
140
+ return {
141
+ ...parsed,
142
+ sessionName: normalizeSessionName(sessionName, 'Untitled Codex Session'),
143
+ };
144
+ }
145
+
146
+ private async extractLastAgentMessageFromEnd(filePath: string): Promise<string | undefined> {
147
+ try {
148
+ const content = await readFile(filePath, 'utf8');
149
+ const lines = content.split(/\r?\n/);
150
+
151
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
152
+ const line = lines[index]?.trim();
153
+ if (!line) {
154
+ continue;
155
+ }
156
+
157
+ let parsed: unknown;
158
+ try {
159
+ parsed = JSON.parse(line);
160
+ } catch {
161
+ continue;
162
+ }
163
+
164
+ const data = parsed as Record<string, unknown>;
165
+ const eventType = typeof data.type === 'string' ? data.type : undefined;
166
+ const payload = data.payload as Record<string, unknown> | undefined;
167
+ const payloadType = typeof payload?.type === 'string' ? payload.type : undefined;
168
+ const lastAgentMessage = typeof payload?.last_agent_message === 'string'
169
+ ? payload.last_agent_message
170
+ : undefined;
171
+
172
+ if (eventType === 'event_msg' && payloadType === 'task_complete' && lastAgentMessage?.trim()) {
173
+ return lastAgentMessage;
174
+ }
175
+ }
176
+ } catch {
177
+ // Ignore missing/unreadable files so sync can continue.
178
+ }
179
+
180
+ return undefined;
181
+ }
182
+ }