@js-recon/js-recon 1.4.3 → 2.0.1-alpha.1

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 (461) hide show
  1. package/.claude-sync/sync.sh +1 -1
  2. package/.github/workflows/build-and-prettify.yaml +55 -25
  3. package/.github/workflows/codeql.yml +33 -0
  4. package/.github/workflows/exploit-smoke-test.yaml +160 -0
  5. package/.github/workflows/framework-detection-smoke-test.yaml +135 -0
  6. package/.github/workflows/plumber.yml +20 -0
  7. package/.github/workflows/promote-js-recon.yml +5 -3
  8. package/.github/workflows/publish-js-recon.yml +6 -1
  9. package/.github/workflows/rules-smoke-test.yaml +15 -7
  10. package/.nvmrc +1 -0
  11. package/.plumber.yaml +151 -0
  12. package/CHANGELOG.md +54 -0
  13. package/CONTRIBUTING.md +32 -0
  14. package/Dockerfile +1 -0
  15. package/README.md +55 -2
  16. package/SECURITY.md +1 -1
  17. package/build/analyze/engine/astEngine.js +10 -9
  18. package/build/analyze/engine/astEngine.js.map +1 -1
  19. package/build/analyze/engine/csMastSEngine.js +6 -6
  20. package/build/analyze/engine/csMastSEngine.js.map +1 -1
  21. package/build/analyze/engine/index.js +1 -1
  22. package/build/analyze/engine/index.js.map +1 -1
  23. package/build/analyze/engine/requestEngine.js +6 -6
  24. package/build/analyze/engine/requestEngine.js.map +1 -1
  25. package/build/analyze/helpers/determineCompatibleVersion.js +70 -0
  26. package/build/analyze/helpers/determineCompatibleVersion.js.map +1 -0
  27. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +9 -3
  28. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -1
  29. package/build/analyze/helpers/initRules.js +42 -24
  30. package/build/analyze/helpers/initRules.js.map +1 -1
  31. package/build/analyze/helpers/outputHelper.js +3 -3
  32. package/build/analyze/helpers/outputHelper.js.map +1 -1
  33. package/build/analyze/helpers/schemas.js +1 -0
  34. package/build/analyze/helpers/schemas.js.map +1 -1
  35. package/build/analyze/helpers/validate.js +9 -5
  36. package/build/analyze/helpers/validate.js.map +1 -1
  37. package/build/analyze/index.js +26 -16
  38. package/build/analyze/index.js.map +1 -1
  39. package/build/cliProgram.js +710 -0
  40. package/build/cliProgram.js.map +1 -0
  41. package/build/completion/index.js +245 -339
  42. package/build/completion/index.js.map +1 -1
  43. package/build/completion/introspect.js +17 -0
  44. package/build/completion/introspect.js.map +1 -0
  45. package/build/config/applicationConfig.js +494 -0
  46. package/build/config/applicationConfig.js.map +1 -0
  47. package/build/cs_mast/index.js +18 -17
  48. package/build/cs_mast/index.js.map +1 -1
  49. package/build/endpoints/gen_report/gen_json.js +2 -2
  50. package/build/endpoints/gen_report/gen_json.js.map +1 -1
  51. package/build/endpoints/gen_report/utility/iterate_n_store.js +1 -1
  52. package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -1
  53. package/build/endpoints/index.js +12 -12
  54. package/build/endpoints/index.js.map +1 -1
  55. package/build/endpoints/next_js/client_jsFilesHref.js +3 -3
  56. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -1
  57. package/build/endpoints/next_js/client_jsonParse.js +4 -4
  58. package/build/endpoints/next_js/client_jsonParse.js.map +1 -1
  59. package/build/endpoints/next_js/client_mappedJsonFile.js +6 -6
  60. package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -1
  61. package/build/endpoints/next_js/client_subsequentRequests.js +5 -5
  62. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -1
  63. package/build/exploit/angular/cve-2026-68945.js +61 -0
  64. package/build/exploit/angular/cve-2026-68945.js.map +1 -0
  65. package/build/exploit/index.js +60 -0
  66. package/build/exploit/index.js.map +1 -0
  67. package/build/exploit/next/cve-2025-29927.js +65 -0
  68. package/build/exploit/next/cve-2025-29927.js.map +1 -0
  69. package/build/exploit/next/cve-2026-64645.js +51 -0
  70. package/build/exploit/next/cve-2026-64645.js.map +1 -0
  71. package/build/exploit/nuxt/cve-2026-71315.js +47 -0
  72. package/build/exploit/nuxt/cve-2026-71315.js.map +1 -0
  73. package/build/exploit/nuxt/cve-2026-71320.js +114 -0
  74. package/build/exploit/nuxt/cve-2026-71320.js.map +1 -0
  75. package/build/exploit/react/cve-2025-55182.js +116 -0
  76. package/build/exploit/react/cve-2025-55182.js.map +1 -0
  77. package/build/exploit/registry/cveRegistry.js +115 -0
  78. package/build/exploit/registry/cveRegistry.js.map +1 -0
  79. package/build/exploit/types.js +2 -0
  80. package/build/exploit/types.js.map +1 -0
  81. package/build/exploit/utility/compareResponses.js +29 -0
  82. package/build/exploit/utility/compareResponses.js.map +1 -0
  83. package/build/exploit/utility/outputHelper.js +22 -0
  84. package/build/exploit/utility/outputHelper.js.map +1 -0
  85. package/build/exploit/utility/rawRequest.js +54 -0
  86. package/build/exploit/utility/rawRequest.js.map +1 -0
  87. package/build/exploit/utility/sandboxRce.js +49 -0
  88. package/build/exploit/utility/sandboxRce.js.map +1 -0
  89. package/build/exploit/utility/toEngineOutput.js +28 -0
  90. package/build/exploit/utility/toEngineOutput.js.map +1 -0
  91. package/build/exploit/utility/wsClient.js +78 -0
  92. package/build/exploit/utility/wsClient.js.map +1 -0
  93. package/build/exploit/vite/cve-2025-30208.js +44 -0
  94. package/build/exploit/vite/cve-2025-30208.js.map +1 -0
  95. package/build/exploit/vite/cve-2026-39363.js +60 -0
  96. package/build/exploit/vite/cve-2026-39363.js.map +1 -0
  97. package/build/fingerprint/index.js +11 -21
  98. package/build/fingerprint/index.js.map +1 -1
  99. package/build/globalConfig.js +2 -2
  100. package/build/globalConfig.js.map +1 -1
  101. package/build/index.js +16 -555
  102. package/build/index.js.map +1 -1
  103. package/build/lazyLoad/angular/angular_getFromPageSource.js +3 -3
  104. package/build/lazyLoad/angular/angular_getFromPageSource.js.map +1 -1
  105. package/build/lazyLoad/downloadFilesUtil.js +51 -40
  106. package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
  107. package/build/lazyLoad/downloadQueue.js +154 -50
  108. package/build/lazyLoad/downloadQueue.js.map +1 -1
  109. package/build/lazyLoad/downloadResponse.js +113 -0
  110. package/build/lazyLoad/downloadResponse.js.map +1 -0
  111. package/build/lazyLoad/generic/generic_crawlPages.js +186 -0
  112. package/build/lazyLoad/generic/generic_crawlPages.js.map +1 -0
  113. package/build/lazyLoad/generic/generic_downloadFiles.js +81 -0
  114. package/build/lazyLoad/generic/generic_downloadFiles.js.map +1 -0
  115. package/build/lazyLoad/generic/generic_extractLinks.js +79 -0
  116. package/build/lazyLoad/generic/generic_extractLinks.js.map +1 -0
  117. package/build/lazyLoad/generic/generic_getScriptTags.js +152 -0
  118. package/build/lazyLoad/generic/generic_getScriptTags.js.map +1 -0
  119. package/build/lazyLoad/generic/generic_importMapDiscovery.js +87 -0
  120. package/build/lazyLoad/generic/generic_importMapDiscovery.js.map +1 -0
  121. package/build/lazyLoad/generic/generic_resolveScope.js +61 -0
  122. package/build/lazyLoad/generic/generic_resolveScope.js.map +1 -0
  123. package/build/lazyLoad/generic/generic_scanAttributesForJs.js +122 -0
  124. package/build/lazyLoad/generic/generic_scanAttributesForJs.js.map +1 -0
  125. package/build/lazyLoad/generic/generic_stringsDiscovery.js +103 -0
  126. package/build/lazyLoad/generic/generic_stringsDiscovery.js.map +1 -0
  127. package/build/lazyLoad/generic/generic_webpackChunkPaths.js +56 -0
  128. package/build/lazyLoad/generic/generic_webpackChunkPaths.js.map +1 -0
  129. package/build/lazyLoad/globals.js +35 -0
  130. package/build/lazyLoad/globals.js.map +1 -1
  131. package/build/lazyLoad/index.js +311 -175
  132. package/build/lazyLoad/index.js.map +1 -1
  133. package/build/lazyLoad/methodFilter.js +2 -0
  134. package/build/lazyLoad/methodFilter.js.map +1 -1
  135. package/build/lazyLoad/next_js/NextJsCrawler.js +39 -14
  136. package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -1
  137. package/build/lazyLoad/next_js/next_GetJSScript.js +3 -3
  138. package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -1
  139. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +4 -4
  140. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -1
  141. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +21 -20
  142. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  143. package/build/lazyLoad/next_js/next_SubsequentRequests.js +100 -99
  144. package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -1
  145. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js +1 -1
  146. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js.map +1 -1
  147. package/build/lazyLoad/next_js/next_buildId.js +2 -2
  148. package/build/lazyLoad/next_js/next_buildId.js.map +1 -1
  149. package/build/lazyLoad/next_js/next_getClientSidePaths.js +2 -2
  150. package/build/lazyLoad/next_js/next_getClientSidePaths.js.map +1 -1
  151. package/build/lazyLoad/next_js/next_parseLayoutJs.js +6 -6
  152. package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -1
  153. package/build/lazyLoad/next_js/next_promiseResolve.js +1 -1
  154. package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -1
  155. package/build/lazyLoad/next_js/next_routerStateForge.js +341 -0
  156. package/build/lazyLoad/next_js/next_routerStateForge.js.map +1 -0
  157. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js +1 -1
  158. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js.map +1 -1
  159. package/build/lazyLoad/next_js/next_serverActionIdScan.js +77 -0
  160. package/build/lazyLoad/next_js/next_serverActionIdScan.js.map +1 -0
  161. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +15 -13
  162. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -1
  163. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js +2 -2
  164. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js.map +1 -1
  165. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +3 -3
  166. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -1
  167. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +2 -2
  168. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -1
  169. package/build/lazyLoad/outputPath.js +92 -0
  170. package/build/lazyLoad/outputPath.js.map +1 -0
  171. package/build/lazyLoad/react/react_followImports.js +15 -5
  172. package/build/lazyLoad/react/react_followImports.js.map +1 -1
  173. package/build/lazyLoad/react/react_getScriptTags.js +11 -6
  174. package/build/lazyLoad/react/react_getScriptTags.js.map +1 -1
  175. package/build/lazyLoad/react/react_sourcemapUrls.js +3 -2
  176. package/build/lazyLoad/react/react_sourcemapUrls.js.map +1 -1
  177. package/build/lazyLoad/react/react_webpackChunkPaths.js +12 -203
  178. package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
  179. package/build/lazyLoad/researchUtils.js +15 -0
  180. package/build/lazyLoad/researchUtils.js.map +1 -0
  181. package/build/lazyLoad/shared/webpackChunkParsers.js +218 -0
  182. package/build/lazyLoad/shared/webpackChunkParsers.js.map +1 -0
  183. package/build/lazyLoad/stagnation/stagnationMonitor.js +63 -0
  184. package/build/lazyLoad/stagnation/stagnationMonitor.js.map +1 -0
  185. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js +1 -0
  186. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js.map +1 -1
  187. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +5 -5
  188. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -1
  189. package/build/lazyLoad/svelte/svelte_getVersionJson.js +2 -2
  190. package/build/lazyLoad/svelte/svelte_getVersionJson.js.map +1 -1
  191. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js +6 -6
  192. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js.map +1 -1
  193. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +2 -2
  194. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
  195. package/build/lazyLoad/techDetect/checkAngularJS.js +1 -1
  196. package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
  197. package/build/lazyLoad/techDetect/checkNuxtJS.js +3 -3
  198. package/build/lazyLoad/techDetect/checkNuxtJS.js.map +1 -1
  199. package/build/lazyLoad/techDetect/checkSvelte.js +0 -1
  200. package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -1
  201. package/build/lazyLoad/techDetect/checkVueJS.js +6 -6
  202. package/build/lazyLoad/techDetect/checkVueJS.js.map +1 -1
  203. package/build/lazyLoad/techDetect/index.js +106 -60
  204. package/build/lazyLoad/techDetect/index.js.map +1 -1
  205. package/build/lazyLoad/vue/vue_RuntimeJs.js +20 -15
  206. package/build/lazyLoad/vue/vue_RuntimeJs.js.map +1 -1
  207. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +10 -5
  208. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
  209. package/build/lazyLoad/vue/vue_discoverJsFiles.js +20 -17
  210. package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
  211. package/build/lazyLoad/vue/vue_getClientSidePaths.js +70 -46
  212. package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
  213. package/build/lazyLoad/vue/vue_jsImports.js +3 -2
  214. package/build/lazyLoad/vue/vue_jsImports.js.map +1 -1
  215. package/build/lazyLoad/vue/vue_pageSrc.js +3 -2
  216. package/build/lazyLoad/vue/vue_pageSrc.js.map +1 -1
  217. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js +6 -5
  218. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js.map +1 -1
  219. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +10 -21
  220. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -1
  221. package/build/lazyLoad/vue/vue_severalJsFilesHome.js +5 -4
  222. package/build/lazyLoad/vue/vue_severalJsFilesHome.js.map +1 -1
  223. package/build/lazyLoad/vue/vue_stringJsFiles.js +28 -25
  224. package/build/lazyLoad/vue/vue_stringJsFiles.js.map +1 -1
  225. package/build/lazyLoad/vue/vue_viteMapDeps.js +8 -2
  226. package/build/lazyLoad/vue/vue_viteMapDeps.js.map +1 -1
  227. package/build/load/index.js +8 -7
  228. package/build/load/index.js.map +1 -1
  229. package/build/map/angular_js/getAngularConnections.js +6 -6
  230. package/build/map/angular_js/getAngularConnections.js.map +1 -1
  231. package/build/map/graphql/resolveGraphql.js +6 -6
  232. package/build/map/graphql/resolveGraphql.js.map +1 -1
  233. package/build/map/index.js +17 -17
  234. package/build/map/index.js.map +1 -1
  235. package/build/map/interactive-mode/commandHandler.js +278 -0
  236. package/build/map/interactive-mode/commandHandler.js.map +1 -0
  237. package/build/map/interactive-mode/commandHelpers.js +189 -0
  238. package/build/map/interactive-mode/commandHelpers.js.map +1 -0
  239. package/build/map/interactive-mode/esqueryGen.js.map +1 -0
  240. package/build/map/interactive-mode/helpMenu.js +11 -0
  241. package/build/map/interactive-mode/helpMenu.js.map +1 -0
  242. package/build/map/interactive-mode/inputPatch.js.map +1 -0
  243. package/build/map/interactive-mode/interactive.js +71 -0
  244. package/build/map/interactive-mode/interactive.js.map +1 -0
  245. package/build/map/interactive-mode/keybindings.js.map +1 -0
  246. package/build/map/interactive-mode/printer.js.map +1 -0
  247. package/build/map/interactive-mode/ui.js.map +1 -0
  248. package/build/map/next_js/getAxiosInstances.js +5 -5
  249. package/build/map/next_js/getAxiosInstances.js.map +1 -1
  250. package/build/map/next_js/getExports.js +4 -4
  251. package/build/map/next_js/getExports.js.map +1 -1
  252. package/build/map/next_js/getFetchInstances.js +10 -10
  253. package/build/map/next_js/getFetchInstances.js.map +1 -1
  254. package/build/map/next_js/getTurbopackConnections.js +8 -8
  255. package/build/map/next_js/getTurbopackConnections.js.map +1 -1
  256. package/build/map/next_js/getWebpackConnections.js +27 -16
  257. package/build/map/next_js/getWebpackConnections.js.map +1 -1
  258. package/build/map/next_js/interactive.js +3 -65
  259. package/build/map/next_js/interactive.js.map +1 -1
  260. package/build/map/next_js/interactive_helpers/commandHandler.js +38 -290
  261. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -1
  262. package/build/map/next_js/interactive_helpers/commandHelpers.js +0 -184
  263. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -1
  264. package/build/map/next_js/interactive_helpers/helpMenu.js +2 -10
  265. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -1
  266. package/build/map/next_js/resolveAxios.js +6 -6
  267. package/build/map/next_js/resolveAxios.js.map +1 -1
  268. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js +4 -4
  269. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js.map +1 -1
  270. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -2
  271. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
  272. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +5 -5
  273. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
  274. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +10 -10
  275. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
  276. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +13 -9
  277. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
  278. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +12 -8
  279. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -1
  280. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +12 -8
  281. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -1
  282. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +11 -11
  283. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
  284. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +16 -16
  285. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
  286. package/build/map/next_js/resolveFetch.js +23 -23
  287. package/build/map/next_js/resolveFetch.js.map +1 -1
  288. package/build/map/next_js/resolveNewRequest.js +10 -10
  289. package/build/map/next_js/resolveNewRequest.js.map +1 -1
  290. package/build/map/next_js/resolveServerActions.js +4 -4
  291. package/build/map/next_js/resolveServerActions.js.map +1 -1
  292. package/build/map/next_js/utils.js +8 -2
  293. package/build/map/next_js/utils.js.map +1 -1
  294. package/build/map/react_js/getReactConnections.js +21 -14
  295. package/build/map/react_js/getReactConnections.js.map +1 -1
  296. package/build/map/svelte_js/interactive.js +3 -54
  297. package/build/map/svelte_js/interactive.js.map +1 -1
  298. package/build/map/vue_js/getViteConnections.js +23 -16
  299. package/build/map/vue_js/getViteConnections.js.map +1 -1
  300. package/build/map/vue_js/interactive.js +3 -63
  301. package/build/map/vue_js/interactive.js.map +1 -1
  302. package/build/map/vue_js/interactive_helpers/commandHandler.js +34 -283
  303. package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -1
  304. package/build/map/vue_js/interactive_helpers/helpMenu.js +2 -10
  305. package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -1
  306. package/build/map/vue_js/taint_utils.js +1 -1
  307. package/build/map/vue_js/taint_utils.js.map +1 -1
  308. package/build/map/vue_js/vue_resolveFetch.js +12 -12
  309. package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
  310. package/build/map/vue_js/vue_resolveHttpClient.js +18 -18
  311. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  312. package/build/map/vue_js/vue_resolveXhr.js +11 -11
  313. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  314. package/build/mcp/chatOneShot.js +7 -7
  315. package/build/mcp/chatOneShot.js.map +1 -1
  316. package/build/mcp/claudeCodeCreds.js +5 -5
  317. package/build/mcp/claudeCodeCreds.js.map +1 -1
  318. package/build/mcp/cli.js +36 -35
  319. package/build/mcp/cli.js.map +1 -1
  320. package/build/mcp/config.js +4 -4
  321. package/build/mcp/config.js.map +1 -1
  322. package/build/mcp/index.js +7 -7
  323. package/build/mcp/index.js.map +1 -1
  324. package/build/mcp/mcpServer.js +3 -2
  325. package/build/mcp/mcpServer.js.map +1 -1
  326. package/build/mcp/skills.js +1 -0
  327. package/build/mcp/skills.js.map +1 -1
  328. package/build/mcp/tools.js +5 -4
  329. package/build/mcp/tools.js.map +1 -1
  330. package/build/proxy/checkFeasibility.js +8 -4
  331. package/build/proxy/checkFeasibility.js.map +1 -1
  332. package/build/proxy/checkFireWallBlocking.js +23 -13
  333. package/build/proxy/checkFireWallBlocking.js.map +1 -1
  334. package/build/proxy/detectBlockedResponse.js +205 -0
  335. package/build/proxy/detectBlockedResponse.js.map +1 -0
  336. package/build/proxy/genReq.js +434 -127
  337. package/build/proxy/genReq.js.map +1 -1
  338. package/build/proxy/index.js +3 -3
  339. package/build/proxy/index.js.map +1 -1
  340. package/build/proxy/oxylabsFallback.js +110 -0
  341. package/build/proxy/oxylabsFallback.js.map +1 -0
  342. package/build/proxy/proxyFeasibilityRequest.js +11 -9
  343. package/build/proxy/proxyFeasibilityRequest.js.map +1 -1
  344. package/build/refactor/index.js +83 -79
  345. package/build/refactor/index.js.map +1 -1
  346. package/build/refactor/next/index.js +69 -26
  347. package/build/refactor/next/index.js.map +1 -1
  348. package/build/refactor/next/transform.js +11 -4
  349. package/build/refactor/next/transform.js.map +1 -1
  350. package/build/refactor/next/validator.js +7 -7
  351. package/build/refactor/next/validator.js.map +1 -1
  352. package/build/refactor/react/index.js +13 -13
  353. package/build/refactor/react/index.js.map +1 -1
  354. package/build/refactor/react/validator.js +7 -7
  355. package/build/refactor/react/validator.js.map +1 -1
  356. package/build/refactor/react-vite/index.js +3 -3
  357. package/build/refactor/react-vite/index.js.map +1 -1
  358. package/build/refactor/remote/hf-client.js +1 -0
  359. package/build/refactor/remote/hf-client.js.map +1 -1
  360. package/build/refactor/remote/version-detect.js +12 -12
  361. package/build/refactor/remote/version-detect.js.map +1 -1
  362. package/build/refactor/vue/index.js +6 -6
  363. package/build/refactor/vue/index.js.map +1 -1
  364. package/build/refactor/vue/vite.js +6 -6
  365. package/build/refactor/vue/vite.js.map +1 -1
  366. package/build/report/index.js +30 -8
  367. package/build/report/index.js.map +1 -1
  368. package/build/report/swaggerJacker.js +63 -0
  369. package/build/report/swaggerJacker.js.map +1 -0
  370. package/build/report/utility/genHtml.js +7 -7
  371. package/build/report/utility/genHtml.js.map +1 -1
  372. package/build/report/utility/populateDb/populateAnalysisFindings.js +2 -2
  373. package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -1
  374. package/build/report/utility/populateDb/populateEndpoints.js +3 -3
  375. package/build/report/utility/populateDb/populateEndpoints.js.map +1 -1
  376. package/build/report/utility/populateDb/populateMappedJson.js +2 -2
  377. package/build/report/utility/populateDb/populateMappedJson.js.map +1 -1
  378. package/build/report/utility/populateDb/populateMappedOpenapi.js +3 -3
  379. package/build/report/utility/populateDb/populateMappedOpenapi.js.map +1 -1
  380. package/build/run/bundler-detect.js +45 -9
  381. package/build/run/bundler-detect.js.map +1 -1
  382. package/build/run/cancellableStep.js +27 -0
  383. package/build/run/cancellableStep.js.map +1 -0
  384. package/build/run/dashboard/dashboardHtml.js +150 -0
  385. package/build/run/dashboard/dashboardHtml.js.map +1 -0
  386. package/build/run/dashboard/fsBrowser.js +43 -0
  387. package/build/run/dashboard/fsBrowser.js.map +1 -0
  388. package/build/run/dashboard/server.js +123 -0
  389. package/build/run/dashboard/server.js.map +1 -0
  390. package/build/run/dashboard/state.js +97 -0
  391. package/build/run/dashboard/state.js.map +1 -0
  392. package/build/run/index.js +239 -204
  393. package/build/run/index.js.map +1 -1
  394. package/build/run/interruptHandler.js +18 -0
  395. package/build/run/interruptHandler.js.map +1 -1
  396. package/build/run/outputDirectory.js +377 -0
  397. package/build/run/outputDirectory.js.map +1 -0
  398. package/build/sourcemaps/index.js +116 -29
  399. package/build/sourcemaps/index.js.map +1 -1
  400. package/build/strings/index.js +38 -28
  401. package/build/strings/index.js.map +1 -1
  402. package/build/strings/openapi.js +4 -4
  403. package/build/strings/openapi.js.map +1 -1
  404. package/build/strings/permutate.js +4 -4
  405. package/build/strings/permutate.js.map +1 -1
  406. package/build/strings/secrets.js +1 -0
  407. package/build/strings/secrets.js.map +1 -1
  408. package/build/strings/trufflehog.js +66 -19
  409. package/build/strings/trufflehog.js.map +1 -1
  410. package/build/strings/trufflehogConfig.js +36 -0
  411. package/build/strings/trufflehogConfig.js.map +1 -0
  412. package/build/strings/trufflehogDownload.js +115 -0
  413. package/build/strings/trufflehogDownload.js.map +1 -0
  414. package/build/utility/ai.js +33 -4
  415. package/build/utility/ai.js.map +1 -1
  416. package/build/utility/banner.js +4 -3
  417. package/build/utility/banner.js.map +1 -1
  418. package/build/utility/configureSandbox.js +2 -2
  419. package/build/utility/configureSandbox.js.map +1 -1
  420. package/build/utility/downloadProgress.js +99 -0
  421. package/build/utility/downloadProgress.js.map +1 -0
  422. package/build/utility/globals.js +19 -11
  423. package/build/utility/globals.js.map +1 -1
  424. package/build/utility/heap.js +2 -1
  425. package/build/utility/heap.js.map +1 -1
  426. package/build/utility/makeReq.js +490 -257
  427. package/build/utility/makeReq.js.map +1 -1
  428. package/build/utility/openapiGenerator.js +2 -2
  429. package/build/utility/openapiGenerator.js.map +1 -1
  430. package/build/utility/printMsg.js +53 -0
  431. package/build/utility/printMsg.js.map +1 -0
  432. package/build/utility/progressLog.js +68 -7
  433. package/build/utility/progressLog.js.map +1 -1
  434. package/build/utility/resolvePath.js +2 -1
  435. package/build/utility/resolvePath.js.map +1 -1
  436. package/build/utility/ruleVersionMap.js +73 -0
  437. package/build/utility/ruleVersionMap.js.map +1 -0
  438. package/build/utility/targetInputs.js +177 -0
  439. package/build/utility/targetInputs.js.map +1 -0
  440. package/build/utility/urlUtils.js +37 -1
  441. package/build/utility/urlUtils.js.map +1 -1
  442. package/config.dist.yaml +251 -0
  443. package/contributing/testing.md +106 -0
  444. package/eslint.config.js +24 -0
  445. package/package.json +22 -5
  446. package/scripts/exploit-smoke-test.js +82 -0
  447. package/scripts/framework-detect-smoke-test.js +64 -0
  448. package/scripts/postinstall-completion.mjs +40 -0
  449. package/scripts/smoke-test.js +12 -0
  450. package/build/lazyLoad/downloadLoadedJsUtil.js +0 -98
  451. package/build/lazyLoad/downloadLoadedJsUtil.js.map +0 -1
  452. package/build/map/next_js/interactive_helpers/esqueryGen.js.map +0 -1
  453. package/build/map/next_js/interactive_helpers/inputPatch.js.map +0 -1
  454. package/build/map/next_js/interactive_helpers/keybindings.js.map +0 -1
  455. package/build/map/next_js/interactive_helpers/printer.js.map +0 -1
  456. package/build/map/next_js/interactive_helpers/ui.js.map +0 -1
  457. /package/build/map/{next_js/interactive_helpers → interactive-mode}/esqueryGen.js +0 -0
  458. /package/build/map/{next_js/interactive_helpers → interactive-mode}/inputPatch.js +0 -0
  459. /package/build/map/{next_js/interactive_helpers → interactive-mode}/keybindings.js +0 -0
  460. /package/build/map/{next_js/interactive_helpers → interactive-mode}/printer.js +0 -0
  461. /package/build/map/{next_js/interactive_helpers → interactive-mode}/ui.js +0 -0
