@js-recon/js-recon 1.4.4 → 2.0.1-alpha.2

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 (440) hide show
  1. package/.claude-sync/sync.sh +1 -1
  2. package/.github/dependabot.yml +50 -0
  3. package/.github/workflows/build-and-prettify.yaml +49 -19
  4. package/.github/workflows/codeql.yml +33 -0
  5. package/.github/workflows/exploit-smoke-test.yaml +160 -0
  6. package/.github/workflows/framework-detection-smoke-test.yaml +135 -0
  7. package/.github/workflows/plumber.yml +20 -0
  8. package/.github/workflows/promote-js-recon.yml +5 -3
  9. package/.github/workflows/publish-js-recon.yml +31 -2
  10. package/.github/workflows/rules-smoke-test.yaml +13 -5
  11. package/.nvmrc +1 -0
  12. package/.plumber.yaml +151 -0
  13. package/CHANGELOG.md +55 -0
  14. package/CONTRIBUTING.md +32 -0
  15. package/Dockerfile +1 -0
  16. package/README.md +3 -2
  17. package/SECURITY.md +1 -1
  18. package/build/analyze/engine/astEngine.js +10 -9
  19. package/build/analyze/engine/astEngine.js.map +1 -1
  20. package/build/analyze/engine/csMastSEngine.js +6 -6
  21. package/build/analyze/engine/csMastSEngine.js.map +1 -1
  22. package/build/analyze/engine/index.js +1 -1
  23. package/build/analyze/engine/index.js.map +1 -1
  24. package/build/analyze/engine/requestEngine.js +6 -6
  25. package/build/analyze/engine/requestEngine.js.map +1 -1
  26. package/build/analyze/helpers/determineCompatibleVersion.js +70 -0
  27. package/build/analyze/helpers/determineCompatibleVersion.js.map +1 -0
  28. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +9 -3
  29. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -1
  30. package/build/analyze/helpers/initRules.js +9 -9
  31. package/build/analyze/helpers/initRules.js.map +1 -1
  32. package/build/analyze/helpers/outputHelper.js +3 -3
  33. package/build/analyze/helpers/outputHelper.js.map +1 -1
  34. package/build/analyze/helpers/schemas.js +1 -0
  35. package/build/analyze/helpers/schemas.js.map +1 -1
  36. package/build/analyze/helpers/validate.js +9 -5
  37. package/build/analyze/helpers/validate.js.map +1 -1
  38. package/build/analyze/index.js +26 -16
  39. package/build/analyze/index.js.map +1 -1
  40. package/build/cliProgram.js +733 -0
  41. package/build/cliProgram.js.map +1 -0
  42. package/build/completion/index.js +247 -382
  43. package/build/completion/index.js.map +1 -1
  44. package/build/completion/introspect.js +17 -0
  45. package/build/completion/introspect.js.map +1 -0
  46. package/build/config/applicationConfig.js +3 -2
  47. package/build/config/applicationConfig.js.map +1 -1
  48. package/build/cs_mast/index.js +18 -17
  49. package/build/cs_mast/index.js.map +1 -1
  50. package/build/endpoints/gen_report/gen_json.js +2 -2
  51. package/build/endpoints/gen_report/gen_json.js.map +1 -1
  52. package/build/endpoints/gen_report/utility/iterate_n_store.js +1 -1
  53. package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -1
  54. package/build/endpoints/index.js +12 -12
  55. package/build/endpoints/index.js.map +1 -1
  56. package/build/endpoints/next_js/client_jsFilesHref.js +3 -3
  57. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -1
  58. package/build/endpoints/next_js/client_jsonParse.js +4 -4
  59. package/build/endpoints/next_js/client_jsonParse.js.map +1 -1
  60. package/build/endpoints/next_js/client_mappedJsonFile.js +6 -6
  61. package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -1
  62. package/build/endpoints/next_js/client_subsequentRequests.js +5 -5
  63. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -1
  64. package/build/exploit/angular/cve-2026-68945.js +61 -0
  65. package/build/exploit/angular/cve-2026-68945.js.map +1 -0
  66. package/build/exploit/index.js +60 -0
  67. package/build/exploit/index.js.map +1 -0
  68. package/build/exploit/next/cve-2025-29927.js +65 -0
  69. package/build/exploit/next/cve-2025-29927.js.map +1 -0
  70. package/build/exploit/next/cve-2026-64645.js +51 -0
  71. package/build/exploit/next/cve-2026-64645.js.map +1 -0
  72. package/build/exploit/nuxt/cve-2026-71315.js +47 -0
  73. package/build/exploit/nuxt/cve-2026-71315.js.map +1 -0
  74. package/build/exploit/nuxt/cve-2026-71320.js +114 -0
  75. package/build/exploit/nuxt/cve-2026-71320.js.map +1 -0
  76. package/build/exploit/react/cve-2025-55182.js +116 -0
  77. package/build/exploit/react/cve-2025-55182.js.map +1 -0
  78. package/build/exploit/registry/cveRegistry.js +115 -0
  79. package/build/exploit/registry/cveRegistry.js.map +1 -0
  80. package/build/exploit/types.js +2 -0
  81. package/build/exploit/types.js.map +1 -0
  82. package/build/exploit/utility/compareResponses.js +29 -0
  83. package/build/exploit/utility/compareResponses.js.map +1 -0
  84. package/build/exploit/utility/outputHelper.js +22 -0
  85. package/build/exploit/utility/outputHelper.js.map +1 -0
  86. package/build/exploit/utility/rawRequest.js +56 -0
  87. package/build/exploit/utility/rawRequest.js.map +1 -0
  88. package/build/exploit/utility/sandboxRce.js +49 -0
  89. package/build/exploit/utility/sandboxRce.js.map +1 -0
  90. package/build/exploit/utility/toEngineOutput.js +28 -0
  91. package/build/exploit/utility/toEngineOutput.js.map +1 -0
  92. package/build/exploit/utility/wsClient.js +78 -0
  93. package/build/exploit/utility/wsClient.js.map +1 -0
  94. package/build/exploit/vite/cve-2025-30208.js +44 -0
  95. package/build/exploit/vite/cve-2025-30208.js.map +1 -0
  96. package/build/exploit/vite/cve-2026-39363.js +60 -0
  97. package/build/exploit/vite/cve-2026-39363.js.map +1 -0
  98. package/build/fingerprint/index.js +3 -2
  99. package/build/fingerprint/index.js.map +1 -1
  100. package/build/globalConfig.js +2 -2
  101. package/build/globalConfig.js.map +1 -1
  102. package/build/index.js +5 -596
  103. package/build/index.js.map +1 -1
  104. package/build/lazyLoad/angular/angular_getFromPageSource.js +3 -3
  105. package/build/lazyLoad/angular/angular_getFromPageSource.js.map +1 -1
  106. package/build/lazyLoad/downloadFilesUtil.js +14 -11
  107. package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
  108. package/build/lazyLoad/downloadQueue.js +9 -1
  109. package/build/lazyLoad/downloadQueue.js.map +1 -1
  110. package/build/lazyLoad/downloadResponse.js +1 -0
  111. package/build/lazyLoad/downloadResponse.js.map +1 -1
  112. package/build/lazyLoad/generic/generic_crawlPages.js +186 -0
  113. package/build/lazyLoad/generic/generic_crawlPages.js.map +1 -0
  114. package/build/lazyLoad/generic/generic_downloadFiles.js +81 -0
  115. package/build/lazyLoad/generic/generic_downloadFiles.js.map +1 -0
  116. package/build/lazyLoad/generic/generic_extractLinks.js +79 -0
  117. package/build/lazyLoad/generic/generic_extractLinks.js.map +1 -0
  118. package/build/lazyLoad/generic/generic_getScriptTags.js +152 -0
  119. package/build/lazyLoad/generic/generic_getScriptTags.js.map +1 -0
  120. package/build/lazyLoad/generic/generic_importMapDiscovery.js +87 -0
  121. package/build/lazyLoad/generic/generic_importMapDiscovery.js.map +1 -0
  122. package/build/lazyLoad/generic/generic_resolveScope.js +66 -0
  123. package/build/lazyLoad/generic/generic_resolveScope.js.map +1 -0
  124. package/build/lazyLoad/generic/generic_scanAttributesForJs.js +122 -0
  125. package/build/lazyLoad/generic/generic_scanAttributesForJs.js.map +1 -0
  126. package/build/lazyLoad/generic/generic_stringsDiscovery.js +103 -0
  127. package/build/lazyLoad/generic/generic_stringsDiscovery.js.map +1 -0
  128. package/build/lazyLoad/generic/generic_webpackChunkPaths.js +56 -0
  129. package/build/lazyLoad/generic/generic_webpackChunkPaths.js.map +1 -0
  130. package/build/lazyLoad/globals.js +31 -0
  131. package/build/lazyLoad/globals.js.map +1 -1
  132. package/build/lazyLoad/index.js +172 -75
  133. package/build/lazyLoad/index.js.map +1 -1
  134. package/build/lazyLoad/methodFilter.js +9 -1
  135. package/build/lazyLoad/methodFilter.js.map +1 -1
  136. package/build/lazyLoad/next_js/NextJsCrawler.js +98 -14
  137. package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -1
  138. package/build/lazyLoad/next_js/next_GetJSScript.js +3 -3
  139. package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -1
  140. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +4 -4
  141. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -1
  142. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +17 -11
  143. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  144. package/build/lazyLoad/next_js/next_SubsequentRequests.js +7 -6
  145. package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -1
  146. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js +1 -1
  147. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js.map +1 -1
  148. package/build/lazyLoad/next_js/next_buildId.js +2 -2
  149. package/build/lazyLoad/next_js/next_buildId.js.map +1 -1
  150. package/build/lazyLoad/next_js/next_getClientSidePaths.js +2 -2
  151. package/build/lazyLoad/next_js/next_getClientSidePaths.js.map +1 -1
  152. package/build/lazyLoad/next_js/next_parseLayoutJs.js +6 -6
  153. package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -1
  154. package/build/lazyLoad/next_js/next_promiseResolve.js +1 -1
  155. package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -1
  156. package/build/lazyLoad/next_js/next_routerStateForge.js +407 -0
  157. package/build/lazyLoad/next_js/next_routerStateForge.js.map +1 -0
  158. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js +1 -1
  159. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js.map +1 -1
  160. package/build/lazyLoad/next_js/next_serverActionIdScan.js +77 -0
  161. package/build/lazyLoad/next_js/next_serverActionIdScan.js.map +1 -0
  162. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +15 -13
  163. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -1
  164. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js +2 -2
  165. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js.map +1 -1
  166. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +3 -3
  167. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -1
  168. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +29 -5
  169. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -1
  170. package/build/lazyLoad/react/react_sourcemapUrls.js +7 -28
  171. package/build/lazyLoad/react/react_sourcemapUrls.js.map +1 -1
  172. package/build/lazyLoad/react/react_webpackChunkPaths.js +10 -202
  173. package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
  174. package/build/lazyLoad/researchUtils.js +15 -0
  175. package/build/lazyLoad/researchUtils.js.map +1 -0
  176. package/build/lazyLoad/shared/webpackChunkParsers.js +218 -0
  177. package/build/lazyLoad/shared/webpackChunkParsers.js.map +1 -0
  178. package/build/lazyLoad/sourcemap.js +120 -0
  179. package/build/lazyLoad/sourcemap.js.map +1 -1
  180. package/build/lazyLoad/stagnation/stagnationMonitor.js +63 -0
  181. package/build/lazyLoad/stagnation/stagnationMonitor.js.map +1 -0
  182. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js +1 -0
  183. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js.map +1 -1
  184. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +5 -5
  185. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -1
  186. package/build/lazyLoad/svelte/svelte_getVersionJson.js +2 -2
  187. package/build/lazyLoad/svelte/svelte_getVersionJson.js.map +1 -1
  188. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js +6 -6
  189. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js.map +1 -1
  190. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +15 -6
  191. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
  192. package/build/lazyLoad/techDetect/checkAngularJS.js +1 -1
  193. package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
  194. package/build/lazyLoad/techDetect/checkNuxtJS.js +3 -3
  195. package/build/lazyLoad/techDetect/checkNuxtJS.js.map +1 -1
  196. package/build/lazyLoad/techDetect/checkSvelte.js +0 -1
  197. package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -1
  198. package/build/lazyLoad/techDetect/checkVueJS.js +6 -6
  199. package/build/lazyLoad/techDetect/checkVueJS.js.map +1 -1
  200. package/build/lazyLoad/techDetect/index.js +17 -1
  201. package/build/lazyLoad/techDetect/index.js.map +1 -1
  202. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +2 -2
  203. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
  204. package/build/lazyLoad/vue/vue_discoverJsFiles.js +13 -11
  205. package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
  206. package/build/lazyLoad/vue/vue_getClientSidePaths.js +1 -1
  207. package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
  208. package/build/lazyLoad/vue/vue_pageSrc.js +1 -1
  209. package/build/lazyLoad/vue/vue_pageSrc.js.map +1 -1
  210. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js +12 -3
  211. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js.map +1 -1
  212. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +2 -2
  213. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -1
  214. package/build/lazyLoad/vue/vue_severalJsFilesHome.js +3 -3
  215. package/build/lazyLoad/vue/vue_severalJsFilesHome.js.map +1 -1
  216. package/build/load/index.js +28 -38
  217. package/build/load/index.js.map +1 -1
  218. package/build/map/angular_js/getAngularConnections.js +6 -6
  219. package/build/map/angular_js/getAngularConnections.js.map +1 -1
  220. package/build/map/graphql/resolveGraphql.js +6 -6
  221. package/build/map/graphql/resolveGraphql.js.map +1 -1
  222. package/build/map/index.js +17 -17
  223. package/build/map/index.js.map +1 -1
  224. package/build/map/interactive-mode/commandHandler.js +278 -0
  225. package/build/map/interactive-mode/commandHandler.js.map +1 -0
  226. package/build/map/interactive-mode/commandHelpers.js +189 -0
  227. package/build/map/interactive-mode/commandHelpers.js.map +1 -0
  228. package/build/map/interactive-mode/esqueryGen.js.map +1 -0
  229. package/build/map/interactive-mode/helpMenu.js +11 -0
  230. package/build/map/interactive-mode/helpMenu.js.map +1 -0
  231. package/build/map/interactive-mode/inputPatch.js.map +1 -0
  232. package/build/map/interactive-mode/interactive.js +71 -0
  233. package/build/map/interactive-mode/interactive.js.map +1 -0
  234. package/build/map/interactive-mode/keybindings.js.map +1 -0
  235. package/build/map/interactive-mode/printer.js.map +1 -0
  236. package/build/map/interactive-mode/ui.js.map +1 -0
  237. package/build/map/next_js/getAxiosInstances.js +5 -5
  238. package/build/map/next_js/getAxiosInstances.js.map +1 -1
  239. package/build/map/next_js/getExports.js +4 -4
  240. package/build/map/next_js/getExports.js.map +1 -1
  241. package/build/map/next_js/getFetchInstances.js +10 -10
  242. package/build/map/next_js/getFetchInstances.js.map +1 -1
  243. package/build/map/next_js/getTurbopackConnections.js +8 -8
  244. package/build/map/next_js/getTurbopackConnections.js.map +1 -1
  245. package/build/map/next_js/getWebpackConnections.js +27 -16
  246. package/build/map/next_js/getWebpackConnections.js.map +1 -1
  247. package/build/map/next_js/interactive.js +3 -65
  248. package/build/map/next_js/interactive.js.map +1 -1
  249. package/build/map/next_js/interactive_helpers/commandHandler.js +38 -290
  250. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -1
  251. package/build/map/next_js/interactive_helpers/commandHelpers.js +0 -184
  252. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -1
  253. package/build/map/next_js/interactive_helpers/helpMenu.js +2 -10
  254. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -1
  255. package/build/map/next_js/resolveAxios.js +6 -6
  256. package/build/map/next_js/resolveAxios.js.map +1 -1
  257. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js +4 -4
  258. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js.map +1 -1
  259. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -2
  260. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
  261. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +5 -5
  262. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
  263. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +10 -10
  264. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
  265. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +13 -9
  266. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
  267. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +12 -8
  268. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -1
  269. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +12 -8
  270. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -1
  271. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +11 -11
  272. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
  273. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +16 -16
  274. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
  275. package/build/map/next_js/resolveFetch.js +23 -23
  276. package/build/map/next_js/resolveFetch.js.map +1 -1
  277. package/build/map/next_js/resolveNewRequest.js +10 -10
  278. package/build/map/next_js/resolveNewRequest.js.map +1 -1
  279. package/build/map/next_js/resolveServerActions.js +4 -4
  280. package/build/map/next_js/resolveServerActions.js.map +1 -1
  281. package/build/map/next_js/utils.js +8 -2
  282. package/build/map/next_js/utils.js.map +1 -1
  283. package/build/map/react_js/getReactConnections.js +21 -14
  284. package/build/map/react_js/getReactConnections.js.map +1 -1
  285. package/build/map/svelte_js/interactive.js +3 -54
  286. package/build/map/svelte_js/interactive.js.map +1 -1
  287. package/build/map/vue_js/getViteConnections.js +23 -16
  288. package/build/map/vue_js/getViteConnections.js.map +1 -1
  289. package/build/map/vue_js/interactive.js +3 -63
  290. package/build/map/vue_js/interactive.js.map +1 -1
  291. package/build/map/vue_js/interactive_helpers/commandHandler.js +34 -283
  292. package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -1
  293. package/build/map/vue_js/interactive_helpers/helpMenu.js +2 -10
  294. package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -1
  295. package/build/map/vue_js/taint_utils.js +1 -1
  296. package/build/map/vue_js/taint_utils.js.map +1 -1
  297. package/build/map/vue_js/vue_resolveFetch.js +12 -12
  298. package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
  299. package/build/map/vue_js/vue_resolveHttpClient.js +18 -18
  300. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  301. package/build/map/vue_js/vue_resolveXhr.js +11 -11
  302. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  303. package/build/mcp/chatOneShot.js +7 -7
  304. package/build/mcp/chatOneShot.js.map +1 -1
  305. package/build/mcp/claudeCodeCreds.js +5 -5
  306. package/build/mcp/claudeCodeCreds.js.map +1 -1
  307. package/build/mcp/cli.js +36 -35
  308. package/build/mcp/cli.js.map +1 -1
  309. package/build/mcp/config.js +4 -4
  310. package/build/mcp/config.js.map +1 -1
  311. package/build/mcp/index.js +7 -7
  312. package/build/mcp/index.js.map +1 -1
  313. package/build/mcp/mcpServer.js +4 -3
  314. package/build/mcp/mcpServer.js.map +1 -1
  315. package/build/mcp/skills.js +1 -0
  316. package/build/mcp/skills.js.map +1 -1
  317. package/build/mcp/tools.js +6 -5
  318. package/build/mcp/tools.js.map +1 -1
  319. package/build/proxy/detectBlockedResponse.js +2 -0
  320. package/build/proxy/detectBlockedResponse.js.map +1 -1
  321. package/build/proxy/index.js +3 -3
  322. package/build/proxy/index.js.map +1 -1
  323. package/build/refactor/index.js +83 -79
  324. package/build/refactor/index.js.map +1 -1
  325. package/build/refactor/next/index.js +69 -26
  326. package/build/refactor/next/index.js.map +1 -1
  327. package/build/refactor/next/transform.js +11 -4
  328. package/build/refactor/next/transform.js.map +1 -1
  329. package/build/refactor/next/validator.js +7 -7
  330. package/build/refactor/next/validator.js.map +1 -1
  331. package/build/refactor/react/index.js +13 -13
  332. package/build/refactor/react/index.js.map +1 -1
  333. package/build/refactor/react/validator.js +7 -7
  334. package/build/refactor/react/validator.js.map +1 -1
  335. package/build/refactor/react-vite/index.js +3 -3
  336. package/build/refactor/react-vite/index.js.map +1 -1
  337. package/build/refactor/remote/hf-client.js +1 -0
  338. package/build/refactor/remote/hf-client.js.map +1 -1
  339. package/build/refactor/remote/version-detect.js +12 -12
  340. package/build/refactor/remote/version-detect.js.map +1 -1
  341. package/build/refactor/vue/index.js +6 -6
  342. package/build/refactor/vue/index.js.map +1 -1
  343. package/build/refactor/vue/vite.js +6 -6
  344. package/build/refactor/vue/vite.js.map +1 -1
  345. package/build/report/index.js +30 -8
  346. package/build/report/index.js.map +1 -1
  347. package/build/report/swaggerJacker.js +63 -0
  348. package/build/report/swaggerJacker.js.map +1 -0
  349. package/build/report/utility/dataTables/genDataTablesPage.js +2 -1
  350. package/build/report/utility/dataTables/genDataTablesPage.js.map +1 -1
  351. package/build/report/utility/genHtml.js +316 -25
  352. package/build/report/utility/genHtml.js.map +1 -1
  353. package/build/report/utility/markdownGen/addAnalyze.js +2 -1
  354. package/build/report/utility/markdownGen/addAnalyze.js.map +1 -1
  355. package/build/report/utility/populateDb/populateAnalysisFindings.js +2 -2
  356. package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -1
  357. package/build/report/utility/populateDb/populateEndpoints.js +3 -3
  358. package/build/report/utility/populateDb/populateEndpoints.js.map +1 -1
  359. package/build/report/utility/populateDb/populateMappedJson.js +2 -2
  360. package/build/report/utility/populateDb/populateMappedJson.js.map +1 -1
  361. package/build/report/utility/populateDb/populateMappedOpenapi.js +3 -3
  362. package/build/report/utility/populateDb/populateMappedOpenapi.js.map +1 -1
  363. package/build/report/utility/severityColors.js +35 -0
  364. package/build/report/utility/severityColors.js.map +1 -0
  365. package/build/run/bundler-detect.js +45 -9
  366. package/build/run/bundler-detect.js.map +1 -1
  367. package/build/run/dashboard/dashboardHtml.js +150 -0
  368. package/build/run/dashboard/dashboardHtml.js.map +1 -0
  369. package/build/run/dashboard/fsBrowser.js +43 -0
  370. package/build/run/dashboard/fsBrowser.js.map +1 -0
  371. package/build/run/dashboard/server.js +123 -0
  372. package/build/run/dashboard/server.js.map +1 -0
  373. package/build/run/dashboard/state.js +97 -0
  374. package/build/run/dashboard/state.js.map +1 -0
  375. package/build/run/index.js +177 -110
  376. package/build/run/index.js.map +1 -1
  377. package/build/run/interruptHandler.js +18 -0
  378. package/build/run/interruptHandler.js.map +1 -1
  379. package/build/sourcemaps/index.js +7 -6
  380. package/build/sourcemaps/index.js.map +1 -1
  381. package/build/strings/index.js +27 -24
  382. package/build/strings/index.js.map +1 -1
  383. package/build/strings/openapi.js +4 -4
  384. package/build/strings/openapi.js.map +1 -1
  385. package/build/strings/permutate.js +4 -4
  386. package/build/strings/permutate.js.map +1 -1
  387. package/build/strings/secrets.js +1 -0
  388. package/build/strings/secrets.js.map +1 -1
  389. package/build/strings/trufflehog.js +66 -19
  390. package/build/strings/trufflehog.js.map +1 -1
  391. package/build/strings/trufflehogConfig.js +36 -0
  392. package/build/strings/trufflehogConfig.js.map +1 -0
  393. package/build/strings/trufflehogDownload.js +115 -0
  394. package/build/strings/trufflehogDownload.js.map +1 -0
  395. package/build/utility/ai.js +33 -4
  396. package/build/utility/ai.js.map +1 -1
  397. package/build/utility/banner.js +4 -3
  398. package/build/utility/banner.js.map +1 -1
  399. package/build/utility/cacheDb.js +78 -0
  400. package/build/utility/cacheDb.js.map +1 -0
  401. package/build/utility/configureSandbox.js +2 -2
  402. package/build/utility/configureSandbox.js.map +1 -1
  403. package/build/utility/customHeaders.js +30 -0
  404. package/build/utility/customHeaders.js.map +1 -0
  405. package/build/utility/globals.js +37 -12
  406. package/build/utility/globals.js.map +1 -1
  407. package/build/utility/heap.js +2 -1
  408. package/build/utility/heap.js.map +1 -1
  409. package/build/utility/makeReq.js +38 -87
  410. package/build/utility/makeReq.js.map +1 -1
  411. package/build/utility/openapiGenerator.js +2 -2
  412. package/build/utility/openapiGenerator.js.map +1 -1
  413. package/build/utility/printMsg.js +53 -0
  414. package/build/utility/printMsg.js.map +1 -0
  415. package/build/utility/progressLog.js +4 -3
  416. package/build/utility/progressLog.js.map +1 -1
  417. package/build/utility/resolvePath.js +2 -1
  418. package/build/utility/resolvePath.js.map +1 -1
  419. package/build/utility/ruleVersionMap.js +73 -0
  420. package/build/utility/ruleVersionMap.js.map +1 -0
  421. package/config.dist.yaml +3 -3
  422. package/contributing/testing.md +106 -0
  423. package/eslint.config.js +24 -0
  424. package/package.json +22 -6
  425. package/scripts/exploit-smoke-test.js +82 -0
  426. package/scripts/framework-detect-smoke-test.js +64 -0
  427. package/scripts/postinstall-completion.mjs +40 -0
  428. package/scripts/smoke-test.js +12 -0
  429. package/build/lazyLoad/downloadLoadedJsUtil.js +0 -98
  430. package/build/lazyLoad/downloadLoadedJsUtil.js.map +0 -1
  431. package/build/map/next_js/interactive_helpers/esqueryGen.js.map +0 -1
  432. package/build/map/next_js/interactive_helpers/inputPatch.js.map +0 -1
  433. package/build/map/next_js/interactive_helpers/keybindings.js.map +0 -1
  434. package/build/map/next_js/interactive_helpers/printer.js.map +0 -1
  435. package/build/map/next_js/interactive_helpers/ui.js.map +0 -1
  436. /package/build/map/{next_js/interactive_helpers → interactive-mode}/esqueryGen.js +0 -0
  437. /package/build/map/{next_js/interactive_helpers → interactive-mode}/inputPatch.js +0 -0
  438. /package/build/map/{next_js/interactive_helpers → interactive-mode}/keybindings.js +0 -0
  439. /package/build/map/{next_js/interactive_helpers → interactive-mode}/printer.js +0 -0
  440. /package/build/map/{next_js/interactive_helpers → interactive-mode}/ui.js +0 -0
