claude-code-workflow 6.2.2 → 6.2.4

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 (346) hide show
  1. package/ccw/dist/cli.d.ts +2 -0
  2. package/ccw/dist/cli.d.ts.map +1 -0
  3. package/ccw/dist/cli.js +219 -0
  4. package/ccw/dist/cli.js.map +1 -0
  5. package/ccw/dist/commands/cli.d.ts +32 -0
  6. package/ccw/dist/commands/cli.d.ts.map +1 -0
  7. package/ccw/dist/commands/cli.js +619 -0
  8. package/ccw/dist/commands/cli.js.map +1 -0
  9. package/ccw/dist/commands/core-memory.d.ts +32 -0
  10. package/ccw/dist/commands/core-memory.d.ts.map +1 -0
  11. package/ccw/dist/commands/core-memory.js +640 -0
  12. package/ccw/dist/commands/core-memory.js.map +1 -0
  13. package/ccw/dist/commands/hook.d.ts +16 -0
  14. package/ccw/dist/commands/hook.d.ts.map +1 -0
  15. package/ccw/dist/commands/hook.js +276 -0
  16. package/ccw/dist/commands/hook.js.map +1 -0
  17. package/ccw/dist/commands/install.d.ts +12 -0
  18. package/ccw/dist/commands/install.d.ts.map +1 -0
  19. package/ccw/dist/commands/install.js +443 -0
  20. package/ccw/dist/commands/install.js.map +1 -0
  21. package/ccw/dist/commands/list.d.ts +5 -0
  22. package/ccw/dist/commands/list.d.ts.map +1 -0
  23. package/ccw/dist/commands/list.js +32 -0
  24. package/ccw/dist/commands/list.js.map +1 -0
  25. package/ccw/dist/commands/memory.d.ts +57 -0
  26. package/ccw/dist/commands/memory.d.ts.map +1 -0
  27. package/ccw/dist/commands/memory.js +890 -0
  28. package/ccw/dist/commands/memory.js.map +1 -0
  29. package/ccw/dist/commands/serve.d.ts +12 -0
  30. package/ccw/dist/commands/serve.d.ts.map +1 -0
  31. package/ccw/dist/commands/serve.js +63 -0
  32. package/ccw/dist/commands/serve.js.map +1 -0
  33. package/ccw/dist/commands/session-path-resolver.d.ts +45 -0
  34. package/ccw/dist/commands/session-path-resolver.d.ts.map +1 -0
  35. package/ccw/dist/commands/session-path-resolver.js +302 -0
  36. package/ccw/dist/commands/session-path-resolver.js.map +1 -0
  37. package/ccw/dist/commands/session.d.ts +12 -0
  38. package/ccw/dist/commands/session.d.ts.map +1 -0
  39. package/ccw/dist/commands/session.js +954 -0
  40. package/ccw/dist/commands/session.js.map +1 -0
  41. package/ccw/dist/commands/stop.d.ts +11 -0
  42. package/ccw/dist/commands/stop.d.ts.map +1 -0
  43. package/ccw/dist/commands/stop.js +96 -0
  44. package/ccw/dist/commands/stop.js.map +1 -0
  45. package/ccw/dist/commands/tool.d.ts +29 -0
  46. package/ccw/dist/commands/tool.d.ts.map +1 -0
  47. package/ccw/dist/commands/tool.js +173 -0
  48. package/ccw/dist/commands/tool.js.map +1 -0
  49. package/ccw/dist/commands/uninstall.d.ts +9 -0
  50. package/ccw/dist/commands/uninstall.d.ts.map +1 -0
  51. package/ccw/dist/commands/uninstall.js +239 -0
  52. package/ccw/dist/commands/uninstall.js.map +1 -0
  53. package/ccw/dist/commands/upgrade.d.ts +10 -0
  54. package/ccw/dist/commands/upgrade.d.ts.map +1 -0
  55. package/ccw/dist/commands/upgrade.js +288 -0
  56. package/ccw/dist/commands/upgrade.js.map +1 -0
  57. package/ccw/dist/commands/view.d.ts +14 -0
  58. package/ccw/dist/commands/view.d.ts.map +1 -0
  59. package/ccw/dist/commands/view.js +100 -0
  60. package/ccw/dist/commands/view.js.map +1 -0
  61. package/ccw/dist/config/storage-paths.d.ts +184 -0
  62. package/ccw/dist/config/storage-paths.d.ts.map +1 -0
  63. package/ccw/dist/config/storage-paths.js +536 -0
  64. package/ccw/dist/config/storage-paths.js.map +1 -0
  65. package/ccw/dist/core/cache-manager.d.ts +80 -0
  66. package/ccw/dist/core/cache-manager.d.ts.map +1 -0
  67. package/ccw/dist/core/cache-manager.js +260 -0
  68. package/ccw/dist/core/cache-manager.js.map +1 -0
  69. package/ccw/dist/core/claude-freshness.d.ts +53 -0
  70. package/ccw/dist/core/claude-freshness.d.ts.map +1 -0
  71. package/ccw/dist/core/claude-freshness.js +232 -0
  72. package/ccw/dist/core/claude-freshness.js.map +1 -0
  73. package/ccw/dist/core/core-memory-store.d.ts +320 -0
  74. package/ccw/dist/core/core-memory-store.d.ts.map +1 -0
  75. package/ccw/dist/core/core-memory-store.js +1177 -0
  76. package/ccw/dist/core/core-memory-store.js.map +1 -0
  77. package/ccw/dist/core/dashboard-generator-patch.d.ts +2 -0
  78. package/ccw/dist/core/dashboard-generator-patch.d.ts.map +1 -0
  79. package/ccw/dist/core/dashboard-generator-patch.js +48 -0
  80. package/ccw/dist/core/dashboard-generator-patch.js.map +1 -0
  81. package/ccw/dist/core/dashboard-generator.d.ts +8 -0
  82. package/ccw/dist/core/dashboard-generator.d.ts.map +1 -0
  83. package/ccw/dist/core/dashboard-generator.js +695 -0
  84. package/ccw/dist/core/dashboard-generator.js.map +1 -0
  85. package/ccw/dist/core/data-aggregator.d.ts +145 -0
  86. package/ccw/dist/core/data-aggregator.d.ts.map +1 -0
  87. package/ccw/dist/core/data-aggregator.js +416 -0
  88. package/ccw/dist/core/data-aggregator.js.map +1 -0
  89. package/ccw/dist/core/history-importer.d.ts +102 -0
  90. package/ccw/dist/core/history-importer.d.ts.map +1 -0
  91. package/ccw/dist/core/history-importer.js +493 -0
  92. package/ccw/dist/core/history-importer.js.map +1 -0
  93. package/ccw/dist/core/lite-scanner-complete.d.ts +81 -0
  94. package/ccw/dist/core/lite-scanner-complete.d.ts.map +1 -0
  95. package/ccw/dist/core/lite-scanner-complete.js +368 -0
  96. package/ccw/dist/core/lite-scanner-complete.js.map +1 -0
  97. package/ccw/dist/core/lite-scanner.d.ts +81 -0
  98. package/ccw/dist/core/lite-scanner.d.ts.map +1 -0
  99. package/ccw/dist/core/lite-scanner.js +368 -0
  100. package/ccw/dist/core/lite-scanner.js.map +1 -0
  101. package/ccw/dist/core/manifest.d.ts +88 -0
  102. package/ccw/dist/core/manifest.d.ts.map +1 -0
  103. package/ccw/dist/core/manifest.js +214 -0
  104. package/ccw/dist/core/manifest.js.map +1 -0
  105. package/ccw/dist/core/memory-embedder-bridge.d.ts +83 -0
  106. package/ccw/dist/core/memory-embedder-bridge.d.ts.map +1 -0
  107. package/ccw/dist/core/memory-embedder-bridge.js +181 -0
  108. package/ccw/dist/core/memory-embedder-bridge.js.map +1 -0
  109. package/ccw/dist/core/memory-store.d.ts +249 -0
  110. package/ccw/dist/core/memory-store.d.ts.map +1 -0
  111. package/ccw/dist/core/memory-store.js +781 -0
  112. package/ccw/dist/core/memory-store.js.map +1 -0
  113. package/ccw/dist/core/routes/ccw-routes.d.ts +20 -0
  114. package/ccw/dist/core/routes/ccw-routes.d.ts.map +1 -0
  115. package/ccw/dist/core/routes/ccw-routes.js +70 -0
  116. package/ccw/dist/core/routes/ccw-routes.js.map +1 -0
  117. package/ccw/dist/core/routes/claude-routes.d.ts +19 -0
  118. package/ccw/dist/core/routes/claude-routes.d.ts.map +1 -0
  119. package/ccw/dist/core/routes/claude-routes.js +1017 -0
  120. package/ccw/dist/core/routes/claude-routes.js.map +1 -0
  121. package/ccw/dist/core/routes/cli-routes.d.ts +20 -0
  122. package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -0
  123. package/ccw/dist/core/routes/cli-routes.js +468 -0
  124. package/ccw/dist/core/routes/cli-routes.js.map +1 -0
  125. package/ccw/dist/core/routes/codexlens-routes.d.ts +20 -0
  126. package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -0
  127. package/ccw/dist/core/routes/codexlens-routes.js +754 -0
  128. package/ccw/dist/core/routes/codexlens-routes.js.map +1 -0
  129. package/ccw/dist/core/routes/core-memory-routes.d.ts +21 -0
  130. package/ccw/dist/core/routes/core-memory-routes.d.ts.map +1 -0
  131. package/ccw/dist/core/routes/core-memory-routes.js +520 -0
  132. package/ccw/dist/core/routes/core-memory-routes.js.map +1 -0
  133. package/ccw/dist/core/routes/files-routes.d.ts +20 -0
  134. package/ccw/dist/core/routes/files-routes.d.ts.map +1 -0
  135. package/ccw/dist/core/routes/files-routes.js +374 -0
  136. package/ccw/dist/core/routes/files-routes.js.map +1 -0
  137. package/ccw/dist/core/routes/graph-routes.d.ts +20 -0
  138. package/ccw/dist/core/routes/graph-routes.d.ts.map +1 -0
  139. package/ccw/dist/core/routes/graph-routes.js +517 -0
  140. package/ccw/dist/core/routes/graph-routes.js.map +1 -0
  141. package/ccw/dist/core/routes/help-routes.d.ts +20 -0
  142. package/ccw/dist/core/routes/help-routes.d.ts.map +1 -0
  143. package/ccw/dist/core/routes/help-routes.js +250 -0
  144. package/ccw/dist/core/routes/help-routes.js.map +1 -0
  145. package/ccw/dist/core/routes/hooks-routes.d.ts +21 -0
  146. package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -0
  147. package/ccw/dist/core/routes/hooks-routes.js +346 -0
  148. package/ccw/dist/core/routes/hooks-routes.js.map +1 -0
  149. package/ccw/dist/core/routes/mcp-routes.d.ts +20 -0
  150. package/ccw/dist/core/routes/mcp-routes.d.ts.map +1 -0
  151. package/ccw/dist/core/routes/mcp-routes.js +1129 -0
  152. package/ccw/dist/core/routes/mcp-routes.js.map +1 -0
  153. package/ccw/dist/core/routes/mcp-templates-db.d.ts +54 -0
  154. package/ccw/dist/core/routes/mcp-templates-db.d.ts.map +1 -0
  155. package/ccw/dist/core/routes/mcp-templates-db.js +226 -0
  156. package/ccw/dist/core/routes/mcp-templates-db.js.map +1 -0
  157. package/ccw/dist/core/routes/memory-routes.d.ts +21 -0
  158. package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -0
  159. package/ccw/dist/core/routes/memory-routes.js +1095 -0
  160. package/ccw/dist/core/routes/memory-routes.js.map +1 -0
  161. package/ccw/dist/core/routes/rules-routes.d.ts +20 -0
  162. package/ccw/dist/core/routes/rules-routes.d.ts.map +1 -0
  163. package/ccw/dist/core/routes/rules-routes.js +442 -0
  164. package/ccw/dist/core/routes/rules-routes.js.map +1 -0
  165. package/ccw/dist/core/routes/session-routes.d.ts +20 -0
  166. package/ccw/dist/core/routes/session-routes.d.ts.map +1 -0
  167. package/ccw/dist/core/routes/session-routes.js +423 -0
  168. package/ccw/dist/core/routes/session-routes.js.map +1 -0
  169. package/ccw/dist/core/routes/skills-routes.d.ts +20 -0
  170. package/ccw/dist/core/routes/skills-routes.d.ts.map +1 -0
  171. package/ccw/dist/core/routes/skills-routes.js +533 -0
  172. package/ccw/dist/core/routes/skills-routes.js.map +1 -0
  173. package/ccw/dist/core/routes/status-routes.d.ts +20 -0
  174. package/ccw/dist/core/routes/status-routes.d.ts.map +1 -0
  175. package/ccw/dist/core/routes/status-routes.js +38 -0
  176. package/ccw/dist/core/routes/status-routes.js.map +1 -0
  177. package/ccw/dist/core/routes/system-routes.d.ts +22 -0
  178. package/ccw/dist/core/routes/system-routes.d.ts.map +1 -0
  179. package/ccw/dist/core/routes/system-routes.js +354 -0
  180. package/ccw/dist/core/routes/system-routes.js.map +1 -0
  181. package/ccw/dist/core/server.d.ts +17 -0
  182. package/ccw/dist/core/server.d.ts.map +1 -0
  183. package/ccw/dist/core/server.js +386 -0
  184. package/ccw/dist/core/server.js.map +1 -0
  185. package/ccw/dist/core/session-clustering-service.d.ts +153 -0
  186. package/ccw/dist/core/session-clustering-service.d.ts.map +1 -0
  187. package/ccw/dist/core/session-clustering-service.js +1065 -0
  188. package/ccw/dist/core/session-clustering-service.js.map +1 -0
  189. package/ccw/dist/core/session-scanner.d.ts +32 -0
  190. package/ccw/dist/core/session-scanner.d.ts.map +1 -0
  191. package/ccw/dist/core/session-scanner.js +253 -0
  192. package/ccw/dist/core/session-scanner.js.map +1 -0
  193. package/ccw/dist/core/websocket.d.ts +23 -0
  194. package/ccw/dist/core/websocket.d.ts.map +1 -0
  195. package/ccw/dist/core/websocket.js +168 -0
  196. package/ccw/dist/core/websocket.js.map +1 -0
  197. package/ccw/dist/index.d.ts +10 -0
  198. package/ccw/dist/index.d.ts.map +1 -0
  199. package/ccw/dist/index.js +10 -0
  200. package/ccw/dist/index.js.map +1 -0
  201. package/ccw/dist/mcp-server/index.d.ts +7 -0
  202. package/ccw/dist/mcp-server/index.d.ts.map +1 -0
  203. package/ccw/dist/mcp-server/index.js +157 -0
  204. package/ccw/dist/mcp-server/index.js.map +1 -0
  205. package/ccw/dist/tools/classify-folders.d.ts +26 -0
  206. package/ccw/dist/tools/classify-folders.d.ts.map +1 -0
  207. package/ccw/dist/tools/classify-folders.js +201 -0
  208. package/ccw/dist/tools/classify-folders.js.map +1 -0
  209. package/ccw/dist/tools/cli-config-manager.d.ts +62 -0
  210. package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -0
  211. package/ccw/dist/tools/cli-config-manager.js +221 -0
  212. package/ccw/dist/tools/cli-config-manager.js.map +1 -0
  213. package/ccw/dist/tools/cli-executor.d.ts +373 -0
  214. package/ccw/dist/tools/cli-executor.d.ts.map +1 -0
  215. package/ccw/dist/tools/cli-executor.js +1625 -0
  216. package/ccw/dist/tools/cli-executor.js.map +1 -0
  217. package/ccw/dist/tools/cli-history-store.d.ts +330 -0
  218. package/ccw/dist/tools/cli-history-store.d.ts.map +1 -0
  219. package/ccw/dist/tools/cli-history-store.js +916 -0
  220. package/ccw/dist/tools/cli-history-store.js.map +1 -0
  221. package/ccw/dist/tools/codex-lens.d.ts +118 -0
  222. package/ccw/dist/tools/codex-lens.d.ts.map +1 -0
  223. package/ccw/dist/tools/codex-lens.js +962 -0
  224. package/ccw/dist/tools/codex-lens.js.map +1 -0
  225. package/ccw/dist/tools/convert-tokens-to-css.d.ts +14 -0
  226. package/ccw/dist/tools/convert-tokens-to-css.d.ts.map +1 -0
  227. package/ccw/dist/tools/convert-tokens-to-css.js +244 -0
  228. package/ccw/dist/tools/convert-tokens-to-css.js.map +1 -0
  229. package/ccw/dist/tools/core-memory.d.ts +66 -0
  230. package/ccw/dist/tools/core-memory.d.ts.map +1 -0
  231. package/ccw/dist/tools/core-memory.js +324 -0
  232. package/ccw/dist/tools/core-memory.js.map +1 -0
  233. package/ccw/dist/tools/detect-changed-modules.d.ts +24 -0
  234. package/ccw/dist/tools/detect-changed-modules.d.ts.map +1 -0
  235. package/ccw/dist/tools/detect-changed-modules.js +277 -0
  236. package/ccw/dist/tools/detect-changed-modules.js.map +1 -0
  237. package/ccw/dist/tools/discover-design-files.d.ts +36 -0
  238. package/ccw/dist/tools/discover-design-files.d.ts.map +1 -0
  239. package/ccw/dist/tools/discover-design-files.js +147 -0
  240. package/ccw/dist/tools/discover-design-files.js.map +1 -0
  241. package/ccw/dist/tools/edit-file.d.ts +28 -0
  242. package/ccw/dist/tools/edit-file.d.ts.map +1 -0
  243. package/ccw/dist/tools/edit-file.js +479 -0
  244. package/ccw/dist/tools/edit-file.js.map +1 -0
  245. package/ccw/dist/tools/generate-module-docs.d.ts +22 -0
  246. package/ccw/dist/tools/generate-module-docs.d.ts.map +1 -0
  247. package/ccw/dist/tools/generate-module-docs.js +379 -0
  248. package/ccw/dist/tools/generate-module-docs.js.map +1 -0
  249. package/ccw/dist/tools/get-modules-by-depth.d.ts +15 -0
  250. package/ccw/dist/tools/get-modules-by-depth.d.ts.map +1 -0
  251. package/ccw/dist/tools/get-modules-by-depth.js +296 -0
  252. package/ccw/dist/tools/get-modules-by-depth.js.map +1 -0
  253. package/ccw/dist/tools/index.d.ts +55 -0
  254. package/ccw/dist/tools/index.d.ts.map +1 -0
  255. package/ccw/dist/tools/index.js +304 -0
  256. package/ccw/dist/tools/index.js.map +1 -0
  257. package/ccw/dist/tools/native-session-discovery.d.ts +97 -0
  258. package/ccw/dist/tools/native-session-discovery.d.ts.map +1 -0
  259. package/ccw/dist/tools/native-session-discovery.js +700 -0
  260. package/ccw/dist/tools/native-session-discovery.js.map +1 -0
  261. package/ccw/dist/tools/notifier.d.ts +50 -0
  262. package/ccw/dist/tools/notifier.d.ts.map +1 -0
  263. package/ccw/dist/tools/notifier.js +90 -0
  264. package/ccw/dist/tools/notifier.js.map +1 -0
  265. package/ccw/dist/tools/read-file.d.ts +32 -0
  266. package/ccw/dist/tools/read-file.d.ts.map +1 -0
  267. package/ccw/dist/tools/read-file.js +329 -0
  268. package/ccw/dist/tools/read-file.js.map +1 -0
  269. package/ccw/dist/tools/resume-strategy.d.ts +48 -0
  270. package/ccw/dist/tools/resume-strategy.d.ts.map +1 -0
  271. package/ccw/dist/tools/resume-strategy.js +248 -0
  272. package/ccw/dist/tools/resume-strategy.js.map +1 -0
  273. package/ccw/dist/tools/session-content-parser.d.ts +58 -0
  274. package/ccw/dist/tools/session-content-parser.d.ts.map +1 -0
  275. package/ccw/dist/tools/session-content-parser.js +420 -0
  276. package/ccw/dist/tools/session-content-parser.js.map +1 -0
  277. package/ccw/dist/tools/session-manager.d.ts +9 -0
  278. package/ccw/dist/tools/session-manager.d.ts.map +1 -0
  279. package/ccw/dist/tools/session-manager.js +834 -0
  280. package/ccw/dist/tools/session-manager.js.map +1 -0
  281. package/ccw/dist/tools/smart-context.d.ts +35 -0
  282. package/ccw/dist/tools/smart-context.d.ts.map +1 -0
  283. package/ccw/dist/tools/smart-context.js +182 -0
  284. package/ccw/dist/tools/smart-context.js.map +1 -0
  285. package/ccw/dist/tools/smart-search.d.ts +105 -0
  286. package/ccw/dist/tools/smart-search.d.ts.map +1 -0
  287. package/ccw/dist/tools/smart-search.js +1753 -0
  288. package/ccw/dist/tools/smart-search.js.map +1 -0
  289. package/ccw/dist/tools/storage-manager.d.ts +114 -0
  290. package/ccw/dist/tools/storage-manager.d.ts.map +1 -0
  291. package/ccw/dist/tools/storage-manager.js +392 -0
  292. package/ccw/dist/tools/storage-manager.js.map +1 -0
  293. package/ccw/dist/tools/ui-generate-preview.d.ts +39 -0
  294. package/ccw/dist/tools/ui-generate-preview.d.ts.map +1 -0
  295. package/ccw/dist/tools/ui-generate-preview.js +300 -0
  296. package/ccw/dist/tools/ui-generate-preview.js.map +1 -0
  297. package/ccw/dist/tools/ui-instantiate-prototypes.d.ts +75 -0
  298. package/ccw/dist/tools/ui-instantiate-prototypes.d.ts.map +1 -0
  299. package/ccw/dist/tools/ui-instantiate-prototypes.js +256 -0
  300. package/ccw/dist/tools/ui-instantiate-prototypes.js.map +1 -0
  301. package/ccw/dist/tools/update-module-claude.d.ts +80 -0
  302. package/ccw/dist/tools/update-module-claude.d.ts.map +1 -0
  303. package/ccw/dist/tools/update-module-claude.js +351 -0
  304. package/ccw/dist/tools/update-module-claude.js.map +1 -0
  305. package/ccw/dist/tools/write-file.d.ts +19 -0
  306. package/ccw/dist/tools/write-file.d.ts.map +1 -0
  307. package/ccw/dist/tools/write-file.js +193 -0
  308. package/ccw/dist/tools/write-file.js.map +1 -0
  309. package/ccw/dist/types/config.d.ts +11 -0
  310. package/ccw/dist/types/config.d.ts.map +1 -0
  311. package/ccw/dist/types/config.js +2 -0
  312. package/ccw/dist/types/config.js.map +1 -0
  313. package/ccw/dist/types/index.d.ts +4 -0
  314. package/ccw/dist/types/index.d.ts.map +1 -0
  315. package/ccw/dist/types/index.js +4 -0
  316. package/ccw/dist/types/index.js.map +1 -0
  317. package/ccw/dist/types/session.d.ts +20 -0
  318. package/ccw/dist/types/session.d.ts.map +1 -0
  319. package/ccw/dist/types/session.js +2 -0
  320. package/ccw/dist/types/session.js.map +1 -0
  321. package/ccw/dist/types/tool.d.ts +36 -0
  322. package/ccw/dist/types/tool.d.ts.map +1 -0
  323. package/ccw/dist/types/tool.js +11 -0
  324. package/ccw/dist/types/tool.js.map +1 -0
  325. package/ccw/dist/utils/browser-launcher.d.ts +13 -0
  326. package/ccw/dist/utils/browser-launcher.d.ts.map +1 -0
  327. package/ccw/dist/utils/browser-launcher.js +60 -0
  328. package/ccw/dist/utils/browser-launcher.js.map +1 -0
  329. package/ccw/dist/utils/file-utils.d.ts +25 -0
  330. package/ccw/dist/utils/file-utils.d.ts.map +1 -0
  331. package/ccw/dist/utils/file-utils.js +48 -0
  332. package/ccw/dist/utils/file-utils.js.map +1 -0
  333. package/ccw/dist/utils/path-resolver.d.ts +80 -0
  334. package/ccw/dist/utils/path-resolver.d.ts.map +1 -0
  335. package/ccw/dist/utils/path-resolver.js +260 -0
  336. package/ccw/dist/utils/path-resolver.js.map +1 -0
  337. package/ccw/dist/utils/path-validator.d.ts +49 -0
  338. package/ccw/dist/utils/path-validator.d.ts.map +1 -0
  339. package/ccw/dist/utils/path-validator.js +123 -0
  340. package/ccw/dist/utils/path-validator.js.map +1 -0
  341. package/ccw/dist/utils/ui.d.ts +62 -0
  342. package/ccw/dist/utils/ui.d.ts.map +1 -0
  343. package/ccw/dist/utils/ui.js +129 -0
  344. package/ccw/dist/utils/ui.js.map +1 -0
  345. package/ccw/package.json +1 -1
  346. package/package.json +5 -2