@@ -1,292 +1,38 @@
1
- import chalk from "chalk";
2
- const COMMANDS = [
3
- "lazyload",
4
- "endpoints",
5
- "strings",
6
- "proxy",
7
- "map",
8
- "refactor",
9
- "analyze",
10
- "report",
11
- "run",
12
- "load",
13
- "fingerprint",
14
- "mcp",
15
- "cs-mast",
16
- "sourcemaps",
17
- "completion",
18
- ];
19
- const FLAGS = {
20
- lazyload: [
21
- "-u",
22
- "--url",
23
- "-o",
24
- "--output",
25
- "--strict-scope",
26
- "-s",
27
- "--scope",
28
- "-t",
29
- "--threads",
30
- "--subsequent-requests",
31
- "--urls-file",
32
- "--proxy-config",
33
- "--ignore-proxy-env",
34
- "--cache-file",
35
- "--disable-cache",
36
- "--cache-only",
37
- "-y",
38
- "--yes",
39
- "--timeout",
40
- "-k",
41
- "--insecure",
42
- "--no-sandbox",
43
- "--build-id",
44
- "--sourcemap-dir",
45
- "--research",
46
- "--research-output",
47
- "--max-iterations",
48
- "--max-js-size",
49
- "--lazyload-timeout",
50
- "--max-pages",
51
- "--include-methods",
52
- "--exclude-methods",
53
- "--list-methods",
54
- ],
55
- endpoints: [
56
- "-u",
57
- "--url",
58
- "-d",
59
- "--directory",
60
- "-o",
61
- "--output",
62
- "--output-format",
63
- "-t",
64
- "--tech",
65
- "-l",
66
- "--list",
67
- "--mapped-json",
68
- ],
69
- strings: [
70
- "-d",
71
- "--directory",
72
- "-o",
73
- "--output",
74
- "-e",
75
- "--extract-urls",
76
- "--extracted-url-path",
77
- "-p",
78
- "--permutate",
79
- "--openapi",
80
- "-s",
81
- "--scan-secrets",
82
- "--trufflehog",
83
- ],
84
- proxy: [
85
- "-i",
86
- "--init",
87
- "-d",
88
- "--destroy",
89
- "--destroy-all",
90
- "-r",
91
- "--region",
92
- "--aws-access-key",
93
- "--aws-secret-key",
94
- "-c",
95
- "--config",
96
- "-l",
97
- "--list",
98
- "--feasibility",
99
- "--feasibility-url",
100
- "--proxy-method",
101
- "--proxy",
102
- "--oxylabs-username",
103
- "--oxylabs-password",
104
- "--oxylabs-country",
105
- "--oxylabs-city",
106
- "--oxylabs-session-id",
107
- ],
108
- map: [
109
- "-d",
110
- "--directory",
111
- "-t",
112
- "--tech",
113
- "-l",
114
- "--list",
115
- "-o",
116
- "--output",
117
- "-f",
118
- "--format",
119
- "-i",
120
- "--interactive",
121
- "-c",
122
- "--command",
123
- "--ai",
124
- "--ai-threads",
125
- "--ai-provider",
126
- "--ai-endpoint",
127
- "--openai-api-key",
128
- "--model",
129
- "--openapi",
130
- "--openapi-output",
131
- "--openapi-chunk-tag",
132
- "--no-graphql",
133
- "--ngql",
134
- "--max-recursion-depth",
135
- "--max-heap",
136
- ],
137
- refactor: [
138
- "-m",
139
- "--mapped-json",
140
- "-o",
141
- "--output",
142
- "-t",
143
- "--tech",
144
- "-l",
145
- "--list",
146
- "--collisions",
147
- "--sq",
148
- "--signature-quality",
149
- "--refresh-cache",
150
- "--skip-cache-checks",
151
- "--no-remote",
152
- "--remote-collisions",
153
- "--scat",
154
- "--detect-version",
155
- "--detect-version-config",
156
- "--detect-version-dynamic-threshold",
157
- "--detect-version-dynamic-conf-purge",
158
- ],
159
- analyze: [
160
- "-r",
161
- "--rules",
162
- "-m",
163
- "--mapped-json",
164
- "-t",
165
- "--tech",
166
- "--openapi",
167
- "-l",
168
- "--list",
169
- "--validate",
170
- "-o",
171
- "--output",
172
- ],
173
- report: [
174
- "-s",
175
- "--sqlite-db",
176
- "-m",
177
- "--mapped-json",
178
- "-a",
179
- "--analyze-json",
180
- "-e",
181
- "--endpoints-json",
182
- "--map-openapi",
183
- "--mapped-openapi-json",
184
- "-o",
185
- "--output",
186
- ],
187
- run: [
188
- "-u",
189
- "--url",
190
- "-r",
191
- "--rules",
192
- "-c",
193
- "--command",
194
- "-o",
195
- "--output",
196
- "--strict-scope",
197
- "-s",
198
- "--scope",
199
- "-t",
200
- "--threads",
201
- "--proxy-config",
202
- "--ignore-proxy-env",
203
- "--cache-file",
204
- "--disable-cache",
205
- "--cache-only",
206
- "-y",
207
- "--yes",
208
- "--secrets",
209
- "--trufflehog",
210
- "--ai",
211
- "--ai-threads",
212
- "--ai-provider",
213
- "--ai-endpoint",
214
- "--openai-api-key",
215
- "--model",
216
- "--map-openapi-chunk-tag",
217
- "--no-graphql",
218
- "--ngql",
219
- "--timeout",
220
- "-k",
221
- "--insecure",
222
- "--no-sandbox",
223
- "--sourcemap-dir",
224
- "--research",
225
- "--research-output",
226
- "--max-iterations",
227
- "--max-js-size",
228
- "--lazyload-timeout",
229
- "--max-heap",
230
- "--max-pages",
231
- "--include-methods",
232
- "--exclude-methods",
233
- "--list-methods",
234
- "--cs-mast-tech-detect-threshold",
235
- "--disable-refactor",
236
- ],
237
- load: ["-c", "--caido", "-u", "--url", "--cache-file"],
238
- fingerprint: [
239
- "-u",
240
- "--url",
241
- "-o",
242
- "--output",
243
- "-f",
244
- "--format",
245
- "-t",
246
- "--threads",
247
- "--timeout",
248
- "-k",
249
- "--insecure",
250
- "--no-sandbox",
251
- ],
252
- mcp: [
253
- "--cli",
254
- "--server",
255
- "-c",
256
- "--chat",
257
- "--config",
258
- "--api-key",
259
- "--model",
260
- "--provider",
261
- "--no-refresh-claude-creds",
262
- "--claude-client-id",
263
- ],
264
- "cs-mast": [
265
- "-o",
266
- "--output",
267
- "--ct",
268
- "--collision-table",
269
- "--min-collisions",
270
- "--co",
271
- "--collision-output",
272
- "--cf",
273
- "--collision-format",
274
- "--scat",
275
- "--sinc",
276
- "--all-scat-permutations",
277
- "--perm-output",
278
- "--perm-concurrency",
279
- ],
280
- sourcemaps: ["-i", "--input", "-o", "--output"],
281
- completion: ["bash", "zsh", "fish"],
282
- };
283
- function generateBashCompletion() {
284
- const cmdList = COMMANDS.join(" ");
285
- const caseBranches = Object.entries(FLAGS)
286
- .map(([cmd, flags]) => ` ${cmd})\n opts="${flags.join(" ")}"\n ;;`)
287
- .join("\n");
1
+ import fs from "fs";
2
+ import os from "os";
3
+ import path from "path";
4
+ import { printMsg, MSG } from "../utility/printMsg.js";
5
+ import { buildProgram } from "../cliProgram.js";
6
+ import { buildCommandTree } from "./introspect.js";
7
+ function bashLeafOpts(node) {
8
+ return [...node.options.flatMap((o) => o.flags), ...node.argumentChoices].join(" ");
9
+ }
10
+ // Recursively emits nested `case` blocks so multi-level subcommands (e.g. `proxy aws`) get their
11
+ // own flags completed, not just the parent's child-name list. `wordIndex` is the COMP_WORDS index
12
+ // this node's name occupies (1 for top-level commands, 2 for their children, and so on).
13
+ function generateBashCaseBranch(node, wordIndex) {
14
+ const indent = " ".repeat(wordIndex + 1);
15
+ if (node.subcommands.length === 0) {
16
+ return `${indent}${node.name})
17
+ ${indent} opts="${bashLeafOpts(node)}"
18
+ ${indent} ;;`;
19
+ }
20
+ const childBranches = node.subcommands.map((child) => generateBashCaseBranch(child, wordIndex + 1)).join("\n");
21
+ const childNames = node.subcommands.map((c) => c.name).join(" ");
22
+ return `${indent}${node.name})
23
+ ${indent} case "\${words[${wordIndex + 1}]:-}" in
24
+ ${childBranches}
25
+ ${indent} *)
26
+ ${indent} opts="${childNames}"
27
+ ${indent} ;;
28
+ ${indent} esac
29
+ ${indent} ;;`;
30
+ }
31
+ function generateBashCompletion(tree) {
32
+ const cmdList = tree.map((n) => n.name).join(" ");
33
+ const caseBranches = tree.map((node) => generateBashCaseBranch(node, 1)).join("\n");
288
34
  return `# js-recon bash completion
289
- # Add to ~/.bashrc: eval "$(js-recon completion bash)"
35
+ # Installed automatically by: js-recon completion bash
290
36
  _js_recon_completion() {
291
37
  local cur prev words cword opts
292
38
  COMPREPLY=()
@@ -300,9 +46,8 @@ _js_recon_completion() {
300
46
  return 0
301
47
  fi
302
48
 
303
- local cmd="\${words[1]}"
304
49
  opts=""
305
- case "\${cmd}" in
50
+ case "\${words[1]}" in
306
51
  ${caseBranches}
307
52
  esac
308
53
 
@@ -312,34 +57,88 @@ ${caseBranches}
312
57
  complete -F _js_recon_completion js-recon
313
58
  `;
314
59
  }
315
- function generateZshCompletion() {
316
- const commandDescriptions = [
317
- "'lazyload:Run lazy load module'",
318
- "'endpoints:Extract client-side endpoints'",
319
- "'strings:Extract strings from JS files'",
320
- "'proxy:Manage proxy configuration (AWS API Gateway IP rotation, SOCKS/HTTP, Oxylabs)'",
321
- "'map:Map all the functions'",
322
- "'refactor:Refactor the code'",
323
- "'analyze:Analyze the code'",
324
- "'report:Generate a report'",
325
- "'run:Run all modules'",
326
- "'load:Populate response cache from a Caido/Burp request history export'",
327
- "'fingerprint:Detect front-end frameworks across one or more URLs'",
328
- "'mcp:AI-powered CLI / one-shot chat / MCP server'",
329
- "'cs-mast:Compute CS-MAST hashes for downloaded JS files'",
330
- "'sourcemaps:Extract source files from .map sourcemap file(s)'",
331
- "'completion:Generate shell completion scripts'",
332
- ].join("\n ");
333
- const caseBranches = Object.entries(FLAGS)
334
- .map(([cmd, flags]) => {
335
- const flagArgs = flags.map((f) => `'${f}'`).join(" ");
336
- return ` (${cmd})\n _arguments '*: :(${flagArgs})'\n ;;`;
60
+ // zsh escaping: backslash first, then compsys metacharacters, then the shell-level single-quote
61
+ // trick last (since every spec string here is wrapped in '...').
62
+ function zshBracketDesc(desc) {
63
+ return desc.replace(/\\/g, "\\\\").replace(/\]/g, "\\]").replace(/\[/g, "\\[").replace(/'/g, "'\\''");
64
+ }
65
+ // Used inside `_describe` `name:description` arrays, where `:` is the field delimiter.
66
+ function zshDescribeDesc(desc) {
67
+ return desc.replace(/\\/g, "\\\\").replace(/:/g, "\\:").replace(/'/g, "'\\''");
68
+ }
69
+ function zshOptionSpec(option) {
70
+ const desc = zshBracketDesc(option.description);
71
+ const short = option.flags.find((f) => f.length === 2 && f.startsWith("-") && !f.startsWith("--"));
72
+ const long = option.flags.find((f) => f.startsWith("--"));
73
+ if (short && long)
74
+ return `'(${short} ${long})'{${short},${long}}'[${desc}]'`;
75
+ if (long)
76
+ return `'${long}[${desc}]'`;
77
+ if (short)
78
+ return `'${short}[${desc}]'`;
79
+ return "";
80
+ }
81
+ function zshDescribeEntry(node) {
82
+ return `'${node.name}:${zshDescribeDesc(node.description)}'`;
83
+ }
84
+ function zshLeafArguments(node) {
85
+ const parts = [];
86
+ if (node.argumentChoices.length > 0) {
87
+ parts.push(`'1: :(${node.argumentChoices.join(" ")})'`);
88
+ }
89
+ parts.push(...node.options.map(zshOptionSpec).filter(Boolean));
90
+ if (parts.length === 0)
91
+ return ":";
92
+ return `_arguments ${parts.join(" ")}`;
93
+ }
94
+ // Recursively emits a nested `_arguments -C` + `case $state` block for a level of subcommands.
95
+ // Reusing the generic `cmd`/`args` state labels at every nesting level is safe here because each
96
+ // `_arguments -C` call is evaluated strictly before the `case $state` that reads its result — by
97
+ // the time a nested level's `$state` is inspected, the outer level's value is no longer needed.
98
+ function zshSubcommandBlock(nodes, describeTag) {
99
+ const entries = nodes.map(zshDescribeEntry).join("\n ");
100
+ const branches = nodes
101
+ .map((node) => {
102
+ const body = node.subcommands.length > 0 ? zshSubcommandBlock(node.subcommands, node.name) : zshLeafArguments(node);
103
+ return ` (${node.name})
104
+ ${body}
105
+ ;;`;
106
+ })
107
+ .join("\n");
108
+ return `_arguments -C \\
109
+ '1: :->cmd' \\
110
+ '*::arg:->args'
111
+
112
+ case \$state in
113
+ cmd)
114
+ local -a items
115
+ items=(
116
+ ${entries}
117
+ )
118
+ _describe -t items '${describeTag}' items
119
+ ;;
120
+ args)
121
+ case \$line[1] in
122
+ ${branches}
123
+ esac
124
+ ;;
125
+ esac`;
126
+ }
127
+ function generateZshCompletion(tree) {
128
+ const commandDescriptions = tree.map(zshDescribeEntry).join("\n ");
129
+ const caseBranches = tree
130
+ .map((node) => {
131
+ const body = node.subcommands.length > 0
132
+ ? zshSubcommandBlock(node.subcommands, `${node.name} subcommand`)
133
+ : zshLeafArguments(node);
134
+ return ` (${node.name})
135
+ ${body}
136
+ ;;`;
337
137
  })
338
138
  .join("\n");
339
139
  return `#compdef js-recon
340
140
  # js-recon zsh completion
341
- # Add to ~/.zshrc: eval "$(js-recon completion zsh)"
342
- # Or: js-recon completion zsh > "\${fpath[1]}/_js-recon"
141
+ # Installed automatically by: js-recon completion zsh
343
142
 
344
143
  _js_recon() {
345
144
  local state line
@@ -370,23 +169,50 @@ ${caseBranches}
370
169
  _js_recon "\$@"
371
170
  `;
372
171
  }
373
- function generateFishCompletion() {
374
- const cmdCompletions = COMMANDS.map((cmd) => `complete -c js-recon -f -n '__fish_use_subcommand' -a ${cmd}`).join("\n");
375
- const flagCompletions = Object.entries(FLAGS)
376
- .flatMap(([cmd, flags]) => flags.map((flag) => {
377
- if (flag.startsWith("--")) {
378
- return `complete -c js-recon -n '__fish_seen_subcommand_from ${cmd}' -l ${flag.slice(2)}`;
172
+ function fishDesc(desc) {
173
+ return desc.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
174
+ }
175
+ function fishConditionForPath(namePath) {
176
+ return namePath.map((name) => `__fish_seen_subcommand_from ${name}`).join("; and ");
177
+ }
178
+ // Recursively emits `complete` lines for a node's own flags/argument choices (gated on the full
179
+ // name path having been seen so far) and, for each child, both a name-completion at this level
180
+ // and a recursive call so the child's own flags are completed too (e.g. `proxy aws --<tab>`).
181
+ function generateFishNode(node, parentPath) {
182
+ const namePath = [...parentPath, node.name];
183
+ const cond = fishConditionForPath(namePath);
184
+ const lines = [];
185
+ for (const option of node.options) {
186
+ const short = option.flags.find((f) => f.length === 2 && f.startsWith("-") && !f.startsWith("--"));
187
+ const long = option.flags.find((f) => f.startsWith("--"));
188
+ const desc = fishDesc(option.description);
189
+ if (short && long) {
190
+ lines.push(`complete -c js-recon -n '${cond}' -s ${short.slice(1)} -l ${long.slice(2)} -d '${desc}'`);
191
+ }
192
+ else if (long) {
193
+ lines.push(`complete -c js-recon -n '${cond}' -l ${long.slice(2)} -d '${desc}'`);
379
194
  }
380
- else if (flag.startsWith("-") && flag.length === 2) {
381
- return `complete -c js-recon -n '__fish_seen_subcommand_from ${cmd}' -s ${flag.slice(1)}`;
195
+ else if (short) {
196
+ lines.push(`complete -c js-recon -n '${cond}' -s ${short.slice(1)} -d '${desc}'`);
382
197
  }
383
- // positional (e.g. shell names for 'completion' subcommand)
384
- return `complete -c js-recon -n '__fish_seen_subcommand_from ${cmd}' -a ${flag}`;
385
- }))
198
+ }
199
+ if (node.argumentChoices.length > 0) {
200
+ lines.push(`complete -c js-recon -n '${cond}' -a '${node.argumentChoices.join(" ")}'`);
201
+ }
202
+ for (const child of node.subcommands) {
203
+ lines.push(`complete -c js-recon -f -n '${cond}' -a ${child.name} -d '${fishDesc(child.description)}'`);
204
+ lines.push(...generateFishNode(child, namePath));
205
+ }
206
+ return lines;
207
+ }
208
+ function generateFishCompletion(tree) {
209
+ const cmdCompletions = tree
210
+ .map((node) => `complete -c js-recon -f -n '__fish_use_subcommand' -a ${node.name} -d '${fishDesc(node.description)}'`)
386
211
  .join("\n");
212
+ const flagCompletions = tree.flatMap((node) => generateFishNode(node, [])).join("\n");
387
213
  return `# js-recon fish completion
388
- # Save to: ~/.config/fish/completions/js-recon.fish
389
- # Or run: js-recon completion fish > ~/.config/fish/completions/js-recon.fish
214
+ # Installed automatically by: js-recon completion fish
215
+ # (written to ~/.config/fish/completions/js-recon.fish, which fish auto-loads)
390
216
 
391
217
  function __fish_use_subcommand
392
218
  set -l cmd (commandline -poc)
@@ -415,24 +241,104 @@ ${cmdCompletions}
415
241
  ${flagCompletions}
416
242
  `;
417
243
  }
418
- export default function completion(shell) {
419
- if (!shell) {
420
- console.error(chalk.red("[!] Shell type required. Usage: js-recon completion <bash|zsh|fish>"));
421
- process.exit(1);
244
+ const RC_MARKER = "# JS Recon shell completion";
245
+ function getCompletionDir() {
246
+ return path.join(os.homedir(), ".js-recon", "completion");
247
+ }
248
+ function getFishCompletionsDir() {
249
+ return path.join(os.homedir(), ".config", "fish", "completions");
250
+ }
251
+ // Path each shell's full generated script gets written to. Fish uses its own
252
+ // auto-loaded completions dir instead of ~/.js-recon, so it needs no rc-file entry.
253
+ function getInstalledScriptPath(shell) {
254
+ switch (shell) {
255
+ case "bash":
256
+ return path.join(getCompletionDir(), "js-recon.bash");
257
+ case "zsh":
258
+ return path.join(getCompletionDir(), "_js-recon");
259
+ case "fish":
260
+ return path.join(getFishCompletionsDir(), "js-recon.fish");
261
+ default:
262
+ throw new Error(`Unknown shell: ${shell}`);
422
263
  }
423
- switch (shell.toLowerCase()) {
264
+ }
265
+ function getRcFilePath(shell) {
266
+ return path.join(os.homedir(), shell === "bash" ? ".bashrc" : ".zshrc");
267
+ }
268
+ // Small snippet printed for `--rc-file` — this is what actually goes in the user's rc file
269
+ // (via `eval "$(js-recon completion <shell> --rc-file)"`), pointing at the full script on disk.
270
+ function generateRcFileLoader(shell) {
271
+ const importantHeader = `# IMPORTANT: the contents of this command are expected to be present in
272
+ # the shell's rc file, invoked as \`eval "$(js-recon completion ${shell} --rc-file)"\`.
273
+ # Run \`js-recon completion ${shell}\` to (re)install.`;
274
+ if (shell === "bash") {
275
+ return `${importantHeader}
276
+ if [ -f "$HOME/.js-recon/completion/js-recon.bash" ]; then
277
+ source "$HOME/.js-recon/completion/js-recon.bash"
278
+ fi
279
+ `;
280
+ }
281
+ return `${importantHeader}
282
+ fpath=("$HOME/.js-recon/completion" $fpath)
283
+ autoload -Uz compinit
284
+ compinit
285
+ `;
286
+ }
287
+ function generateCompletionScript(shell) {
288
+ const tree = buildCommandTree(buildProgram());
289
+ switch (shell) {
424
290
  case "bash":
425
- process.stdout.write(generateBashCompletion());
426
- break;
291
+ return generateBashCompletion(tree);
427
292
  case "zsh":
428
- process.stdout.write(generateZshCompletion());
429
- break;
293
+ return generateZshCompletion(tree);
430
294
  case "fish":
431
- process.stdout.write(generateFishCompletion());
432
- break;
295
+ return generateFishCompletion(tree);
433
296
  default:
434
- console.error(chalk.red(`[!] Unknown shell: "${shell}". Supported shells: bash, zsh, fish`));
297
+ throw new Error(`Unknown shell: ${shell}`);
298
+ }
299
+ }
300
+ // Writes the full script to disk and, for bash/zsh, wires a tiny loader entry into the
301
+ // user's rc file (idempotent — checks RC_MARKER before appending).
302
+ function installCompletion(shell) {
303
+ const scriptPath = getInstalledScriptPath(shell);
304
+ fs.mkdirSync(path.dirname(scriptPath), { recursive: true });
305
+ fs.writeFileSync(scriptPath, generateCompletionScript(shell));
306
+ if (shell === "fish") {
307
+ printMsg(MSG.Run, `[+] Installed fish completion to ${scriptPath}`);
308
+ printMsg(MSG.Run, "[+] Fish auto-loads this — no further action needed.");
309
+ return;
310
+ }
311
+ const rcPath = getRcFilePath(shell);
312
+ const rcContent = fs.existsSync(rcPath) ? fs.readFileSync(rcPath, "utf8") : "";
313
+ if (rcContent.includes(RC_MARKER)) {
314
+ printMsg(MSG.Run, `[+] Installed ${shell} completion to ${scriptPath}`);
315
+ printMsg(MSG.Run, `[+] ${rcPath} already wired for js-recon completion.`);
316
+ return;
317
+ }
318
+ const entry = `\n${RC_MARKER}\neval "$(js-recon completion ${shell} --rc-file)"\n`;
319
+ fs.appendFileSync(rcPath, entry);
320
+ printMsg(MSG.Run, `[+] Installed ${shell} completion to ${scriptPath}`);
321
+ printMsg(MSG.Run, `[+] Added completion loader to ${rcPath}`);
322
+ printMsg(MSG.Run, `[+] Restart your shell or run: source ${rcPath}`);
323
+ }
324
+ export default function completion(shell, rcFile) {
325
+ if (!shell) {
326
+ printMsg(MSG.Err, "[!] Shell type required. Usage: js-recon completion <bash|zsh|fish>");
327
+ process.exit(1);
328
+ }
329
+ const normalizedShell = shell.toLowerCase();
330
+ if (normalizedShell !== "bash" && normalizedShell !== "zsh" && normalizedShell !== "fish") {
331
+ printMsg(MSG.Err, `[!] Unknown shell: "${shell}". Supported shells: bash, zsh, fish`);
332
+ process.exit(1);
333
+ }
334
+ if (rcFile) {
335
+ if (normalizedShell === "fish") {
336
+ printMsg(MSG.Err, '[!] --rc-file is not applicable to fish; fish auto-loads completions from "~/.config/fish/completions/".');
435
337
  process.exit(1);
338
+ }
339
+ process.stdout.write(generateRcFileLoader(normalizedShell));
340
+ return;
436
341
  }
342
+ installCompletion(normalizedShell);
437
343
  }
438
344
  //# sourceMappingURL=index.js.map