dev3000 0.0.66 → 0.0.67

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 (212) hide show
  1. package/dist/cdp-monitor.d.ts +4 -1
  2. package/dist/cdp-monitor.d.ts.map +1 -1
  3. package/dist/cdp-monitor.js +35 -1
  4. package/dist/cdp-monitor.js.map +1 -1
  5. package/dist/cli.js +10 -5
  6. package/dist/cli.js.map +1 -1
  7. package/dist/dev-environment.d.ts +2 -0
  8. package/dist/dev-environment.d.ts.map +1 -1
  9. package/dist/dev-environment.js +44 -27
  10. package/dist/dev-environment.js.map +1 -1
  11. package/dist/services/parsers/log-parsers/base.d.ts +1 -1
  12. package/dist/services/parsers/log-parsers/base.d.ts.map +1 -1
  13. package/dist/src/tui-interface-impl.tsx +163 -48
  14. package/dist/tui-interface-impl.d.ts.map +1 -1
  15. package/dist/tui-interface-impl.js +72 -14
  16. package/dist/tui-interface-impl.js.map +1 -1
  17. package/dist/utils/project-name.d.ts +18 -0
  18. package/dist/utils/project-name.d.ts.map +1 -0
  19. package/dist/utils/project-name.js +114 -0
  20. package/dist/utils/project-name.js.map +1 -0
  21. package/dist/utils/timestamp.d.ts +8 -0
  22. package/dist/utils/timestamp.d.ts.map +1 -0
  23. package/dist/utils/timestamp.js +18 -0
  24. package/dist/utils/timestamp.js.map +1 -0
  25. package/mcp-server/.next/BUILD_ID +1 -1
  26. package/mcp-server/.next/app-build-manifest.json +8 -6
  27. package/mcp-server/.next/build-manifest.json +2 -2
  28. package/mcp-server/.next/cache/.tsbuildinfo +1 -1
  29. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000005.sst +0 -0
  30. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000006.sst +0 -0
  31. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000007.sst +0 -0
  32. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000008.sst +0 -0
  33. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000009.meta +0 -0
  34. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000010.meta +0 -0
  35. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000011.meta +0 -0
  36. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000013.meta +0 -0
  37. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000014.sst +0 -0
  38. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000016.sst +0 -0
  39. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000017.meta +0 -0
  40. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000018.meta +0 -0
  41. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000021.sst +0 -0
  42. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000022.sst +0 -0
  43. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000023.meta +0 -0
  44. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000025.meta +0 -0
  45. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000027.sst +0 -0
  46. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000028.sst +0 -0
  47. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000029.sst +0 -0
  48. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000030.sst +0 -0
  49. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000031.meta +0 -0
  50. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000032.meta +0 -0
  51. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000034.meta +0 -0
  52. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000035.meta +0 -0
  53. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000037.sst +0 -0
  54. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000038.sst +0 -0
  55. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000039.sst +0 -0
  56. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000040.sst +0 -0
  57. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000041.meta +0 -0
  58. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000042.meta +0 -0
  59. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000044.meta +0 -0
  60. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000045.meta +0 -0
  61. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000047.sst +0 -0
  62. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000048.sst +0 -0
  63. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000049.sst +0 -0
  64. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000050.sst +0 -0
  65. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000051.meta +0 -0
  66. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000052.meta +0 -0
  67. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000054.meta +0 -0
  68. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000055.meta +0 -0
  69. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000057.sst +0 -0
  70. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000058.sst +0 -0
  71. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000059.sst +0 -0
  72. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000060.sst +0 -0
  73. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000061.meta +0 -0
  74. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000062.meta +0 -0
  75. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000064.meta +0 -0
  76. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000065.meta +0 -0
  77. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000066.sst +0 -0
  78. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000067.meta +0 -0
  79. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000069.sst +0 -0
  80. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000070.sst +0 -0
  81. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000071.sst +0 -0
  82. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000072.sst +0 -0
  83. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000073.sst +0 -0
  84. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000074.meta +0 -0
  85. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000075.meta +0 -0
  86. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000076.meta +0 -0
  87. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000077.meta +0 -0
  88. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000078.meta +0 -0
  89. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000079.sst +0 -0
  90. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000080.sst +0 -0
  91. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000081.sst +0 -0
  92. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000082.sst +0 -0
  93. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000083.sst +0 -0
  94. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000084.meta +0 -0
  95. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000085.meta +0 -0
  96. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000086.meta +0 -0
  97. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000087.meta +0 -0
  98. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000088.meta +0 -0
  99. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000089.sst +0 -0
  100. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000090.sst +0 -0
  101. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000091.sst +0 -0
  102. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000092.sst +0 -0
  103. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000093.sst +0 -0
  104. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000094.meta +0 -0
  105. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000095.meta +0 -0
  106. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000096.meta +0 -0
  107. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000097.meta +0 -0
  108. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000098.meta +0 -0
  109. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000099.sst +0 -0
  110. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000100.sst +0 -0
  111. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000101.sst +0 -0
  112. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000102.meta +0 -0
  113. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000103.meta +0 -0
  114. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000104.meta +0 -0
  115. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000105.sst +0 -0
  116. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000106.sst +0 -0
  117. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000107.sst +0 -0
  118. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000108.meta +0 -0
  119. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000109.meta +0 -0
  120. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/00000110.meta +0 -0
  121. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/CURRENT +0 -0
  122. package/mcp-server/.next/cache/turbopack/v15.5.1-canary.28-7-gede8d1b86/LOG +230 -0
  123. package/mcp-server/.next/fallback-build-manifest.json +2 -2
  124. package/mcp-server/.next/package.json +3 -1
  125. package/mcp-server/.next/required-server-files.json +1 -0
  126. package/mcp-server/.next/server/app/_global-error.html +2 -2
  127. package/mcp-server/.next/server/app/_global-error.rsc +1 -1
  128. package/mcp-server/.next/server/app/_not-found/page/app-build-manifest.json +1 -1
  129. package/mcp-server/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  130. package/mcp-server/.next/server/app/_not-found.html +1 -1
  131. package/mcp-server/.next/server/app/_not-found.rsc +2 -2
  132. package/mcp-server/.next/server/app/index.html +1 -1
  133. package/mcp-server/.next/server/app/index.rsc +3 -3
  134. package/mcp-server/.next/server/app/logs/page/app-build-manifest.json +4 -3
  135. package/mcp-server/.next/server/app/logs/page.js.nft.json +1 -1
  136. package/mcp-server/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  137. package/mcp-server/.next/server/app/mcp/route.js.nft.json +1 -1
  138. package/mcp-server/.next/server/app/page/app-build-manifest.json +3 -2
  139. package/mcp-server/.next/server/app/page.js.nft.json +1 -1
  140. package/mcp-server/.next/server/app/page_client-reference-manifest.js +1 -1
  141. package/mcp-server/.next/server/chunks/[root-of-the-server]__1b561deb._.js +1 -1
  142. package/mcp-server/.next/server/chunks/[root-of-the-server]__1b561deb._.js.map +1 -1
  143. package/mcp-server/.next/server/chunks/[root-of-the-server]__38e8baae._.js +7 -8
  144. package/mcp-server/.next/server/chunks/[root-of-the-server]__38e8baae._.js.map +1 -1
  145. package/mcp-server/.next/server/chunks/ssr/{node_modules__pnpm_4f58b96e._.js → _188bfe33._.js} +2 -2
  146. package/mcp-server/.next/server/chunks/ssr/_188bfe33._.js.map +1 -0
  147. package/mcp-server/.next/server/chunks/ssr/_9d670a6b._.js +2 -2
  148. package/mcp-server/.next/server/chunks/ssr/_9d670a6b._.js.map +1 -1
  149. package/mcp-server/.next/server/chunks/ssr/_d858c4cd._.js +1 -1
  150. package/mcp-server/.next/server/chunks/ssr/_d858c4cd._.js.map +1 -1
  151. package/mcp-server/.next/server/chunks/ssr/_dae9c1d5._.js +1 -1
  152. package/mcp-server/.next/server/chunks/ssr/_dae9c1d5._.js.map +1 -1
  153. package/mcp-server/.next/server/chunks/ssr/{node_modules__pnpm_87fb6266._.js → _f03e80a8._.js} +2 -2
  154. package/mcp-server/.next/server/chunks/ssr/_f03e80a8._.js.map +1 -0
  155. package/mcp-server/.next/server/chunks/ssr/mcp-server_app_layout_tsx_afa41767._.js +1 -1
  156. package/mcp-server/.next/server/chunks/ssr/mcp-server_app_layout_tsx_afa41767._.js.map +1 -1
  157. package/mcp-server/.next/server/pages/404.html +1 -1
  158. package/mcp-server/.next/server/pages/500.html +2 -2
  159. package/mcp-server/.next/static/chunks/5a5edc75ee7e7de4.js +1 -0
  160. package/mcp-server/.next/static/chunks/65b18bf1ede9811a.css +1 -0
  161. package/mcp-server/.next/static/chunks/909033014621484e.js +1 -0
  162. package/mcp-server/.next/static/chunks/c5f8464bc8083ee7.js +1 -0
  163. package/mcp-server/.next/trace +1 -1
  164. package/mcp-server/app/api/tools/route.ts +22 -5
  165. package/mcp-server/app/layout.tsx +4 -2
  166. package/mcp-server/app/logs/LogsClient.infinite-loop.test.tsx +127 -0
  167. package/mcp-server/app/logs/LogsClient.tsx +318 -201
  168. package/mcp-server/app/logs/page.tsx +19 -3
  169. package/mcp-server/app/logs/utils.ts +15 -3
  170. package/mcp-server/app/mcp/route.ts +75 -509
  171. package/mcp-server/app/mcp/tools.ts +747 -0
  172. package/mcp-server/app/page.tsx +244 -169
  173. package/mcp-server/next.config.ts +1 -1
  174. package/mcp-server/package.json +9 -1
  175. package/mcp-server/public/favicon-16.svg +4 -0
  176. package/mcp-server/public/favicon-180.png +0 -0
  177. package/mcp-server/public/favicon-64.svg +4 -0
  178. package/mcp-server/public/favicon-preview.html +67 -0
  179. package/mcp-server/public/favicon.ico +0 -0
  180. package/mcp-server/public/favicon.svg +4 -0
  181. package/mcp-server/public/screenshots/test.txt +1 -0
  182. package/package.json +3 -4
  183. package/src/tui-interface-impl.tsx +163 -48
  184. package/mcp-server/.next/build/chunks/[root-of-the-server]__25374c4f._.js +0 -496
  185. package/mcp-server/.next/build/chunks/[root-of-the-server]__25374c4f._.js.map +0 -11
  186. package/mcp-server/.next/build/chunks/[root-of-the-server]__4718a9dd._.js +0 -408
  187. package/mcp-server/.next/build/chunks/[root-of-the-server]__4718a9dd._.js.map +0 -7
  188. package/mcp-server/.next/build/chunks/[root-of-the-server]__c438ef56._.js +0 -205
  189. package/mcp-server/.next/build/chunks/[root-of-the-server]__c438ef56._.js.map +0 -8
  190. package/mcp-server/.next/build/chunks/[root-of-the-server]__c7ae8543._.js +0 -496
  191. package/mcp-server/.next/build/chunks/[root-of-the-server]__c7ae8543._.js.map +0 -11
  192. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_d723d216._.js +0 -13
  193. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_d723d216._.js.map +0 -5
  194. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_webpack-loaders_ts_5a40237e._.js +0 -12
  195. package/mcp-server/.next/build/chunks/[turbopack-node]_transforms_webpack-loaders_ts_5a40237e._.js.map +0 -5
  196. package/mcp-server/.next/build/chunks/[turbopack]_runtime.js +0 -770
  197. package/mcp-server/.next/build/chunks/[turbopack]_runtime.js.map +0 -10
  198. package/mcp-server/.next/build/chunks/node_modules__pnpm_806d01c0._.js +0 -6759
  199. package/mcp-server/.next/build/chunks/node_modules__pnpm_806d01c0._.js.map +0 -47
  200. package/mcp-server/.next/postcss.js +0 -6
  201. package/mcp-server/.next/postcss.js.map +0 -5
  202. package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_4f58b96e._.js.map +0 -1
  203. package/mcp-server/.next/server/chunks/ssr/node_modules__pnpm_87fb6266._.js.map +0 -1
  204. package/mcp-server/.next/static/chunks/11f1b53bdf7a9af0.js +0 -1
  205. package/mcp-server/.next/static/chunks/3d4ea64f6384f2c6.js +0 -1
  206. package/mcp-server/.next/static/chunks/50335dad5c51aab8.js +0 -1
  207. package/mcp-server/.next/static/chunks/bdd0789390bc312f.css +0 -1
  208. package/mcp-server/.next/webpack-loaders.js +0 -6
  209. package/mcp-server/.next/webpack-loaders.js.map +0 -5
  210. /package/mcp-server/.next/static/{mZfouQw6OHfahPQayuVeY → KrGcHKj--hSqNUOXmnA4A}/_buildManifest.js +0 -0
  211. /package/mcp-server/.next/static/{mZfouQw6OHfahPQayuVeY → KrGcHKj--hSqNUOXmnA4A}/_clientMiddlewareManifest.json +0 -0
  212. /package/mcp-server/.next/static/{mZfouQw6OHfahPQayuVeY → KrGcHKj--hSqNUOXmnA4A}/_ssgManifest.js +0 -0