@@ -1,307 +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
- "--oxylabs-waf-fallback",
35
- "--oxylabs-fallback-max-requests",
36
- "--oxylabs-fallback-max-total",
37
- "--oxylabs-fallback-max-origins",
38
- "--cache-file",
39
- "--disable-cache",
40
- "--cache-only",
41
- "-y",
42
- "--yes",
43
- "--timeout",
44
- "-k",
45
- "--insecure",
46
- "--no-sandbox",
47
- "--build-id",
48
- "--sourcemap-dir",
49
- "--research",
50
- "--research-output",
51
- "--max-iterations",
52
- "--max-js-size",
53
- "--lazyload-timeout",
54
- "--detection-timeout",
55
- "--max-pages",
56
- "--include-methods",
57
- "--exclude-methods",
58
- "--list-methods",
59
- ],
60
- endpoints: [
61
- "-u",
62
- "--url",
63
- "-d",
64
- "--directory",
65
- "-o",
66
- "--output",
67
- "--output-format",
68
- "-t",
69
- "--tech",
70
- "-l",
71
- "--list",
72
- "--mapped-json",
73
- ],
74
- strings: [
75
- "-d",
76
- "--directory",
77
- "-o",
78
- "--output",
79
- "-e",
80
- "--extract-urls",
81
- "--extracted-url-path",
82
- "-p",
83
- "--permutate",
84
- "--openapi",
85
- "-s",
86
- "--scan-secrets",
87
- "--trufflehog",
88
- ],
89
- proxy: [
90
- "-i",
91
- "--init",
92
- "-d",
93
- "--destroy",
94
- "--destroy-all",
95
- "-r",
96
- "--region",
97
- "--aws-access-key",
98
- "--aws-secret-key",
99
- "-c",
100
- "--config",
101
- "-l",
102
- "--list",
103
- "--feasibility",
104
- "--feasibility-url",
105
- "--proxy-method",
106
- "--proxy",
107
- "--oxylabs-username",
108
- "--oxylabs-password",
109
- "--oxylabs-country",
110
- "--oxylabs-city",
111
- "--oxylabs-session-id",
112
- ],
113
- map: [
114
- "-d",
115
- "--directory",
116
- "-t",
117
- "--tech",
118
- "-l",
119
- "--list",
120
- "-o",
121
- "--output",
122
- "-f",
123
- "--format",
124
- "-i",
125
- "--interactive",
126
- "-c",
127
- "--command",
128
- "--ai",
129
- "--ai-threads",
130
- "--ai-provider",
131
- "--ai-endpoint",
132
- "--openai-api-key",
133
- "--model",
134
- "--openapi",
135
- "--openapi-output",
136
- "--openapi-chunk-tag",
137
- "--no-graphql",
138
- "--ngql",
139
- "--max-recursion-depth",
140
- "--max-heap",
141
- ],
142
- refactor: [
143
- "-m",
144
- "--mapped-json",
145
- "-o",
146
- "--output",
147
- "-t",
148
- "--tech",
149
- "-l",
150
- "--list",
151
- "--collisions",
152
- "--sq",
153
- "--signature-quality",
154
- "--refresh-cache",
155
- "--skip-cache-checks",
156
- "--no-remote",
157
- "--remote-collisions",
158
- "--scat",
159
- "--detect-version",
160
- "--detect-version-config",
161
- "--detect-version-dynamic-threshold",
162
- "--detect-version-dynamic-conf-purge",
163
- ],
164
- analyze: [
165
- "-r",
166
- "--rules",
167
- "--disable-rules-version-check",
168
- "-m",
169
- "--mapped-json",
170
- "-t",
171
- "--tech",
172
- "--openapi",
173
- "-l",
174
- "--list",
175
- "--validate",
176
- "-o",
177
- "--output",
178
- ],
179
- report: [
180
- "-s",
181
- "--sqlite-db",
182
- "-m",
183
- "--mapped-json",
184
- "-a",
185
- "--analyze-json",
186
- "-e",
187
- "--endpoints-json",
188
- "--map-openapi",
189
- "--mapped-openapi-json",
190
- "-o",
191
- "--output",
192
- ],
193
- run: [
194
- "-u",
195
- "--url",
196
- "-r",
197
- "--rules",
198
- "--disable-rules-version-check",
199
- "-c",
200
- "--command",
201
- "-o",
202
- "--output",
203
- "--output-overwrite",
204
- "--strict-scope",
205
- "-s",
206
- "--scope",
207
- "-t",
208
- "--threads",
209
- "--proxy-config",
210
- "--ignore-proxy-env",
211
- "--proxy-waf-fallback",
212
- "--oxylabs-waf-fallback",
213
- "--oxylabs-fallback-max-requests",
214
- "--oxylabs-fallback-max-total",
215
- "--oxylabs-fallback-max-origins",
216
- "--cache-file",
217
- "--disable-cache",
218
- "--cache-only",
219
- "-y",
220
- "--yes",
221
- "--secrets",
222
- "--trufflehog",
223
- "--ai",
224
- "--ai-threads",
225
- "--ai-provider",
226
- "--ai-endpoint",
227
- "--openai-api-key",
228
- "--model",
229
- "--map-openapi-chunk-tag",
230
- "--no-graphql",
231
- "--ngql",
232
- "--timeout",
233
- "-k",
234
- "--insecure",
235
- "--no-sandbox",
236
- "--sourcemap-dir",
237
- "--research",
238
- "--research-output",
239
- "--max-iterations",
240
- "--max-js-size",
241
- "--lazyload-timeout",
242
- "--detection-timeout",
243
- "--max-heap",
244
- "--max-pages",
245
- "--include-methods",
246
- "--exclude-methods",
247
- "--list-methods",
248
- "--cs-mast-tech-detect-threshold",
249
- "--disable-refactor",
250
- ],
251
- load: ["-c", "--caido", "-u", "--url", "--cache-file"],
252
- fingerprint: [
253
- "-u",
254
- "--url",
255
- "-o",
256
- "--output",
257
- "-f",
258
- "--format",
259
- "-t",
260
- "--threads",
261
- "--timeout",
262
- "-k",
263
- "--insecure",
264
- "--no-sandbox",
265
- ],
266
- mcp: [
267
- "--cli",
268
- "--server",
269
- "-c",
270
- "--chat",
271
- "--config",
272
- "--api-key",
273
- "--model",
274
- "--provider",
275
- "--no-refresh-claude-creds",
276
- "--claude-client-id",
277
- ],
278
- "cs-mast": [
279
- "-o",
280
- "--output",
281
- "--ct",
282
- "--collision-table",
283
- "--min-collisions",
284
- "--co",
285
- "--collision-output",
286
- "--cf",
287
- "--collision-format",
288
- "--scat",
289
- "--sinc",
290
- "--all-scat-permutations",
291
- "--perm-output",
292
- "--perm-concurrency",
293
- ],
294
- sourcemaps: ["-i", "--input", "-o", "--output"],
295
- completion: ["bash", "zsh", "fish"],
296
- };
297
- function generateBashCompletion() {
298
- const cmdList = COMMANDS.join(" ");
299
- const cmdPattern = COMMANDS.join("|");
300
- const caseBranches = Object.entries(FLAGS)
301
- .map(([cmd, flags]) => ` ${cmd})\n opts="${flags.join(" ")}"\n ;;`)
302
- .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");
303
34
  return `# js-recon bash completion
304
- # Add to ~/.bashrc: eval "$(js-recon completion bash)"
35
+ # Installed automatically by: js-recon completion bash
305
36
  _js_recon_completion() {
306
37
  local cur prev words cword opts
307
38
  COMPREPLY=()
@@ -310,25 +41,13 @@ _js_recon_completion() {
310
41
  words=("\${COMP_WORDS[@]}")
311
42
  cword=\${COMP_CWORD}
312
43
 
313
- if [[ \${prev} == "--config" ]]; then
314
- COMPREPLY=( \$(compgen -f -- "\${cur}") )
315
- return 0
316
- fi
317
-
318
- local cmd=""
319
- local word
320
- for word in "\${words[@]}"; do
321
- case "\${word}" in
322
- ${cmdPattern}) cmd="\${word}"; break ;;
323
- esac
324
- done
325
- if [[ -z \${cmd} ]]; then
326
- COMPREPLY=( \$(compgen -W "--config ${cmdList}" -- "\${cur}") )
44
+ if [[ \${cword} -eq 1 ]]; then
45
+ COMPREPLY=( \$(compgen -W "${cmdList}" -- "\${cur}") )
327
46
  return 0
328
47
  fi
329
48
 
330
49
  opts=""
331
- case "\${cmd}" in
50
+ case "\${words[1]}" in
332
51
  ${caseBranches}
333
52
  esac
334
53
 
@@ -338,34 +57,88 @@ ${caseBranches}
338
57
  complete -F _js_recon_completion js-recon
339
58
  `;
340
59
  }