@@ -0,0 +1,1129 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { homedir } from 'os';
4
+ import * as McpTemplatesDb from './mcp-templates-db.js';
5
+ // Claude config file path
6
+ const CLAUDE_CONFIG_PATH = join(homedir(), '.claude.json');
7
+ // Codex config file path (TOML format)
8
+ const CODEX_CONFIG_PATH = join(homedir(), '.codex', 'config.toml');
9
+ // Workspace root path for scanning .mcp.json files
10
+ let WORKSPACE_ROOT = process.cwd();
11
+ // ========================================
12
+ // TOML Parser for Codex Config
13
+ // ========================================
14
+ /**
15
+ * Simple TOML parser for Codex config.toml
16
+ * Supports basic types: strings, numbers, booleans, arrays, inline tables
17
+ */
18
+ function parseToml(content) {
19
+ const result = {};
20
+ let currentSection = [];
21
+ const lines = content.split('\n');
22
+ for (let i = 0; i < lines.length; i++) {
23
+ let line = lines[i].trim();
24
+ // Skip empty lines and comments
25
+ if (!line || line.startsWith('#'))
26
+ continue;
27
+ // Handle section headers [section] or [section.subsection]
28
+ const sectionMatch = line.match(/^\[([^\]]+)\]$/);
29
+ if (sectionMatch) {
30
+ currentSection = sectionMatch[1].split('.');
31
+ // Ensure nested sections exist
32
+ let obj = result;
33
+ for (const part of currentSection) {
34
+ if (!obj[part])
35
+ obj[part] = {};
36
+ obj = obj[part];
37
+ }
38
+ continue;
39
+ }
40
+ // Handle key = value pairs
41
+ const keyValueMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/);
42
+ if (keyValueMatch) {
43
+ const key = keyValueMatch[1];
44
+ const rawValue = keyValueMatch[2].trim();
45
+ const value = parseTomlValue(rawValue);
46
+ // Navigate to current section
47
+ let obj = result;
48
+ for (const part of currentSection) {
49
+ if (!obj[part])
50
+ obj[part] = {};
51
+ obj = obj[part];
52
+ }
53
+ obj[key] = value;
54
+ }
55
+ }
56
+ return result;
57
+ }
58
+ /**
59
+ * Parse a TOML value
60
+ */
61
+ function parseTomlValue(value) {
62
+ // String (double-quoted)
63
+ if (value.startsWith('"') && value.endsWith('"')) {
64
+ return value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
65
+ }
66
+ // String (single-quoted - literal)
67
+ if (value.startsWith("'") && value.endsWith("'")) {
68
+ return value.slice(1, -1);
69
+ }
70
+ // Boolean
71
+ if (value === 'true')
72
+ return true;
73
+ if (value === 'false')
74
+ return false;
75
+ // Number
76
+ if (/^-?\d+(\.\d+)?$/.test(value)) {
77
+ return value.includes('.') ? parseFloat(value) : parseInt(value, 10);
78
+ }
79
+ // Array
80
+ if (value.startsWith('[') && value.endsWith(']')) {
81
+ const inner = value.slice(1, -1).trim();
82
+ if (!inner)
83
+ return [];
84
+ // Simple array parsing (handles basic cases)
85
+ const items = [];
86
+ let depth = 0;
87
+ let current = '';
88
+ let inString = false;
89
+ let stringChar = '';
90
+ for (const char of inner) {
91
+ if (!inString && (char === '"' || char === "'")) {
92
+ inString = true;
93
+ stringChar = char;
94
+ current += char;
95
+ }
96
+ else if (inString && char === stringChar) {
97
+ inString = false;
98
+ current += char;
99
+ }
100
+ else if (!inString && (char === '[' || char === '{')) {
101
+ depth++;
102
+ current += char;
103
+ }
104
+ else if (!inString && (char === ']' || char === '}')) {
105
+ depth--;
106
+ current += char;
107
+ }
108
+ else if (!inString && char === ',' && depth === 0) {
109
+ items.push(parseTomlValue(current.trim()));
110
+ current = '';
111
+ }
112
+ else {
113
+ current += char;
114
+ }
115
+ }
116
+ if (current.trim()) {
117
+ items.push(parseTomlValue(current.trim()));
118
+ }
119
+ return items;
120
+ }
121
+ // Inline table { key = value, ... }
122
+ if (value.startsWith('{') && value.endsWith('}')) {
123
+ const inner = value.slice(1, -1).trim();
124
+ if (!inner)
125
+ return {};
126
+ const table = {};
127
+ // Simple inline table parsing
128
+ const pairs = inner.split(',');
129
+ for (const pair of pairs) {
130
+ const match = pair.trim().match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.+)$/);
131
+ if (match) {
132
+ table[match[1]] = parseTomlValue(match[2].trim());
133
+ }
134
+ }
135
+ return table;
136
+ }
137
+ // Return as string if nothing else matches
138
+ return value;
139
+ }
140
+ /**
141
+ * Serialize object to TOML format for Codex config
142
+ *
143
+ * Handles mixed objects containing both simple values and sub-objects.
144
+ * For example: { command: "cmd", args: [...], env: { KEY: "value" } }
145
+ * becomes:
146
+ * [section]
147
+ * command = "cmd"
148
+ * args = [...]
149
+ * [section.env]
150
+ * KEY = "value"
151
+ */
152
+ function serializeToml(obj, prefix = '') {
153
+ let result = '';
154
+ for (const [key, value] of Object.entries(obj)) {
155
+ if (value === null || value === undefined)
156
+ continue;
157
+ if (typeof value === 'object' && !Array.isArray(value)) {
158
+ // Handle nested sections (like mcp_servers.server_name)
159
+ const sectionKey = prefix ? `${prefix}.${key}` : key;
160
+ // Separate simple values from sub-objects
161
+ const simpleEntries = [];
162
+ const objectEntries = [];
163
+ for (const [subKey, subValue] of Object.entries(value)) {
164
+ if (subValue === null || subValue === undefined)
165
+ continue;
166
+ if (typeof subValue === 'object' && !Array.isArray(subValue)) {
167
+ objectEntries.push([subKey, subValue]);
168
+ }
169
+ else {
170
+ simpleEntries.push([subKey, subValue]);
171
+ }
172
+ }
173
+ // Write section header if there are simple values
174
+ if (simpleEntries.length > 0) {
175
+ result += `\n[${sectionKey}]\n`;
176
+ for (const [subKey, subValue] of simpleEntries) {
177
+ result += `${subKey} = ${serializeTomlValue(subValue)}\n`;
178
+ }
179
+ }
180
+ // Recursively handle sub-objects
181
+ if (objectEntries.length > 0) {
182
+ for (const [subKey, subValue] of objectEntries) {
183
+ const subSectionKey = `${sectionKey}.${subKey}`;
184
+ // Check if sub-object has nested objects
185
+ const hasNestedObjects = Object.values(subValue).some(v => typeof v === 'object' && v !== null && !Array.isArray(v));
186
+ if (hasNestedObjects) {
187
+ // Recursively process nested objects
188
+ result += serializeToml({ [subKey]: subValue }, sectionKey);
189
+ }
190
+ else {
191
+ // Write sub-section with simple values
192
+ result += `\n[${subSectionKey}]\n`;
193
+ for (const [nestedKey, nestedValue] of Object.entries(subValue)) {
194
+ if (nestedValue !== null && nestedValue !== undefined) {
195
+ result += `${nestedKey} = ${serializeTomlValue(nestedValue)}\n`;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ // If no simple values but has object entries, still need to process
202
+ if (simpleEntries.length === 0 && objectEntries.length === 0) {
203
+ // Empty section - write header only
204
+ result += `\n[${sectionKey}]\n`;
205
+ }
206
+ }
207
+ else if (!prefix) {
208
+ // Top-level simple values
209
+ result += `${key} = ${serializeTomlValue(value)}\n`;
210
+ }
211
+ }
212
+ return result;
213
+ }
214
+ /**
215
+ * Serialize a value to TOML format
216
+ */
217
+ function serializeTomlValue(value) {
218
+ if (typeof value === 'string') {
219
+ return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
220
+ }
221
+ if (typeof value === 'boolean') {
222
+ return value ? 'true' : 'false';
223
+ }
224
+ if (typeof value === 'number') {
225
+ return String(value);
226
+ }
227
+ if (Array.isArray(value)) {
228
+ return `[${value.map(v => serializeTomlValue(v)).join(', ')}]`;
229
+ }
230
+ if (typeof value === 'object' && value !== null) {
231
+ const pairs = Object.entries(value)
232
+ .filter(([_, v]) => v !== null && v !== undefined)
233
+ .map(([k, v]) => `${k} = ${serializeTomlValue(v)}`);
234
+ return `{ ${pairs.join(', ')} }`;
235
+ }
236
+ return String(value);
237
+ }
238
+ // ========================================
239
+ // Codex MCP Functions
240
+ // ========================================
241
+ /**
242
+ * Read Codex config.toml and extract MCP servers
243
+ */
244
+ function getCodexMcpConfig() {
245
+ try {
246
+ if (!existsSync(CODEX_CONFIG_PATH)) {
247
+ return { servers: {}, configPath: CODEX_CONFIG_PATH, exists: false };
248
+ }
249
+ const content = readFileSync(CODEX_CONFIG_PATH, 'utf8');
250
+ const config = parseToml(content);
251
+ // MCP servers are under [mcp_servers] section
252
+ const mcpServers = config.mcp_servers || {};
253
+ return {
254
+ servers: mcpServers,
255
+ configPath: CODEX_CONFIG_PATH,
256
+ exists: true
257
+ };
258
+ }
259
+ catch (error) {
260
+ console.error('Error reading Codex config:', error);
261
+ return { servers: {}, configPath: CODEX_CONFIG_PATH, exists: false };
262
+ }
263
+ }
264
+ /**
265
+ * Add or update MCP server in Codex config.toml
266
+ */
267
+ function addCodexMcpServer(serverName, serverConfig) {
268
+ try {
269
+ const codexDir = join(homedir(), '.codex');
270
+ // Ensure .codex directory exists
271
+ if (!existsSync(codexDir)) {
272
+ mkdirSync(codexDir, { recursive: true });
273
+ }
274
+ let config = {};
275
+ // Read existing config if it exists
276
+ if (existsSync(CODEX_CONFIG_PATH)) {
277
+ const content = readFileSync(CODEX_CONFIG_PATH, 'utf8');
278
+ config = parseToml(content);
279
+ }
280
+ // Ensure mcp_servers section exists
281
+ if (!config.mcp_servers) {
282
+ config.mcp_servers = {};
283
+ }
284
+ // Convert serverConfig from Claude format to Codex format
285
+ const codexServerConfig = {};
286
+ // Handle STDIO servers (command-based)
287
+ if (serverConfig.command) {
288
+ codexServerConfig.command = serverConfig.command;
289
+ if (serverConfig.args && serverConfig.args.length > 0) {
290
+ codexServerConfig.args = serverConfig.args;
291
+ }
292
+ if (serverConfig.env && Object.keys(serverConfig.env).length > 0) {
293
+ codexServerConfig.env = serverConfig.env;
294
+ }
295
+ if (serverConfig.cwd) {
296
+ codexServerConfig.cwd = serverConfig.cwd;
297
+ }
298
+ }
299
+ // Handle HTTP servers (url-based)
300
+ if (serverConfig.url) {
301
+ codexServerConfig.url = serverConfig.url;
302
+ if (serverConfig.bearer_token_env_var) {
303
+ codexServerConfig.bearer_token_env_var = serverConfig.bearer_token_env_var;
304
+ }
305
+ if (serverConfig.http_headers) {
306
+ codexServerConfig.http_headers = serverConfig.http_headers;
307
+ }
308
+ }
309
+ // Copy optional fields
310
+ if (serverConfig.startup_timeout_sec !== undefined) {
311
+ codexServerConfig.startup_timeout_sec = serverConfig.startup_timeout_sec;
312
+ }
313
+ if (serverConfig.tool_timeout_sec !== undefined) {
314
+ codexServerConfig.tool_timeout_sec = serverConfig.tool_timeout_sec;
315
+ }
316
+ if (serverConfig.enabled !== undefined) {
317
+ codexServerConfig.enabled = serverConfig.enabled;
318
+ }
319
+ if (serverConfig.enabled_tools) {
320
+ codexServerConfig.enabled_tools = serverConfig.enabled_tools;
321
+ }
322
+ if (serverConfig.disabled_tools) {
323
+ codexServerConfig.disabled_tools = serverConfig.disabled_tools;
324
+ }
325
+ // Add the server
326
+ config.mcp_servers[serverName] = codexServerConfig;
327
+ // Serialize and write back
328
+ const tomlContent = serializeToml(config);
329
+ writeFileSync(CODEX_CONFIG_PATH, tomlContent, 'utf8');
330
+ return { success: true };
331
+ }
332
+ catch (error) {
333
+ console.error('Error adding Codex MCP server:', error);
334
+ return { error: error.message };
335
+ }
336
+ }
337
+ /**
338
+ * Remove MCP server from Codex config.toml
339
+ */
340
+ function removeCodexMcpServer(serverName) {
341
+ try {
342
+ if (!existsSync(CODEX_CONFIG_PATH)) {
343
+ return { error: 'Codex config.toml not found' };
344
+ }
345
+ const content = readFileSync(CODEX_CONFIG_PATH, 'utf8');
346
+ const config = parseToml(content);
347
+ if (!config.mcp_servers || !config.mcp_servers[serverName]) {
348
+ return { error: `Server not found: ${serverName}` };
349
+ }
350
+ // Remove the server
351
+ delete config.mcp_servers[serverName];
352
+ // Serialize and write back
353
+ const tomlContent = serializeToml(config);
354
+ writeFileSync(CODEX_CONFIG_PATH, tomlContent, 'utf8');
355
+ return { success: true };
356
+ }
357
+ catch (error) {
358
+ console.error('Error removing Codex MCP server:', error);
359
+ return { error: error.message };
360
+ }
361
+ }
362
+ /**
363
+ * Toggle Codex MCP server enabled state
364
+ */
365
+ function toggleCodexMcpServer(serverName, enabled) {
366
+ try {
367
+ if (!existsSync(CODEX_CONFIG_PATH)) {
368
+ return { error: 'Codex config.toml not found' };
369
+ }
370
+ const content = readFileSync(CODEX_CONFIG_PATH, 'utf8');
371
+ const config = parseToml(content);
372
+ if (!config.mcp_servers || !config.mcp_servers[serverName]) {
373
+ return { error: `Server not found: ${serverName}` };
374
+ }
375
+ // Set enabled state
376
+ config.mcp_servers[serverName].enabled = enabled;
377
+ // Serialize and write back
378
+ const tomlContent = serializeToml(config);
379
+ writeFileSync(CODEX_CONFIG_PATH, tomlContent, 'utf8');
380
+ return { success: true };
381
+ }
382
+ catch (error) {
383
+ console.error('Error toggling Codex MCP server:', error);
384
+ return { error: error.message };
385
+ }
386
+ }
387
+ // ========================================
388
+ // Helper Functions
389
+ // ========================================
390
+ /**
391
+ * Get enterprise managed MCP path (platform-specific)
392
+ */
393
+ function getEnterpriseMcpPath() {
394
+ const platform = process.platform;
395
+ if (platform === 'darwin') {
396
+ return '/Library/Application Support/ClaudeCode/managed-mcp.json';
397
+ }
398
+ else if (platform === 'win32') {
399
+ return 'C:\\Program Files\\ClaudeCode\\managed-mcp.json';
400
+ }
401
+ else {
402
+ // Linux and WSL
403
+ return '/etc/claude-code/managed-mcp.json';
404
+ }
405
+ }
406
+ /**
407
+ * Safely read and parse JSON file
408
+ */
409
+ function safeReadJson(filePath) {
410
+ try {
411
+ if (!existsSync(filePath))
412
+ return null;
413
+ const content = readFileSync(filePath, 'utf8');
414
+ return JSON.parse(content);
415
+ }
416
+ catch {
417
+ return null;
418
+ }
419
+ }
420
+ /**
421
+ * Get MCP servers from a JSON file (expects mcpServers key at top level)
422
+ * @param {string} filePath
423
+ * @returns {Object} mcpServers object or empty object
424
+ */
425
+ function getMcpServersFromFile(filePath) {
426
+ const config = safeReadJson(filePath);
427
+ if (!config)
428
+ return {};
429
+ return config.mcpServers || {};
430
+ }
431
+ /**
432
+ * Add or update MCP server in project's .mcp.json file
433
+ * @param {string} projectPath - Project directory path
434
+ * @param {string} serverName - MCP server name
435
+ * @param {Object} serverConfig - MCP server configuration
436
+ * @returns {Object} Result with success/error
437
+ */
438
+ function addMcpServerToMcpJson(projectPath, serverName, serverConfig) {
439
+ try {
440
+ const normalizedPath = normalizePathForFileSystem(projectPath);
441
+ const mcpJsonPath = join(normalizedPath, '.mcp.json');
442
+ // Read existing .mcp.json or create new structure
443
+ let mcpJson = safeReadJson(mcpJsonPath) || { mcpServers: {} };
444
+ // Ensure mcpServers exists
445
+ if (!mcpJson.mcpServers) {
446
+ mcpJson.mcpServers = {};
447
+ }
448
+ // Add or update the server
449
+ mcpJson.mcpServers[serverName] = serverConfig;
450
+ // Write back to .mcp.json
451
+ writeFileSync(mcpJsonPath, JSON.stringify(mcpJson, null, 2), 'utf8');
452
+ return {
453
+ success: true,
454
+ serverName,
455
+ serverConfig,
456
+ scope: 'project-mcp-json',
457
+ path: mcpJsonPath
458
+ };
459
+ }
460
+ catch (error) {
461
+ console.error('Error adding MCP server to .mcp.json:', error);
462
+ return { error: error.message };
463
+ }
464
+ }
465
+ /**
466
+ * Remove MCP server from project's .mcp.json file
467
+ * @param {string} projectPath - Project directory path
468
+ * @param {string} serverName - MCP server name
469
+ * @returns {Object} Result with success/error
470
+ */
471
+ function removeMcpServerFromMcpJson(projectPath, serverName) {
472
+ try {
473
+ const normalizedPath = normalizePathForFileSystem(projectPath);
474
+ const mcpJsonPath = join(normalizedPath, '.mcp.json');
475
+ if (!existsSync(mcpJsonPath)) {
476
+ return { error: '.mcp.json not found' };
477
+ }
478
+ const mcpJson = safeReadJson(mcpJsonPath);
479
+ if (!mcpJson || !mcpJson.mcpServers || !mcpJson.mcpServers[serverName]) {
480
+ return { error: `Server not found: ${serverName}` };
481
+ }
482
+ // Remove the server
483
+ delete mcpJson.mcpServers[serverName];
484
+ // Write back to .mcp.json
485
+ writeFileSync(mcpJsonPath, JSON.stringify(mcpJson, null, 2), 'utf8');
486
+ return {
487
+ success: true,
488
+ serverName,
489
+ removed: true,
490
+ scope: 'project-mcp-json'
491
+ };
492
+ }
493
+ catch (error) {
494
+ console.error('Error removing MCP server from .mcp.json:', error);
495
+ return { error: error.message };
496
+ }
497
+ }
498
+ /**
499
+ * Get MCP configuration from multiple sources (per official Claude Code docs):
500
+ *
501
+ * Priority (highest to lowest):
502
+ * 1. Enterprise managed-mcp.json (cannot be overridden)
503
+ * 2. Local scope (project-specific private in ~/.claude.json)
504
+ * 3. Project scope (.mcp.json in project root)
505
+ * 4. User scope (mcpServers in ~/.claude.json)
506
+ *
507
+ * Note: ~/.claude/settings.json is for MCP PERMISSIONS, NOT definitions!
508
+ *
509
+ * @returns {Object}
510
+ */
511
+ function getMcpConfig() {
512
+ try {
513
+ const result = {
514
+ projects: {},
515
+ userServers: {}, // User-level servers from ~/.claude.json mcpServers
516
+ enterpriseServers: {}, // Enterprise managed servers (highest priority)
517
+ configSources: [] // Track where configs came from for debugging
518
+ };
519
+ // 1. Read Enterprise managed MCP servers (highest priority)
520
+ const enterprisePath = getEnterpriseMcpPath();
521
+ if (existsSync(enterprisePath)) {
522
+ const enterpriseConfig = safeReadJson(enterprisePath);
523
+ if (enterpriseConfig?.mcpServers) {
524
+ result.enterpriseServers = enterpriseConfig.mcpServers;
525
+ result.configSources.push({ type: 'enterprise', path: enterprisePath, count: Object.keys(enterpriseConfig.mcpServers).length });
526
+ }
527
+ }
528
+ // 2. Read from ~/.claude.json
529
+ if (existsSync(CLAUDE_CONFIG_PATH)) {
530
+ const claudeConfig = safeReadJson(CLAUDE_CONFIG_PATH);
531
+ if (claudeConfig) {
532
+ // 2a. User-level mcpServers (top-level mcpServers key)
533
+ if (claudeConfig.mcpServers) {
534
+ result.userServers = claudeConfig.mcpServers;
535
+ result.configSources.push({ type: 'user', path: CLAUDE_CONFIG_PATH, count: Object.keys(claudeConfig.mcpServers).length });
536
+ }
537
+ // 2b. Project-specific configurations (projects[path].mcpServers)
538
+ if (claudeConfig.projects) {
539
+ result.projects = claudeConfig.projects;
540
+ }
541
+ }
542
+ }
543
+ // 3. For each known project, check for .mcp.json (project-level config)
544
+ // .mcp.json is now the PRIMARY source for project-level MCP servers
545
+ const projectPaths = Object.keys(result.projects);
546
+ for (const projectPath of projectPaths) {
547
+ const mcpJsonPath = join(projectPath, '.mcp.json');
548
+ if (existsSync(mcpJsonPath)) {
549
+ const mcpJsonConfig = safeReadJson(mcpJsonPath);
550
+ if (mcpJsonConfig?.mcpServers) {
551
+ // Merge .mcp.json servers into project config
552
+ // .mcp.json has HIGHER priority than ~/.claude.json projects[path].mcpServers
553
+ const existingServers = result.projects[projectPath]?.mcpServers || {};
554
+ result.projects[projectPath] = {
555
+ ...result.projects[projectPath],
556
+ mcpServers: {
557
+ ...existingServers, // ~/.claude.json projects[path] (lower priority, legacy)
558
+ ...mcpJsonConfig.mcpServers // .mcp.json (higher priority, new default)
559
+ },
560
+ mcpJsonPath: mcpJsonPath, // Track source for debugging
561
+ hasMcpJson: true
562
+ };
563
+ result.configSources.push({
564
+ type: 'project-mcp-json',
565
+ path: mcpJsonPath,
566
+ count: Object.keys(mcpJsonConfig.mcpServers).length
567
+ });
568
+ }
569
+ }
570
+ }
571
+ // Build globalServers by merging user and enterprise servers
572
+ // Enterprise servers override user servers
573
+ result.globalServers = {
574
+ ...result.userServers,
575
+ ...result.enterpriseServers
576
+ };
577
+ return result;
578
+ }
579
+ catch (error) {
580
+ console.error('Error reading MCP config:', error);
581
+ return { projects: {}, globalServers: {}, userServers: {}, enterpriseServers: {}, configSources: [], error: error.message };
582
+ }
583
+ }
584
+ /**
585
+ * Normalize path to filesystem format (for accessing .mcp.json files)
586
+ * Always uses forward slashes for cross-platform compatibility
587
+ * @param {string} path
588
+ * @returns {string}
589
+ */
590
+ function normalizePathForFileSystem(path) {
591
+ let normalized = path.replace(/\\/g, '/');
592
+ // Handle /d/path format -> D:/path
593
+ if (normalized.match(/^\/[a-zA-Z]\//)) {
594
+ normalized = normalized.charAt(1).toUpperCase() + ':' + normalized.slice(2);
595
+ }
596
+ return normalized;
597
+ }
598
+ /**
599
+ * Normalize project path to match existing format in .claude.json
600
+ * Checks both forward slash and backslash formats to find existing entry
601
+ * @param {string} path
602
+ * @param {Object} claudeConfig - Optional existing config to check format
603
+ * @returns {string}
604
+ */
605
+ function normalizeProjectPathForConfig(path, claudeConfig = null) {
606
+ // IMPORTANT: Always normalize to forward slashes to prevent duplicate entries
607
+ // (e.g., prevents both "D:/Claude_dms3" and "D:\\Claude_dms3")
608
+ let normalizedForward = path.replace(/\\/g, '/');
609
+ // Handle /d/path format -> D:/path
610
+ if (normalizedForward.match(/^\/[a-zA-Z]\//)) {
611
+ normalizedForward = normalizedForward.charAt(1).toUpperCase() + ':' + normalizedForward.slice(2);
612
+ }
613
+ // ALWAYS return forward slash format to prevent duplicates
614
+ return normalizedForward;
615
+ }
616
+ /**
617
+ * Toggle MCP server enabled/disabled
618
+ * @param {string} projectPath
619
+ * @param {string} serverName
620
+ * @param {boolean} enable
621
+ * @returns {Object}
622
+ */
623
+ function toggleMcpServerEnabled(projectPath, serverName, enable) {
624
+ try {
625
+ if (!existsSync(CLAUDE_CONFIG_PATH)) {
626
+ return { error: '.claude.json not found' };
627
+ }
628
+ const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
629
+ const config = JSON.parse(content);
630
+ const normalizedPath = normalizeProjectPathForConfig(projectPath, config);
631
+ if (!config.projects || !config.projects[normalizedPath]) {
632
+ return { error: `Project not found: ${normalizedPath}` };
633
+ }
634
+ const projectConfig = config.projects[normalizedPath];
635
+ // Ensure disabledMcpServers array exists
636
+ if (!projectConfig.disabledMcpServers) {
637
+ projectConfig.disabledMcpServers = [];
638
+ }
639
+ if (enable) {
640
+ // Remove from disabled list
641
+ projectConfig.disabledMcpServers = projectConfig.disabledMcpServers.filter(s => s !== serverName);
642
+ }
643
+ else {
644
+ // Add to disabled list if not already there
645
+ if (!projectConfig.disabledMcpServers.includes(serverName)) {
646
+ projectConfig.disabledMcpServers.push(serverName);
647
+ }
648
+ }
649
+ // Write back to file
650
+ writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
651
+ return {
652
+ success: true,
653
+ serverName,
654
+ enabled: enable,
655
+ disabledMcpServers: projectConfig.disabledMcpServers
656
+ };
657
+ }
658
+ catch (error) {
659
+ console.error('Error toggling MCP server:', error);
660
+ return { error: error.message };
661
+ }
662
+ }
663
+ /**
664
+ * Add MCP server to project
665
+ * Now defaults to using .mcp.json instead of .claude.json
666
+ * @param {string} projectPath
667
+ * @param {string} serverName
668
+ * @param {Object} serverConfig
669
+ * @param {boolean} useLegacyConfig - If true, use .claude.json instead of .mcp.json
670
+ * @returns {Object}
671
+ */
672
+ function addMcpServerToProject(projectPath, serverName, serverConfig, useLegacyConfig = false) {
673
+ try {
674
+ // Default: Use .mcp.json for project-level MCP servers
675
+ if (!useLegacyConfig) {
676
+ return addMcpServerToMcpJson(projectPath, serverName, serverConfig);
677
+ }
678
+ // Legacy: Use .claude.json (kept for backward compatibility)
679
+ if (!existsSync(CLAUDE_CONFIG_PATH)) {
680
+ return { error: '.claude.json not found' };
681
+ }
682
+ const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
683
+ const config = JSON.parse(content);
684
+ const normalizedPath = normalizeProjectPathForConfig(projectPath, config);
685
+ // Create project entry if it doesn't exist
686
+ if (!config.projects) {
687
+ config.projects = {};
688
+ }
689
+ if (!config.projects[normalizedPath]) {
690
+ config.projects[normalizedPath] = {
691
+ allowedTools: [],
692
+ mcpContextUris: [],
693
+ mcpServers: {},
694
+ enabledMcpjsonServers: [],
695
+ disabledMcpjsonServers: [],
696
+ hasTrustDialogAccepted: false,
697
+ projectOnboardingSeenCount: 0,
698
+ hasClaudeMdExternalIncludesApproved: false,
699
+ hasClaudeMdExternalIncludesWarningShown: false
700
+ };
701
+ }
702
+ const projectConfig = config.projects[normalizedPath];
703
+ // Ensure mcpServers exists
704
+ if (!projectConfig.mcpServers) {
705
+ projectConfig.mcpServers = {};
706
+ }
707
+ // Add the server
708
+ projectConfig.mcpServers[serverName] = serverConfig;
709
+ // Write back to file
710
+ writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
711
+ return {
712
+ success: true,
713
+ serverName,
714
+ serverConfig,
715
+ scope: 'project-legacy'
716
+ };
717
+ }
718
+ catch (error) {
719
+ console.error('Error adding MCP server:', error);
720
+ return { error: error.message };
721
+ }
722
+ }
723
+ /**
724
+ * Remove MCP server from project
725
+ * Checks both .mcp.json and .claude.json
726
+ * @param {string} projectPath
727
+ * @param {string} serverName
728
+ * @returns {Object}
729
+ */
730
+ function removeMcpServerFromProject(projectPath, serverName) {
731
+ try {
732
+ const normalizedPathForFile = normalizePathForFileSystem(projectPath);
733
+ const mcpJsonPath = join(normalizedPathForFile, '.mcp.json');
734
+ let removedFromMcpJson = false;
735
+ let removedFromClaudeJson = false;
736
+ // Try to remove from .mcp.json first (new default)
737
+ if (existsSync(mcpJsonPath)) {
738
+ const mcpJson = safeReadJson(mcpJsonPath);
739
+ if (mcpJson?.mcpServers?.[serverName]) {
740
+ const result = removeMcpServerFromMcpJson(projectPath, serverName);
741
+ if (result.success) {
742
+ removedFromMcpJson = true;
743
+ }
744
+ }
745
+ }
746
+ // Also try to remove from .claude.json (legacy - may coexist)
747
+ if (existsSync(CLAUDE_CONFIG_PATH)) {
748
+ const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
749
+ const config = JSON.parse(content);
750
+ // Get normalized path that matches existing config format
751
+ const normalizedPath = normalizeProjectPathForConfig(projectPath, config);
752
+ if (config.projects && config.projects[normalizedPath]) {
753
+ const projectConfig = config.projects[normalizedPath];
754
+ if (projectConfig.mcpServers && projectConfig.mcpServers[serverName]) {
755
+ // Remove the server
756
+ delete projectConfig.mcpServers[serverName];
757
+ // Also remove from disabled list if present
758
+ if (projectConfig.disabledMcpServers) {
759
+ projectConfig.disabledMcpServers = projectConfig.disabledMcpServers.filter(s => s !== serverName);
760
+ }
761
+ // Write back to file
762
+ writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
763
+ removedFromClaudeJson = true;
764
+ }
765
+ }
766
+ }
767
+ // Return success if removed from either location
768
+ if (removedFromMcpJson || removedFromClaudeJson) {
769
+ return {
770
+ success: true,
771
+ serverName,
772
+ removed: true,
773
+ scope: removedFromMcpJson ? 'project-mcp-json' : 'project-legacy',
774
+ removedFrom: removedFromMcpJson && removedFromClaudeJson ? 'both' :
775
+ removedFromMcpJson ? '.mcp.json' : '.claude.json'
776
+ };
777
+ }
778
+ return { error: `Server not found: ${serverName}` };
779
+ }
780
+ catch (error) {
781
+ console.error('Error removing MCP server:', error);
782
+ return { error: error.message };
783
+ }
784
+ }
785
+ /**
786
+ * Add MCP server to global/user scope (top-level mcpServers in ~/.claude.json)
787
+ * @param {string} serverName
788
+ * @param {Object} serverConfig
789
+ * @returns {Object}
790
+ */
791
+ function addGlobalMcpServer(serverName, serverConfig) {
792
+ try {
793
+ if (!existsSync(CLAUDE_CONFIG_PATH)) {
794
+ return { error: '.claude.json not found' };
795
+ }
796
+ const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
797
+ const config = JSON.parse(content);
798
+ // Ensure top-level mcpServers exists
799
+ if (!config.mcpServers) {
800
+ config.mcpServers = {};
801
+ }
802
+ // Add the server to top-level mcpServers
803
+ config.mcpServers[serverName] = serverConfig;
804
+ // Write back to file
805
+ writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
806
+ return {
807
+ success: true,
808
+ serverName,
809
+ serverConfig,
810
+ scope: 'global'
811
+ };
812
+ }
813
+ catch (error) {
814
+ console.error('Error adding global MCP server:', error);
815
+ return { error: error.message };
816
+ }
817
+ }
818
+ /**
819
+ * Remove MCP server from global/user scope (top-level mcpServers)
820
+ * @param {string} serverName
821
+ * @returns {Object}
822
+ */
823
+ function removeGlobalMcpServer(serverName) {
824
+ try {
825
+ if (!existsSync(CLAUDE_CONFIG_PATH)) {
826
+ return { error: '.claude.json not found' };
827
+ }
828
+ const content = readFileSync(CLAUDE_CONFIG_PATH, 'utf8');
829
+ const config = JSON.parse(content);
830
+ if (!config.mcpServers || !config.mcpServers[serverName]) {
831
+ return { error: `Global server not found: ${serverName}` };
832
+ }
833
+ // Remove the server from top-level mcpServers
834
+ delete config.mcpServers[serverName];
835
+ // Write back to file
836
+ writeFileSync(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
837
+ return {
838
+ success: true,
839
+ serverName,
840
+ removed: true,
841
+ scope: 'global'
842
+ };
843
+ }
844
+ catch (error) {
845
+ console.error('Error removing global MCP server:', error);
846
+ return { error: error.message };
847
+ }
848
+ }
849
+ /**
850
+ * Read settings file safely
851
+ * @param {string} filePath
852
+ * @returns {Object}
853
+ */
854
+ function readSettingsFile(filePath) {
855
+ try {
856
+ if (!existsSync(filePath)) {
857
+ return {};
858
+ }
859
+ const content = readFileSync(filePath, 'utf8');
860
+ return JSON.parse(content);
861
+ }
862
+ catch (error) {
863
+ console.error(`Error reading settings file ${filePath}:`, error);
864
+ return {};
865
+ }
866
+ }
867
+ /**
868
+ * Write settings file safely
869
+ * @param {string} filePath
870
+ * @param {Object} settings
871
+ */
872
+ function writeSettingsFile(filePath, settings) {
873
+ const dirPath = dirname(filePath);
874
+ // Ensure directory exists
875
+ if (!existsSync(dirPath)) {
876
+ mkdirSync(dirPath, { recursive: true });
877
+ }
878
+ writeFileSync(filePath, JSON.stringify(settings, null, 2), 'utf8');
879
+ }
880
+ /**
881
+ * Get project settings path
882
+ * @param {string} projectPath
883
+ * @returns {string}
884
+ */
885
+ function getProjectSettingsPath(projectPath) {
886
+ const normalizedPath = projectPath.replace(/\//g, '\\').replace(/^\\([a-zA-Z])\\/, '$1:\\');
887
+ return join(normalizedPath, '.claude', 'settings.json');
888
+ }
889
+ // ========================================
890
+ // Route Handlers
891
+ // ========================================
892
+ /**
893
+ * Handle MCP routes
894
+ * @returns true if route was handled, false otherwise
895
+ */
896
+ export async function handleMcpRoutes(ctx) {
897
+ const { pathname, url, req, res, initialPath, handlePostRequest, broadcastToClients } = ctx;
898
+ // API: Get MCP configuration (includes both Claude and Codex)
899
+ if (pathname === '/api/mcp-config') {
900
+ const mcpData = getMcpConfig();
901
+ const codexData = getCodexMcpConfig();
902
+ const combinedData = {
903
+ ...mcpData,
904
+ codex: codexData
905
+ };
906
+ res.writeHead(200, { 'Content-Type': 'application/json' });
907
+ res.end(JSON.stringify(combinedData));
908
+ return true;
909
+ }
910
+ // ========================================
911
+ // Codex MCP API Endpoints
912
+ // ========================================
913
+ // API: Get Codex MCP configuration
914
+ if (pathname === '/api/codex-mcp-config') {
915
+ const codexData = getCodexMcpConfig();
916
+ res.writeHead(200, { 'Content-Type': 'application/json' });
917
+ res.end(JSON.stringify(codexData));
918
+ return true;
919
+ }
920
+ // API: Add Codex MCP server
921
+ if (pathname === '/api/codex-mcp-add' && req.method === 'POST') {
922
+ handlePostRequest(req, res, async (body) => {
923
+ const { serverName, serverConfig } = body;
924
+ if (!serverName || !serverConfig) {
925
+ return { error: 'serverName and serverConfig are required', status: 400 };
926
+ }
927
+ return addCodexMcpServer(serverName, serverConfig);
928
+ });
929
+ return true;
930
+ }
931
+ // API: Remove Codex MCP server
932
+ if (pathname === '/api/codex-mcp-remove' && req.method === 'POST') {
933
+ handlePostRequest(req, res, async (body) => {
934
+ const { serverName } = body;
935
+ if (!serverName) {
936
+ return { error: 'serverName is required', status: 400 };
937
+ }
938
+ return removeCodexMcpServer(serverName);
939
+ });
940
+ return true;
941
+ }
942
+ // API: Toggle Codex MCP server enabled state
943
+ if (pathname === '/api/codex-mcp-toggle' && req.method === 'POST') {
944
+ handlePostRequest(req, res, async (body) => {
945
+ const { serverName, enabled } = body;
946
+ if (!serverName || enabled === undefined) {
947
+ return { error: 'serverName and enabled are required', status: 400 };
948
+ }
949
+ return toggleCodexMcpServer(serverName, enabled);
950
+ });
951
+ return true;
952
+ }
953
+ // API: Toggle MCP server enabled/disabled
954
+ if (pathname === '/api/mcp-toggle' && req.method === 'POST') {
955
+ handlePostRequest(req, res, async (body) => {
956
+ const { projectPath, serverName, enable } = body;
957
+ if (!projectPath || !serverName) {
958
+ return { error: 'projectPath and serverName are required', status: 400 };
959
+ }
960
+ return toggleMcpServerEnabled(projectPath, serverName, enable);
961
+ });
962
+ return true;
963
+ }
964
+ // API: Copy MCP server to project
965
+ if (pathname === '/api/mcp-copy-server' && req.method === 'POST') {
966
+ handlePostRequest(req, res, async (body) => {
967
+ const { projectPath, serverName, serverConfig, configType } = body;
968
+ if (!projectPath || !serverName || !serverConfig) {
969
+ return { error: 'projectPath, serverName, and serverConfig are required', status: 400 };
970
+ }
971
+ // configType: 'mcp' = use .mcp.json (default), 'claude' = use .claude.json
972
+ const useLegacyConfig = configType === 'claude';
973
+ return addMcpServerToProject(projectPath, serverName, serverConfig, useLegacyConfig);
974
+ });
975
+ return true;
976
+ }
977
+ // API: Install CCW MCP server to project
978
+ if (pathname === '/api/mcp-install-ccw' && req.method === 'POST') {
979
+ handlePostRequest(req, res, async (body) => {
980
+ const { projectPath } = body;
981
+ if (!projectPath) {
982
+ return { error: 'projectPath is required', status: 400 };
983
+ }
984
+ // Generate CCW MCP server config
985
+ // Use cmd /c to inherit Claude Code's working directory
986
+ const ccwMcpConfig = {
987
+ command: "cmd",
988
+ args: ["/c", "npx", "-y", "ccw-mcp"],
989
+ env: {
990
+ CCW_ENABLED_TOOLS: "all"
991
+ }
992
+ };
993
+ // Use existing addMcpServerToProject to install CCW MCP
994
+ return addMcpServerToProject(projectPath, 'ccw-tools', ccwMcpConfig);
995
+ });
996
+ return true;
997
+ }
998
+ // API: Remove MCP server from project
999
+ if (pathname === '/api/mcp-remove-server' && req.method === 'POST') {
1000
+ handlePostRequest(req, res, async (body) => {
1001
+ const { projectPath, serverName } = body;
1002
+ if (!projectPath || !serverName) {
1003
+ return { error: 'projectPath and serverName are required', status: 400 };
1004
+ }
1005
+ return removeMcpServerFromProject(projectPath, serverName);
1006
+ });
1007
+ return true;
1008
+ }
1009
+ // API: Add MCP server to global scope (top-level mcpServers in ~/.claude.json)
1010
+ if (pathname === '/api/mcp-add-global-server' && req.method === 'POST') {
1011
+ handlePostRequest(req, res, async (body) => {
1012
+ const { serverName, serverConfig } = body;
1013
+ if (!serverName || !serverConfig) {
1014
+ return { error: 'serverName and serverConfig are required', status: 400 };
1015
+ }
1016
+ return addGlobalMcpServer(serverName, serverConfig);
1017
+ });
1018
+ return true;
1019
+ }
1020
+ // API: Remove MCP server from global scope
1021
+ if (pathname === '/api/mcp-remove-global-server' && req.method === 'POST') {
1022
+ handlePostRequest(req, res, async (body) => {
1023
+ const { serverName } = body;
1024
+ if (!serverName) {
1025
+ return { error: 'serverName is required', status: 400 };
1026
+ }
1027
+ return removeGlobalMcpServer(serverName);
1028
+ });
1029
+ return true;
1030
+ }
1031
+ // ========================================
1032
+ // MCP Templates API
1033
+ // ========================================
1034
+ // API: Get all MCP templates
1035
+ if (pathname === '/api/mcp-templates' && req.method === 'GET') {
1036
+ const templates = McpTemplatesDb.getAllTemplates();
1037
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1038
+ res.end(JSON.stringify({ success: true, templates }));
1039
+ return true;
1040
+ }
1041
+ // API: Save MCP template
1042
+ if (pathname === '/api/mcp-templates' && req.method === 'POST') {
1043
+ handlePostRequest(req, res, async (body) => {
1044
+ const { name, description, serverConfig, tags, category } = body;
1045
+ if (!name || !serverConfig) {
1046
+ return { error: 'name and serverConfig are required', status: 400 };
1047
+ }
1048
+ return McpTemplatesDb.saveTemplate({
1049
+ name,
1050
+ description,
1051
+ serverConfig,
1052
+ tags,
1053
+ category
1054
+ });
1055
+ });
1056
+ return true;
1057
+ }
1058
+ // API: Get template by name
1059
+ if (pathname.startsWith('/api/mcp-templates/') && req.method === 'GET') {
1060
+ const templateName = decodeURIComponent(pathname.split('/api/mcp-templates/')[1]);
1061
+ const template = McpTemplatesDb.getTemplateByName(templateName);
1062
+ if (template) {
1063
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1064
+ res.end(JSON.stringify({ success: true, template }));
1065
+ }
1066
+ else {
1067
+ res.writeHead(404, { 'Content-Type': 'application/json' });
1068
+ res.end(JSON.stringify({ success: false, error: 'Template not found' }));
1069
+ }
1070
+ return true;
1071
+ }
1072
+ // API: Delete MCP template
1073
+ if (pathname.startsWith('/api/mcp-templates/') && req.method === 'DELETE') {
1074
+ const templateName = decodeURIComponent(pathname.split('/api/mcp-templates/')[1]);
1075
+ const result = McpTemplatesDb.deleteTemplate(templateName);
1076
+ res.writeHead(result.success ? 200 : 404, { 'Content-Type': 'application/json' });
1077
+ res.end(JSON.stringify(result));
1078
+ return true;
1079
+ }
1080
+ // API: Search MCP templates
1081
+ if (pathname === '/api/mcp-templates/search' && req.method === 'GET') {
1082
+ const keyword = url.searchParams.get('q') || '';
1083
+ const templates = McpTemplatesDb.searchTemplates(keyword);
1084
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1085
+ res.end(JSON.stringify({ success: true, templates }));
1086
+ return true;
1087
+ }
1088
+ // API: Get all categories
1089
+ if (pathname === '/api/mcp-templates/categories' && req.method === 'GET') {
1090
+ const categories = McpTemplatesDb.getAllCategories();
1091
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1092
+ res.end(JSON.stringify({ success: true, categories }));
1093
+ return true;
1094
+ }
1095
+ // API: Get templates by category
1096
+ if (pathname.startsWith('/api/mcp-templates/category/') && req.method === 'GET') {
1097
+ const category = decodeURIComponent(pathname.split('/api/mcp-templates/category/')[1]);
1098
+ const templates = McpTemplatesDb.getTemplatesByCategory(category);
1099
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1100
+ res.end(JSON.stringify({ success: true, templates }));
1101
+ return true;
1102
+ }
1103
+ // API: Install template to project or global
1104
+ if (pathname === '/api/mcp-templates/install' && req.method === 'POST') {
1105
+ handlePostRequest(req, res, async (body) => {
1106
+ const { templateName, projectPath, scope } = body;
1107
+ if (!templateName) {
1108
+ return { error: 'templateName is required', status: 400 };
1109
+ }
1110
+ const template = McpTemplatesDb.getTemplateByName(templateName);
1111
+ if (!template) {
1112
+ return { error: 'Template not found', status: 404 };
1113
+ }
1114
+ // Install to global or project
1115
+ if (scope === 'global') {
1116
+ return addGlobalMcpServer(templateName, template.serverConfig);
1117
+ }
1118
+ else {
1119
+ if (!projectPath) {
1120
+ return { error: 'projectPath is required for project scope', status: 400 };
1121
+ }
1122
+ return addMcpServerToProject(projectPath, templateName, template.serverConfig);
1123
+ }
1124
+ });
1125
+ return true;
1126
+ }
1127
+ return false;
1128
+ }
1129
+ //# sourceMappingURL=mcp-routes.js.map