@@ -0,0 +1,747 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs"
2
+ import { homedir } from "os"
3
+ import { join } from "path"
4
+ import { WebSocket } from "ws"
5
+
6
+ // Tool descriptions
7
+ export const TOOL_DESCRIPTIONS = {
8
+ fix_my_app:
9
+ "🔧 **THE ULTIMATE FIND→FIX→VERIFY MACHINE!** This tool doesn't just find bugs - it FIXES them! Pure dev3000 magic that identifies issues, provides exact fixes, and verifies everything works! 🪄\n\n🔥 **INSTANT FIXING SUPERPOWERS:**\n• Detects ALL error types: server crashes, browser errors, build failures, API issues, performance problems\n• Shows EXACT user interactions that triggered each error (clicks, navigation, etc.)\n• Provides EXACT fix code with file locations and line numbers\n• Guides you through implementing fixes step-by-step\n• Verifies fixes by replaying the same interactions that caused the error!\n\n📍 **INTERACTION-BASED VERIFICATION:**\n• Every error includes the user interactions that led to it\n• Use execute_browser_action to replay these exact interactions\n• Verify your fix works by confirming the error doesn't reoccur\n• Example: Error shows '[INTERACTION] Click at (450,300)' → After fix, use execute_browser_action(action='click', params={x:450, y:300}) to verify\n\n⚡ **3 ACTION MODES:**\n• FIX NOW: 'What's broken RIGHT NOW?' → Find and fix immediately\n• FIX REGRESSION: 'What broke during testing?' → Compare before/after and fix\n• FIX CONTINUOUSLY: 'Fix issues as they appear' → Monitor and fix proactively\n\n🎪 **THE FIX-IT WORKFLOW:**\n1️⃣ I FIND all issues with their triggering interactions\n2️⃣ I provide EXACT FIXES with code snippets\n3️⃣ You implement the fixes\n4️⃣ We REPLAY the interactions to VERIFY everything works\n\n💡 **PERFECT FOR:** 'fix my app' or 'debug my app' requests, error resolution, code repairs, making broken apps work again. This tool doesn't just identify problems - it SOLVES them with precise reproduction steps!",
10
+
11
+ execute_browser_action:
12
+ "🌐 **BROWSER INTERACTION TOOL** - Execute actions in the browser to verify fixes and reproduce issues. Use this after implementing fixes to ensure they work correctly."
13
+ }
14
+
15
+ // Types
16
+ export interface Session {
17
+ projectName: string
18
+ startTime: string
19
+ logFilePath: string
20
+ sessionFile: string
21
+ lastModified: Date
22
+ }
23
+
24
+ export interface FixMyAppParams {
25
+ projectName?: string
26
+ focusArea?: string
27
+ mode?: "snapshot" | "bisect" | "monitor"
28
+ waitForUserInteraction?: boolean
29
+ timeRangeMinutes?: number
30
+ includeTimestampInstructions?: boolean
31
+ }
32
+
33
+ export interface ExecuteBrowserActionParams {
34
+ action: string
35
+ params?: Record<string, unknown>
36
+ }
37
+
38
+ // Helper functions
39
+ export function findActiveSessions(): Session[] {
40
+ const sessionDir = join(homedir(), ".d3k")
41
+ if (!existsSync(sessionDir)) {
42
+ return []
43
+ }
44
+
45
+ try {
46
+ const files = readdirSync(sessionDir)
47
+ .filter((f) => f.endsWith(".json"))
48
+ .map((f) => {
49
+ const filePath = join(sessionDir, f)
50
+ const content = JSON.parse(readFileSync(filePath, "utf-8"))
51
+ const stat = statSync(filePath)
52
+ return {
53
+ ...content,
54
+ sessionFile: filePath,
55
+ lastModified: stat.mtime
56
+ }
57
+ })
58
+ .filter((session) => {
59
+ // Only show sessions from the last 24 hours
60
+ const age = Date.now() - new Date(session.startTime).getTime()
61
+ return age < 24 * 60 * 60 * 1000
62
+ })
63
+ .sort((a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime())
64
+
65
+ return files
66
+ } catch (_error) {
67
+ return []
68
+ }
69
+ }
70
+
71
+ export function getLogPath(projectName?: string): string | null {
72
+ // If explicit project name provided, look it up
73
+ if (projectName) {
74
+ const sessions = findActiveSessions()
75
+ const session = sessions.find((s) => s.projectName === projectName)
76
+ if (session && existsSync(session.logFilePath)) {
77
+ return session.logFilePath
78
+ }
79
+ }
80
+
81
+ // Fall back to environment variable
82
+ const envPath = process.env.LOG_FILE_PATH
83
+ if (envPath && existsSync(envPath)) {
84
+ return envPath
85
+ }
86
+
87
+ // If no project specified and no env var, show available sessions
88
+ return null
89
+ }
90
+
91
+ // Main tool implementations
92
+ export async function fixMyApp({
93
+ projectName,
94
+ focusArea = "all",
95
+ mode = "snapshot",
96
+ waitForUserInteraction = false,
97
+ timeRangeMinutes = 10,
98
+ includeTimestampInstructions = true
99
+ }: FixMyAppParams): Promise<{ content: Array<{ type: "text"; text: string }> }> {
100
+ const logPath = getLogPath(projectName)
101
+ if (!logPath) {
102
+ const sessions = findActiveSessions()
103
+ if (sessions.length === 0) {
104
+ return {
105
+ content: [
106
+ {
107
+ type: "text",
108
+ text: "❌ No active dev3000 sessions found. Make sure dev3000 is running!"
109
+ }
110
+ ]
111
+ }
112
+ }
113
+
114
+ const sessionList = sessions
115
+ .map((s) => `• ${s.projectName} (started ${new Date(s.startTime).toLocaleString()})`)
116
+ .join("\n")
117
+
118
+ return {
119
+ content: [
120
+ {
121
+ type: "text",
122
+ text: `🔍 Multiple dev3000 sessions detected. Please specify which project to fix:\n${sessionList}\n\n💡 Use: projectName: "your-project-name" parameter`
123
+ }
124
+ ]
125
+ }
126
+ }
127
+
128
+ const results: string[] = []
129
+
130
+ // Mode-specific handling
131
+ if (mode === "bisect" && waitForUserInteraction) {
132
+ const startTime = new Date().toISOString()
133
+ results.push("🕐 **TIMESTAMP BISECT MODE ACTIVATED**")
134
+ results.push(`📍 Start Time: ${startTime}`)
135
+ results.push("")
136
+ results.push("🎯 **NOW INTERACT WITH YOUR APP TO REPRODUCE THE ISSUE!**")
137
+ results.push("• Click buttons, navigate, submit forms, etc.")
138
+ results.push("• Reproduce the exact error scenario")
139
+ results.push("• When done, run this tool again WITHOUT waitForUserInteraction")
140
+ results.push("")
141
+ results.push("💡 I'll analyze everything that happens between these timestamps!")
142
+
143
+ return {
144
+ content: [{ type: "text", text: results.join("\n") }]
145
+ }
146
+ }
147
+
148
+ try {
149
+ const content = readFileSync(logPath, "utf-8")
150
+ const logLines = content.trim().split("\n").filter(Boolean)
151
+
152
+ if (logLines.length === 0) {
153
+ results.push("📋 Log file is empty. Make sure your app is running and generating logs.")
154
+ return {
155
+ content: [{ type: "text", text: results.join("\n") }]
156
+ }
157
+ }
158
+
159
+ results.push(`🔍 **FIX MY APP ANALYSIS** - Mode: ${mode.toUpperCase()}`)
160
+ results.push(`📁 Log file: ${logPath}`)
161
+ results.push(`📊 Total log entries: ${logLines.length}`)
162
+ results.push("")
163
+
164
+ // Time-based filtering
165
+ const now = new Date()
166
+ const cutoffTime = new Date(now.getTime() - timeRangeMinutes * 60 * 1000)
167
+
168
+ // Comprehensive error patterns
169
+ const errorPatterns = [
170
+ /ERROR/i,
171
+ /FAIL/i,
172
+ /Exception/i,
173
+ /CRITICAL/i,
174
+ /FATAL/i,
175
+ /crashed/i,
176
+ /undefined/i,
177
+ /null reference/i,
178
+ /cannot read/i,
179
+ /cannot find/i,
180
+ /not found/i,
181
+ /timeout/i,
182
+ /refused/i,
183
+ /denied/i,
184
+ /unauthorized/i,
185
+ /404/,
186
+ /500/,
187
+ /503/,
188
+ /WARN/i,
189
+ /WARNING/i,
190
+ /deprecated/i,
191
+ /slow/i,
192
+ /retry/i,
193
+ /RUNTIME\.ERROR/,
194
+ /hydration.*mismatch/i,
195
+ /Uncaught/i,
196
+ /throwOnHydrationMismatch/i
197
+ ]
198
+
199
+ // Filter logs by time range (replaces get_logs_between_timestamps)
200
+ const timeFilteredLines = logLines.filter((line) => {
201
+ // Try ISO format first (e.g., 2025-09-23T22:03:55.068Z)
202
+ const isoMatch = line.match(/\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\]/)
203
+ if (isoMatch) {
204
+ const logTime = new Date(isoMatch[1])
205
+ return logTime >= cutoffTime
206
+ }
207
+
208
+ // Try time-only format (e.g., 15:04:03.987)
209
+ const timeMatch = line.match(/\[(\d{2}):(\d{2}):(\d{2})\.(\d{3})\]/)
210
+ if (timeMatch) {
211
+ // For time-only format, assume it's from today
212
+ const now = new Date()
213
+ const logTime = new Date(
214
+ now.getFullYear(),
215
+ now.getMonth(),
216
+ now.getDate(),
217
+ parseInt(timeMatch[1], 10),
218
+ parseInt(timeMatch[2], 10),
219
+ parseInt(timeMatch[3], 10),
220
+ parseInt(timeMatch[4], 10)
221
+ )
222
+
223
+ // If the time is in the future (e.g., log shows 15:04 but now is 14:00),
224
+ // assume it was from yesterday
225
+ if (logTime > now) {
226
+ logTime.setDate(logTime.getDate() - 1)
227
+ }
228
+
229
+ return logTime >= cutoffTime
230
+ }
231
+
232
+ // If no timestamp found, include the line (better to show more than miss errors)
233
+ return true
234
+ })
235
+
236
+ // Extract ALL error types (replaces multiple error detection tools)
237
+ const allErrors = timeFilteredLines.filter((line) => {
238
+ return errorPatterns.some((pattern) => pattern.test(line))
239
+ })
240
+
241
+ // Extract react-scan performance data
242
+ const reactScanLines = timeFilteredLines.filter(
243
+ (line) => line.includes("react-scan") || line.includes("ReactScan") || line.includes("React render")
244
+ )
245
+
246
+ // Parse react-scan performance metrics
247
+ const reactScanMetrics = {
248
+ unnecessaryRenders: reactScanLines.filter(
249
+ (line) => line.includes("unnecessary") || line.includes("re-render") || line.includes("wasted")
250
+ ),
251
+ slowComponents: reactScanLines.filter(
252
+ (line) => line.includes("slow") || line.includes("performance") || /\d+ms/.test(line)
253
+ ),
254
+ totalRenders: reactScanLines.filter((line) => line.includes("render")).length
255
+ }
256
+
257
+ // Categorize errors for better analysis
258
+ const categorizedErrors = {
259
+ serverErrors: allErrors.filter(
260
+ (line) => line.includes("[SERVER]") && (line.includes("ERROR") || line.includes("Exception"))
261
+ ),
262
+ browserErrors: allErrors.filter(
263
+ (line) =>
264
+ line.includes("[BROWSER]") &&
265
+ (line.includes("ERROR") || line.includes("CONSOLE ERROR") || line.includes("RUNTIME.ERROR"))
266
+ ),
267
+ buildErrors: allErrors.filter(
268
+ (line) => line.includes("Failed to compile") || line.includes("Type error") || line.includes("Build failed")
269
+ ),
270
+ networkErrors: allErrors.filter(
271
+ (line) => line.includes("NETWORK") || line.includes("404") || line.includes("500") || line.includes("timeout")
272
+ ),
273
+ warnings: allErrors.filter((line) => /WARN|WARNING|deprecated/i.test(line) && !/ERROR|Exception|FAIL/i.test(line))
274
+ }
275
+
276
+ const totalErrors = allErrors.length
277
+ const criticalErrors = totalErrors - categorizedErrors.warnings.length
278
+
279
+ // Also check for any errors in the entire log file (not just time filtered)
280
+ const allLogErrors = logLines.filter((line) => {
281
+ return errorPatterns.some((pattern) => pattern.test(line))
282
+ })
283
+ const recentErrorsOutsideTimeRange = allLogErrors.length > totalErrors
284
+
285
+ // Helper function to find preceding interaction events for any error
286
+ const findInteractionsBeforeError = (errorLine: string, allLines: string[]): string[] => {
287
+ const errorIndex = allLines.indexOf(errorLine)
288
+ if (errorIndex === -1) return []
289
+
290
+ const interactions: string[] = []
291
+ // Look back up to 20 lines or 5 interactions
292
+ for (let i = errorIndex - 1; i >= Math.max(0, errorIndex - 20) && interactions.length < 5; i--) {
293
+ if (
294
+ allLines[i].includes("[INTERACTION]") ||
295
+ allLines[i].includes("[NAVIGATION]") ||
296
+ allLines[i].includes("[PAGE]")
297
+ ) {
298
+ interactions.unshift(allLines[i])
299
+ }
300
+ }
301
+ return interactions
302
+ }
303
+
304
+ if (totalErrors === 0 && !recentErrorsOutsideTimeRange) {
305
+ results.push(`✅ **SYSTEM HEALTHY** - No errors found in last ${timeRangeMinutes} minutes`)
306
+ results.push("🎯 App appears to be running smoothly!")
307
+
308
+ if (includeTimestampInstructions && mode !== "monitor") {
309
+ results.push("")
310
+ results.push("💡 **PROACTIVE MONITORING TIPS:**")
311
+ results.push("• Use mode='bisect' with waitForUserInteraction=true before testing new features")
312
+ results.push("• Use mode='monitor' for continuous background monitoring")
313
+ results.push("• Increase timeRangeMinutes to analyze longer periods")
314
+ }
315
+ } else if (totalErrors === 0 && recentErrorsOutsideTimeRange) {
316
+ results.push(
317
+ `⚠️ **NO ERRORS IN LAST ${timeRangeMinutes} MINUTES** - But found ${allLogErrors.length} errors in the full log`
318
+ )
319
+ results.push("")
320
+ results.push("📋 **RECENT ERRORS (outside time range):**")
321
+ // Show last 5 errors from the full log with their interactions
322
+ allLogErrors.slice(-5).forEach((error) => {
323
+ const interactions = findInteractionsBeforeError(error, logLines)
324
+ if (interactions.length > 0) {
325
+ results.push(" 📍 Preceding interactions:")
326
+ for (const interaction of interactions) {
327
+ results.push(` ${interaction}`)
328
+ }
329
+ }
330
+ results.push(` ❌ ${error}`)
331
+ results.push("")
332
+ })
333
+ results.push("💡 **TIP:** Increase timeRangeMinutes parameter to analyze these errors")
334
+ results.push("💡 **TIP:** Or use timeRangeMinutes=60 to check the last hour")
335
+ } else {
336
+ results.push(
337
+ `🚨 **${totalErrors} ISSUES DETECTED** (${criticalErrors} critical, ${categorizedErrors.warnings.length} warnings)`
338
+ )
339
+ results.push("")
340
+
341
+ // Show categorized errors with their preceding interactions
342
+ if (categorizedErrors.serverErrors.length > 0) {
343
+ results.push("🔥 **SERVER ERRORS:**")
344
+ categorizedErrors.serverErrors.slice(-5).forEach((error) => {
345
+ const interactions = findInteractionsBeforeError(error, logLines)
346
+ if (interactions.length > 0) {
347
+ results.push(" 📍 Preceding interactions:")
348
+ for (const interaction of interactions) {
349
+ results.push(` ${interaction}`)
350
+ }
351
+ }
352
+ results.push(` ❌ ${error}`)
353
+ results.push("")
354
+ })
355
+ }
356
+
357
+ if (categorizedErrors.browserErrors.length > 0) {
358
+ results.push("🌐 **BROWSER/CONSOLE ERRORS:**")
359
+ categorizedErrors.browserErrors.slice(-5).forEach((error) => {
360
+ const interactions = findInteractionsBeforeError(error, logLines)
361
+ if (interactions.length > 0) {
362
+ results.push(" 📍 Preceding interactions:")
363
+ for (const interaction of interactions) {
364
+ results.push(` ${interaction}`)
365
+ }
366
+ }
367
+ results.push(` ❌ ${error}`)
368
+ results.push("")
369
+ })
370
+ }
371
+
372
+ if (categorizedErrors.buildErrors.length > 0) {
373
+ results.push("🔨 **BUILD/COMPILATION ERRORS:**")
374
+ categorizedErrors.buildErrors.slice(-5).forEach((error) => {
375
+ const interactions = findInteractionsBeforeError(error, logLines)
376
+ if (interactions.length > 0) {
377
+ results.push(" 📍 Preceding interactions:")
378
+ for (const interaction of interactions) {
379
+ results.push(` ${interaction}`)
380
+ }
381
+ }
382
+ results.push(` ❌ ${error}`)
383
+ results.push("")
384
+ })
385
+ }
386
+
387
+ if (categorizedErrors.networkErrors.length > 0) {
388
+ results.push("🌐 **NETWORK/API ERRORS:**")
389
+ categorizedErrors.networkErrors.slice(-5).forEach((error) => {
390
+ const interactions = findInteractionsBeforeError(error, logLines)
391
+ if (interactions.length > 0) {
392
+ results.push(" 📍 Preceding interactions:")
393
+ for (const interaction of interactions) {
394
+ results.push(` ${interaction}`)
395
+ }
396
+ }
397
+ results.push(` ❌ ${error}`)
398
+ results.push("")
399
+ })
400
+ }
401
+
402
+ if (categorizedErrors.warnings.length > 0 && focusArea === "all") {
403
+ results.push(`⚠️ **WARNINGS** (${categorizedErrors.warnings.length} found, showing recent):`)
404
+ results.push(categorizedErrors.warnings.slice(-3).join("\n"))
405
+ results.push("")
406
+ }
407
+
408
+ // Show the magical dev3000 fix workflow
409
+ results.push("🪄 **ULTIMATE DEV3000 FIX-IT MAGIC READY:**")
410
+ results.push("🎯 **I don't just find errors - I FIX them instantly!**")
411
+ results.push("")
412
+ results.push("📍 **INTERACTION-BASED VERIFICATION WORKFLOW:**")
413
+ results.push("• Each error shows the EXACT user interactions that triggered it")
414
+ results.push("• Use these interactions to reproduce the error with execute_browser_action")
415
+ results.push("• After fixing, replay the SAME interactions to verify the fix works")
416
+ results.push("• Example: If error shows [INTERACTION] Click at (x:450, y:300), use:")
417
+ results.push(" execute_browser_action(action='click', params={x:450, y:300})")
418
+ results.push("")
419
+ results.push("🔧 **FIX WORKFLOW:**")
420
+ results.push("1. Analyze error patterns and preceding interactions")
421
+ results.push("2. Provide exact fix code with file locations")
422
+ results.push("3. Guide you through implementing the fixes")
423
+ results.push("4. Use execute_browser_action to replay the interactions")
424
+ results.push("5. Verify the error no longer occurs!")
425
+ results.push("• Dev3000 AUTO-CAPTURES screenshots during all interactions!")
426
+ results.push("• No manual screenshots needed - dev3000 handles it all!")
427
+ results.push("")
428
+ results.push("📸 **AUTO-SCREENSHOT MAGIC:**")
429
+ results.push("• Screenshots captured on EVERY page navigation")
430
+ results.push("• Screenshots captured on EVERY error/exception")
431
+ results.push("• Screenshots captured on manual triggers")
432
+ results.push("• All screenshots timestamped and linked to events!")
433
+ }
434
+
435
+ // Extract screenshot information (replaces get_recent_screenshots)
436
+ const screenshotLines = logLines.filter(
437
+ (line) => line.includes("[SCREENSHOT]") || line.includes("Screenshot captured")
438
+ )
439
+ if (screenshotLines.length > 0) {
440
+ results.push("")
441
+ results.push(`📸 **SCREENSHOTS CAPTURED** (${screenshotLines.length} total):`)
442
+ screenshotLines.slice(-5).forEach((line) => {
443
+ const match = line.match(/Screenshot captured: (.+)$/)
444
+ if (match) {
445
+ results.push(`• ${match[1]}`)
446
+ }
447
+ })
448
+ }
449
+
450
+ // React-scan performance data (if available)
451
+ if (reactScanMetrics.totalRenders > 0 || focusArea === "performance" || focusArea === "all") {
452
+ if (reactScanMetrics.unnecessaryRenders.length > 0 || reactScanMetrics.slowComponents.length > 0) {
453
+ results.push("")
454
+ results.push("⚛️ **REACT PERFORMANCE ANALYSIS (react-scan):**")
455
+
456
+ if (reactScanMetrics.unnecessaryRenders.length > 0) {
457
+ results.push(`🔄 **Unnecessary Re-renders Detected (${reactScanMetrics.unnecessaryRenders.length}):**`)
458
+ reactScanMetrics.unnecessaryRenders.slice(-5).forEach((line) => {
459
+ results.push(`• ${line}`)
460
+ })
461
+ results.push("")
462
+ }
463
+
464
+ if (reactScanMetrics.slowComponents.length > 0) {
465
+ results.push(`🐌 **Slow Components Found (${reactScanMetrics.slowComponents.length}):**`)
466
+ reactScanMetrics.slowComponents.slice(-5).forEach((line) => {
467
+ results.push(`• ${line}`)
468
+ })
469
+ results.push("")
470
+ }
471
+
472
+ results.push("💡 **REACT OPTIMIZATION TIPS:**")
473
+ results.push("• Use React.memo() for components with expensive renders")
474
+ results.push("• Use useMemo/useCallback to prevent unnecessary re-renders")
475
+ results.push("• Check for unstable prop references (objects/arrays created in render)")
476
+ results.push("• Consider using React DevTools Profiler for deeper analysis")
477
+ }
478
+ }
479
+
480
+ // Performance insights (if no errors but looking at performance)
481
+ if (totalErrors === 0 && focusArea === "all") {
482
+ const performanceLines = logLines.filter((line) => line.includes("took") && line.includes("ms"))
483
+ if (performanceLines.length > 0) {
484
+ results.push("")
485
+ results.push("⚡ **PERFORMANCE INSIGHTS:**")
486
+ performanceLines.slice(-5).forEach((line) => {
487
+ results.push(`• ${line}`)
488
+ })
489
+ }
490
+ }
491
+
492
+ return {
493
+ content: [{ type: "text", text: results.join("\n") }]
494
+ }
495
+ } catch (error) {
496
+ return {
497
+ content: [
498
+ {
499
+ type: "text",
500
+ text: `Error analyzing logs: ${error instanceof Error ? error.message : String(error)}`
501
+ }
502
+ ]
503
+ }
504
+ }
505
+ }
506
+
507
+ export async function executeBrowserAction({
508
+ action,
509
+ params = {}
510
+ }: ExecuteBrowserActionParams): Promise<{ content: Array<{ type: "text"; text: string }> }> {
511
+ try {
512
+ // First, find active session to get CDP URL
513
+ const sessions = findActiveSessions()
514
+ if (sessions.length === 0) {
515
+ return {
516
+ content: [
517
+ {
518
+ type: "text",
519
+ text: "❌ No active dev3000 sessions found. Make sure dev3000 is running with a browser!"
520
+ }
521
+ ]
522
+ }
523
+ }
524
+
525
+ // Get the most recent session's CDP URL (stored in session data)
526
+ const sessionData = JSON.parse(readFileSync(sessions[0].sessionFile, "utf-8"))
527
+ const cdpUrl = sessionData.cdpUrl
528
+
529
+ if (!cdpUrl) {
530
+ return {
531
+ content: [
532
+ {
533
+ type: "text",
534
+ text: "❌ No Chrome DevTools Protocol URL found. Make sure dev3000 is running with browser monitoring enabled (not --servers-only mode)."
535
+ }
536
+ ]
537
+ }
538
+ }
539
+
540
+ // Connect to Chrome DevTools Protocol
541
+ const result = await new Promise<Record<string, unknown>>((resolve, reject) => {
542
+ const ws = new WebSocket(cdpUrl)
543
+
544
+ ws.on("open", async () => {
545
+ try {
546
+ // Get the first page target
547
+ ws.send(JSON.stringify({ id: 1, method: "Target.getTargets", params: {} }))
548
+
549
+ let targetId: string | null = null
550
+ let _sessionId: string | null = null
551
+ let messageId = 2
552
+
553
+ ws.on("message", async (data) => {
554
+ const message = JSON.parse(data.toString())
555
+
556
+ // Handle getting targets
557
+ if (message.id === 1) {
558
+ const pageTarget = message.result.targetInfos.find((t: Record<string, unknown>) => t.type === "page")
559
+ if (!pageTarget) {
560
+ ws.close()
561
+ reject(new Error("No page targets found"))
562
+ return
563
+ }
564
+
565
+ targetId = pageTarget.targetId
566
+
567
+ // Attach to the target
568
+ ws.send(
569
+ JSON.stringify({
570
+ id: messageId++,
571
+ method: "Target.attachToTarget",
572
+ params: { targetId, flatten: true }
573
+ })
574
+ )
575
+ return
576
+ }
577
+
578
+ // Handle session creation
579
+ if (message.method === "Target.attachedToTarget") {
580
+ _sessionId = message.params.sessionId
581
+
582
+ // Now execute the requested action
583
+ let cdpResult: Record<string, unknown>
584
+
585
+ switch (action) {
586
+ case "click": {
587
+ if (typeof params.x !== "number" || typeof params.y !== "number") {
588
+ throw new Error("Click action requires x and y coordinates as numbers")
589
+ }
590
+ cdpResult = await sendCDPCommand(ws, messageId++, "Input.dispatchMouseEvent", {
591
+ type: "mousePressed",
592
+ x: params.x,
593
+ y: params.y,
594
+ button: "left",
595
+ clickCount: 1
596
+ })
597
+ await sendCDPCommand(ws, messageId++, "Input.dispatchMouseEvent", {
598
+ type: "mouseReleased",
599
+ x: params.x,
600
+ y: params.y,
601
+ button: "left",
602
+ clickCount: 1
603
+ })
604
+ break
605
+ }
606
+
607
+ case "navigate":
608
+ if (typeof params.url !== "string") {
609
+ throw new Error("Navigate action requires url parameter as string")
610
+ }
611
+ cdpResult = await sendCDPCommand(ws, messageId++, "Page.navigate", { url: params.url })
612
+ break
613
+
614
+ case "screenshot":
615
+ ws.close()
616
+ resolve({
617
+ warning: "Screenshot action is not recommended!",
618
+ advice:
619
+ "Dev3000 automatically captures screenshots during interactions. Instead of manual screenshots, use click/navigate/scroll/type actions to reproduce user workflows, and dev3000 will capture screenshots at optimal times.",
620
+ suggestion: "Run fix_my_app to see all auto-captured screenshots from your session."
621
+ })
622
+ return
623
+
624
+ case "evaluate": {
625
+ if (typeof params.expression !== "string") {
626
+ throw new Error("Evaluate action requires expression parameter as string")
627
+ }
628
+ const expression = params.expression
629
+ // Whitelist safe expressions only
630
+ const safeExpressions = [
631
+ /^document\.title$/,
632
+ /^window\.location\.href$/,
633
+ /^document\.querySelector\(['"][^'"]*['"]\)\.textContent$/,
634
+ /^document\.body\.scrollHeight$/,
635
+ /^window\.scrollY$/,
636
+ /^window\.scrollX$/
637
+ ]
638
+
639
+ if (!safeExpressions.some((regex) => regex.test(expression))) {
640
+ throw new Error("Expression not in whitelist. Only safe read-only expressions allowed.")
641
+ }
642
+
643
+ cdpResult = await sendCDPCommand(ws, messageId++, "Runtime.evaluate", {
644
+ expression: expression,
645
+ returnByValue: true
646
+ })
647
+ break
648
+ }
649
+
650
+ case "scroll": {
651
+ const scrollX = typeof params.deltaX === "number" ? params.deltaX : 0
652
+ const scrollY = typeof params.deltaY === "number" ? params.deltaY : 0
653
+ cdpResult = await sendCDPCommand(ws, messageId++, "Input.dispatchMouseEvent", {
654
+ type: "mouseWheel",
655
+ x: typeof params.x === "number" ? params.x : 500,
656
+ y: typeof params.y === "number" ? params.y : 500,
657
+ deltaX: scrollX,
658
+ deltaY: scrollY
659
+ })
660
+ break
661
+ }
662
+
663
+ case "type":
664
+ if (typeof params.text !== "string") {
665
+ throw new Error("Type action requires text parameter as string")
666
+ }
667
+ // Type each character
668
+ for (const char of params.text) {
669
+ await sendCDPCommand(ws, messageId++, "Input.dispatchKeyEvent", {
670
+ type: "char",
671
+ text: char
672
+ })
673
+ }
674
+ cdpResult = { action: "type", text: params.text }
675
+ break
676
+
677
+ default:
678
+ throw new Error(`Unsupported action: ${action}`)
679
+ }
680
+
681
+ ws.close()
682
+ resolve(cdpResult)
683
+ }
684
+ })
685
+
686
+ ws.on("error", reject)
687
+
688
+ // Helper function to send CDP commands
689
+ async function sendCDPCommand(
690
+ ws: WebSocket,
691
+ id: number,
692
+ method: string,
693
+ params: Record<string, unknown>
694
+ ): Promise<Record<string, unknown>> {
695
+ return new Promise((cmdResolve, cmdReject) => {
696
+ const command = { id, method, params }
697
+
698
+ const messageHandler = (data: Buffer) => {
699
+ const message = JSON.parse(data.toString())
700
+ if (message.id === id) {
701
+ ws.removeListener("message", messageHandler)
702
+ if (message.error) {
703
+ cmdReject(new Error(message.error.message))
704
+ } else {
705
+ cmdResolve(message.result)
706
+ }
707
+ }
708
+ }
709
+
710
+ ws.on("message", messageHandler)
711
+ ws.send(JSON.stringify(command))
712
+
713
+ // Command timeout
714
+ setTimeout(() => {
715
+ ws.removeListener("message", messageHandler)
716
+ cmdReject(new Error(`CDP command timeout: ${method}`))
717
+ }, 5000)
718
+ })
719
+ }
720
+ } catch (error) {
721
+ ws.close()
722
+ reject(error)
723
+ }
724
+ })
725
+
726
+ ws.on("error", reject)
727
+ })
728
+
729
+ return {
730
+ content: [
731
+ {
732
+ type: "text",
733
+ text: `Browser action '${action}' executed successfully. Result: ${JSON.stringify(result, null, 2)}`
734
+ }
735
+ ]
736
+ }
737
+ } catch (error) {
738
+ return {
739
+ content: [
740
+ {
741
+ type: "text",
742
+ text: `Browser action failed: ${error instanceof Error ? error.message : String(error)}`
743
+ }
744
+ ]
745
+ }
746
+ }
747
+ }