341
- function generateZshCompletion() {
342
- const commandDescriptions = [
343
- "'lazyload:Run lazy load module'",
344
- "'endpoints:Extract client-side endpoints'",
345
- "'strings:Extract strings from JS files'",
346
- "'proxy:Manage proxy configuration (AWS API Gateway IP rotation, SOCKS/HTTP, Oxylabs)'",
347
- "'map:Map all the functions'",
348
- "'refactor:Refactor the code'",
349
- "'analyze:Analyze the code'",
350
- "'report:Generate a report'",
351
- "'run:Run all modules'",
352
- "'load:Populate response cache from a Caido/Burp request history export'",
353
- "'fingerprint:Detect front-end frameworks across one or more URLs'",
354
- "'mcp:AI-powered CLI / one-shot chat / MCP server'",
355
- "'cs-mast:Compute CS-MAST hashes for downloaded JS files'",
356
- "'sourcemaps:Extract source files from .map sourcemap file(s)'",
357
- "'completion:Generate shell completion scripts'",
358
- ].join("\n ");
359
- const caseBranches = Object.entries(FLAGS)
360
- .map(([cmd, flags]) => {
361
- const flagArgs = flags.map((f) => `'${f}'`).join(" ");
362
- 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
+ ;;`;
363
137
  })
364
138
  .join("\n");
365
139
  return `#compdef js-recon
366
140
  # js-recon zsh completion
367
- # Add to ~/.zshrc: eval "$(js-recon completion zsh)"
368
- # Or: js-recon completion zsh > "\${fpath[1]}/_js-recon"
141
+ # Installed automatically by: js-recon completion zsh
369
142
 
370
143
  _js_recon() {
371
144
  local state line
@@ -374,7 +147,6 @@ _js_recon() {
374
147
  _arguments -C \\
375
148
  '(-h --help)'{-h,--help}'[Show help]' \\
376
149
  '(-V --version)'{-V,--version}'[Show version]' \\
377
- '--config[Application YAML config]:file:_files' \\
378
150
  '1: :->command' \\
379
151
  '*: :->args'
380
152
 
@@ -397,40 +169,55 @@ ${caseBranches}
397
169
  _js_recon "\$@"
398
170
  `;
399
171
  }
400
- function generateFishCompletion() {
401
- const cmdCompletions = COMMANDS.map((cmd) => `complete -c js-recon -f -n '__fish_use_subcommand' -a ${cmd}`).join("\n");
402
- const flagCompletions = Object.entries(FLAGS)
403
- .flatMap(([cmd, flags]) => flags.map((flag) => {
404
- if (flag.startsWith("--")) {
405
- 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}'`);
406
194
  }
407
- else if (flag.startsWith("-") && flag.length === 2) {
408
- 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}'`);
409
197
  }
410
- // positional (e.g. shell names for 'completion' subcommand)
411
- return `complete -c js-recon -n '__fish_seen_subcommand_from ${cmd}' -a ${flag}`;
412
- }))
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)}'`)
413
211
  .join("\n");
212
+ const flagCompletions = tree.flatMap((node) => generateFishNode(node, [])).join("\n");
414
213
  return `# js-recon fish completion
415
- # Save to: ~/.config/fish/completions/js-recon.fish
416
- # 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)
417
216
 
418
217
  function __fish_use_subcommand
419
218
  set -l cmd (commandline -poc)
420
219
  set -e cmd[1]
421
- set -l skip_next 0
422
220
  for c in $cmd
423
- if test $skip_next -eq 1
424
- set skip_next 0
425
- continue
426
- end
427
- if test "$c" = "--config"
428
- set skip_next 1
429
- continue
430
- end
431
- if string match -q -- '--config=*' "$c"
432
- continue
433
- end
434
221
  if string match -qr '^[^-]' -- $c
435
222
  return 1
436
223
  end
@@ -451,29 +238,107 @@ end
451
238
 
452
239
  ${cmdCompletions}
453
240
 
454
- complete -c js-recon -l config -r -F
455
-
456
241
  ${flagCompletions}
457
242
  `;
458
243
  }
459
- export default function completion(shell) {
460
- if (!shell) {
461
- console.error(chalk.red("[!] Shell type required. Usage: js-recon completion <bash|zsh|fish>"));
462
- 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}`);
263
+ }
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
+ `;
463
280
  }
464
- switch (shell.toLowerCase()) {
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) {
465
290
  case "bash":
466
- process.stdout.write(generateBashCompletion());
467
- break;
291
+ return generateBashCompletion(tree);
468
292
  case "zsh":
469
- process.stdout.write(generateZshCompletion());
470
- break;
293
+ return generateZshCompletion(tree);
471
294
  case "fish":
472
- process.stdout.write(generateFishCompletion());
473
- break;
295
+ return generateFishCompletion(tree);
474
296
  default:
475
- 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/".');
476
337
  process.exit(1);
338
+ }
339
+ process.stdout.write(generateRcFileLoader(normalizedShell));
340
+ return;
477
341
  }
342
+ installCompletion(normalizedShell);
478
343
  }
479
344
  //# sourceMappingURL=index.js.map