codesift-mcp 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (543) hide show
  1. package/README.md +215 -23
  2. package/dist/cache/hono-cache.d.ts +50 -0
  3. package/dist/cache/hono-cache.d.ts.map +1 -0
  4. package/dist/cache/hono-cache.js +132 -0
  5. package/dist/cache/hono-cache.js.map +1 -0
  6. package/dist/cli/help.d.ts.map +1 -1
  7. package/dist/cli/help.js +8 -6
  8. package/dist/cli/help.js.map +1 -1
  9. package/dist/cli/platform.d.ts.map +1 -1
  10. package/dist/cli/platform.js +12 -14
  11. package/dist/cli/platform.js.map +1 -1
  12. package/dist/cli/setup.d.ts +1 -1
  13. package/dist/cli/setup.d.ts.map +1 -1
  14. package/dist/cli/setup.js +27 -3
  15. package/dist/cli/setup.js.map +1 -1
  16. package/dist/formatters-shortening.d.ts +13 -0
  17. package/dist/formatters-shortening.d.ts.map +1 -1
  18. package/dist/formatters-shortening.js +131 -0
  19. package/dist/formatters-shortening.js.map +1 -1
  20. package/dist/formatters.d.ts +38 -0
  21. package/dist/formatters.d.ts.map +1 -1
  22. package/dist/formatters.js +521 -0
  23. package/dist/formatters.js.map +1 -1
  24. package/dist/instructions.d.ts +1 -1
  25. package/dist/instructions.d.ts.map +1 -1
  26. package/dist/instructions.js +39 -38
  27. package/dist/instructions.js.map +1 -1
  28. package/dist/lsp/lsp-servers.d.ts.map +1 -1
  29. package/dist/lsp/lsp-servers.js +5 -0
  30. package/dist/lsp/lsp-servers.js.map +1 -1
  31. package/dist/lsp/lsp-tools.d.ts.map +1 -1
  32. package/dist/lsp/lsp-tools.js +1 -0
  33. package/dist/lsp/lsp-tools.js.map +1 -1
  34. package/dist/parser/astro-template.d.ts +47 -0
  35. package/dist/parser/astro-template.d.ts.map +1 -0
  36. package/dist/parser/astro-template.js +171 -0
  37. package/dist/parser/astro-template.js.map +1 -0
  38. package/dist/parser/extractors/_shared.d.ts +4 -0
  39. package/dist/parser/extractors/_shared.d.ts.map +1 -1
  40. package/dist/parser/extractors/_shared.js +8 -0
  41. package/dist/parser/extractors/_shared.js.map +1 -1
  42. package/dist/parser/extractors/astro.d.ts +4 -5
  43. package/dist/parser/extractors/astro.d.ts.map +1 -1
  44. package/dist/parser/extractors/astro.js +102 -26
  45. package/dist/parser/extractors/astro.js.map +1 -1
  46. package/dist/parser/extractors/gradle-kts.d.ts +4 -0
  47. package/dist/parser/extractors/gradle-kts.d.ts.map +1 -0
  48. package/dist/parser/extractors/gradle-kts.js +246 -0
  49. package/dist/parser/extractors/gradle-kts.js.map +1 -0
  50. package/dist/parser/extractors/hono-inline-analyzer.d.ts +34 -0
  51. package/dist/parser/extractors/hono-inline-analyzer.d.ts.map +1 -0
  52. package/dist/parser/extractors/hono-inline-analyzer.js +465 -0
  53. package/dist/parser/extractors/hono-inline-analyzer.js.map +1 -0
  54. package/dist/parser/extractors/hono-model.d.ts +196 -0
  55. package/dist/parser/extractors/hono-model.d.ts.map +1 -0
  56. package/dist/parser/extractors/hono-model.js +10 -0
  57. package/dist/parser/extractors/hono-model.js.map +1 -0
  58. package/dist/parser/extractors/hono.d.ts +118 -0
  59. package/dist/parser/extractors/hono.d.ts.map +1 -0
  60. package/dist/parser/extractors/hono.js +1527 -0
  61. package/dist/parser/extractors/hono.js.map +1 -0
  62. package/dist/parser/extractors/kotlin.d.ts +4 -0
  63. package/dist/parser/extractors/kotlin.d.ts.map +1 -0
  64. package/dist/parser/extractors/kotlin.js +521 -0
  65. package/dist/parser/extractors/kotlin.js.map +1 -0
  66. package/dist/parser/extractors/php.d.ts +22 -0
  67. package/dist/parser/extractors/php.d.ts.map +1 -0
  68. package/dist/parser/extractors/php.js +334 -0
  69. package/dist/parser/extractors/php.js.map +1 -0
  70. package/dist/parser/extractors/python.d.ts.map +1 -1
  71. package/dist/parser/extractors/python.js +234 -11
  72. package/dist/parser/extractors/python.js.map +1 -1
  73. package/dist/parser/extractors/sql.d.ts +33 -0
  74. package/dist/parser/extractors/sql.d.ts.map +1 -0
  75. package/dist/parser/extractors/sql.js +506 -0
  76. package/dist/parser/extractors/sql.js.map +1 -0
  77. package/dist/parser/extractors/typescript.d.ts.map +1 -1
  78. package/dist/parser/extractors/typescript.js +209 -3
  79. package/dist/parser/extractors/typescript.js.map +1 -1
  80. package/dist/parser/languages/tree-sitter-javascript.wasm +0 -0
  81. package/dist/parser/languages/tree-sitter-kotlin.wasm +0 -0
  82. package/dist/parser/languages/tree-sitter-php.wasm +0 -0
  83. package/dist/parser/languages/tree-sitter-php_only.wasm +0 -0
  84. package/dist/parser/languages/tree-sitter-python.wasm +0 -0
  85. package/dist/parser/parse-cache.d.ts +39 -0
  86. package/dist/parser/parse-cache.d.ts.map +1 -0
  87. package/dist/parser/parse-cache.js +87 -0
  88. package/dist/parser/parse-cache.js.map +1 -0
  89. package/dist/parser/parser-manager.d.ts +32 -0
  90. package/dist/parser/parser-manager.d.ts.map +1 -1
  91. package/dist/parser/parser-manager.js +93 -3
  92. package/dist/parser/parser-manager.js.map +1 -1
  93. package/dist/parser/symbol-extractor.d.ts.map +1 -1
  94. package/dist/parser/symbol-extractor.js +16 -0
  95. package/dist/parser/symbol-extractor.js.map +1 -1
  96. package/dist/register-tools.d.ts +38 -2
  97. package/dist/register-tools.d.ts.map +1 -1
  98. package/dist/register-tools.js +2444 -195
  99. package/dist/register-tools.js.map +1 -1
  100. package/dist/search/reranker.js +1 -1
  101. package/dist/search/reranker.js.map +1 -1
  102. package/dist/search/tool-ranker.d.ts +90 -0
  103. package/dist/search/tool-ranker.d.ts.map +1 -0
  104. package/dist/search/tool-ranker.js +420 -0
  105. package/dist/search/tool-ranker.js.map +1 -0
  106. package/dist/server-helpers.d.ts.map +1 -1
  107. package/dist/server-helpers.js +11 -0
  108. package/dist/server-helpers.js.map +1 -1
  109. package/dist/server.js +47 -14
  110. package/dist/server.js.map +1 -1
  111. package/dist/storage/index-store.d.ts +15 -1
  112. package/dist/storage/index-store.d.ts.map +1 -1
  113. package/dist/storage/index-store.js +27 -1
  114. package/dist/storage/index-store.js.map +1 -1
  115. package/dist/storage/session-state.d.ts +1 -1
  116. package/dist/storage/session-state.d.ts.map +1 -1
  117. package/dist/storage/session-state.js +6 -4
  118. package/dist/storage/session-state.js.map +1 -1
  119. package/dist/storage/usage-tracker.d.ts.map +1 -1
  120. package/dist/storage/usage-tracker.js +4 -1
  121. package/dist/storage/usage-tracker.js.map +1 -1
  122. package/dist/tools/agent-config-tools.d.ts +24 -0
  123. package/dist/tools/agent-config-tools.d.ts.map +1 -0
  124. package/dist/tools/agent-config-tools.js +119 -0
  125. package/dist/tools/agent-config-tools.js.map +1 -0
  126. package/dist/tools/architecture-tools.d.ts +23 -0
  127. package/dist/tools/architecture-tools.d.ts.map +1 -0
  128. package/dist/tools/architecture-tools.js +140 -0
  129. package/dist/tools/architecture-tools.js.map +1 -0
  130. package/dist/tools/astro-actions.d.ts +54 -0
  131. package/dist/tools/astro-actions.d.ts.map +1 -0
  132. package/dist/tools/astro-actions.js +561 -0
  133. package/dist/tools/astro-actions.js.map +1 -0
  134. package/dist/tools/astro-audit.d.ts +87 -0
  135. package/dist/tools/astro-audit.d.ts.map +1 -0
  136. package/dist/tools/astro-audit.js +345 -0
  137. package/dist/tools/astro-audit.js.map +1 -0
  138. package/dist/tools/astro-config.d.ts +33 -0
  139. package/dist/tools/astro-config.d.ts.map +1 -0
  140. package/dist/tools/astro-config.js +260 -0
  141. package/dist/tools/astro-config.js.map +1 -0
  142. package/dist/tools/astro-content-collections.d.ts +44 -0
  143. package/dist/tools/astro-content-collections.d.ts.map +1 -0
  144. package/dist/tools/astro-content-collections.js +630 -0
  145. package/dist/tools/astro-content-collections.js.map +1 -0
  146. package/dist/tools/astro-islands.d.ts +63 -0
  147. package/dist/tools/astro-islands.d.ts.map +1 -0
  148. package/dist/tools/astro-islands.js +255 -0
  149. package/dist/tools/astro-islands.js.map +1 -0
  150. package/dist/tools/astro-migration.d.ts +31 -0
  151. package/dist/tools/astro-migration.d.ts.map +1 -0
  152. package/dist/tools/astro-migration.js +378 -0
  153. package/dist/tools/astro-migration.js.map +1 -0
  154. package/dist/tools/astro-routes.d.ts +49 -0
  155. package/dist/tools/astro-routes.d.ts.map +1 -0
  156. package/dist/tools/astro-routes.js +119 -0
  157. package/dist/tools/astro-routes.js.map +1 -0
  158. package/dist/tools/async-correctness.d.ts +26 -0
  159. package/dist/tools/async-correctness.d.ts.map +1 -0
  160. package/dist/tools/async-correctness.js +166 -0
  161. package/dist/tools/async-correctness.js.map +1 -0
  162. package/dist/tools/audit-tools.d.ts +38 -0
  163. package/dist/tools/audit-tools.d.ts.map +1 -0
  164. package/dist/tools/audit-tools.js +248 -0
  165. package/dist/tools/audit-tools.js.map +1 -0
  166. package/dist/tools/celery-tools.d.ts +38 -0
  167. package/dist/tools/celery-tools.d.ts.map +1 -0
  168. package/dist/tools/celery-tools.js +154 -0
  169. package/dist/tools/celery-tools.js.map +1 -0
  170. package/dist/tools/clone-tools.js +1 -1
  171. package/dist/tools/clone-tools.js.map +1 -1
  172. package/dist/tools/complexity-tools.d.ts +4 -0
  173. package/dist/tools/complexity-tools.d.ts.map +1 -1
  174. package/dist/tools/complexity-tools.js +78 -4
  175. package/dist/tools/complexity-tools.js.map +1 -1
  176. package/dist/tools/compose-tools.d.ts +60 -0
  177. package/dist/tools/compose-tools.d.ts.map +1 -0
  178. package/dist/tools/compose-tools.js +203 -0
  179. package/dist/tools/compose-tools.js.map +1 -0
  180. package/dist/tools/coupling-tools.d.ts +50 -0
  181. package/dist/tools/coupling-tools.d.ts.map +1 -0
  182. package/dist/tools/coupling-tools.js +262 -0
  183. package/dist/tools/coupling-tools.js.map +1 -0
  184. package/dist/tools/dependency-audit-tools.d.ts +65 -0
  185. package/dist/tools/dependency-audit-tools.d.ts.map +1 -0
  186. package/dist/tools/dependency-audit-tools.js +553 -0
  187. package/dist/tools/dependency-audit-tools.js.map +1 -0
  188. package/dist/tools/django-settings.d.ts +22 -0
  189. package/dist/tools/django-settings.d.ts.map +1 -0
  190. package/dist/tools/django-settings.js +301 -0
  191. package/dist/tools/django-settings.js.map +1 -0
  192. package/dist/tools/django-view-security-tools.d.ts +32 -0
  193. package/dist/tools/django-view-security-tools.d.ts.map +1 -0
  194. package/dist/tools/django-view-security-tools.js +184 -0
  195. package/dist/tools/django-view-security-tools.js.map +1 -0
  196. package/dist/tools/fastapi-depends.d.ts +63 -0
  197. package/dist/tools/fastapi-depends.d.ts.map +1 -0
  198. package/dist/tools/fastapi-depends.js +191 -0
  199. package/dist/tools/fastapi-depends.js.map +1 -0
  200. package/dist/tools/frequency-tools.js +1 -1
  201. package/dist/tools/frequency-tools.js.map +1 -1
  202. package/dist/tools/graph-tools.d.ts +8 -2
  203. package/dist/tools/graph-tools.d.ts.map +1 -1
  204. package/dist/tools/graph-tools.js +44 -3
  205. package/dist/tools/graph-tools.js.map +1 -1
  206. package/dist/tools/hilt-tools.d.ts +55 -0
  207. package/dist/tools/hilt-tools.d.ts.map +1 -0
  208. package/dist/tools/hilt-tools.js +258 -0
  209. package/dist/tools/hilt-tools.js.map +1 -0
  210. package/dist/tools/hono-analyze-app.d.ts +48 -0
  211. package/dist/tools/hono-analyze-app.d.ts.map +1 -0
  212. package/dist/tools/hono-analyze-app.js +94 -0
  213. package/dist/tools/hono-analyze-app.js.map +1 -0
  214. package/dist/tools/hono-api-contract.d.ts +22 -0
  215. package/dist/tools/hono-api-contract.d.ts.map +1 -0
  216. package/dist/tools/hono-api-contract.js +112 -0
  217. package/dist/tools/hono-api-contract.js.map +1 -0
  218. package/dist/tools/hono-conditional-middleware.d.ts +27 -0
  219. package/dist/tools/hono-conditional-middleware.d.ts.map +1 -0
  220. package/dist/tools/hono-conditional-middleware.js +62 -0
  221. package/dist/tools/hono-conditional-middleware.js.map +1 -0
  222. package/dist/tools/hono-context-flow.d.ts +24 -0
  223. package/dist/tools/hono-context-flow.d.ts.map +1 -0
  224. package/dist/tools/hono-context-flow.js +70 -0
  225. package/dist/tools/hono-context-flow.js.map +1 -0
  226. package/dist/tools/hono-dead-routes.d.ts +26 -0
  227. package/dist/tools/hono-dead-routes.d.ts.map +1 -0
  228. package/dist/tools/hono-dead-routes.js +102 -0
  229. package/dist/tools/hono-dead-routes.js.map +1 -0
  230. package/dist/tools/hono-entry-resolver.d.ts +27 -0
  231. package/dist/tools/hono-entry-resolver.d.ts.map +1 -0
  232. package/dist/tools/hono-entry-resolver.js +31 -0
  233. package/dist/tools/hono-entry-resolver.js.map +1 -0
  234. package/dist/tools/hono-env-regression.d.ts +29 -0
  235. package/dist/tools/hono-env-regression.d.ts.map +1 -0
  236. package/dist/tools/hono-env-regression.js +157 -0
  237. package/dist/tools/hono-env-regression.js.map +1 -0
  238. package/dist/tools/hono-inline-analyze.d.ts +31 -0
  239. package/dist/tools/hono-inline-analyze.d.ts.map +1 -0
  240. package/dist/tools/hono-inline-analyze.js +59 -0
  241. package/dist/tools/hono-inline-analyze.js.map +1 -0
  242. package/dist/tools/hono-middleware-chain.d.ts +40 -0
  243. package/dist/tools/hono-middleware-chain.d.ts.map +1 -0
  244. package/dist/tools/hono-middleware-chain.js +121 -0
  245. package/dist/tools/hono-middleware-chain.js.map +1 -0
  246. package/dist/tools/hono-modules.d.ts +22 -0
  247. package/dist/tools/hono-modules.d.ts.map +1 -0
  248. package/dist/tools/hono-modules.js +118 -0
  249. package/dist/tools/hono-modules.js.map +1 -0
  250. package/dist/tools/hono-response-types.d.ts +37 -0
  251. package/dist/tools/hono-response-types.d.ts.map +1 -0
  252. package/dist/tools/hono-response-types.js +76 -0
  253. package/dist/tools/hono-response-types.js.map +1 -0
  254. package/dist/tools/hono-rpc-types.d.ts +21 -0
  255. package/dist/tools/hono-rpc-types.d.ts.map +1 -0
  256. package/dist/tools/hono-rpc-types.js +49 -0
  257. package/dist/tools/hono-rpc-types.js.map +1 -0
  258. package/dist/tools/hono-security.d.ts +31 -0
  259. package/dist/tools/hono-security.d.ts.map +1 -0
  260. package/dist/tools/hono-security.js +269 -0
  261. package/dist/tools/hono-security.js.map +1 -0
  262. package/dist/tools/hono-visualize.d.ts +13 -0
  263. package/dist/tools/hono-visualize.d.ts.map +1 -0
  264. package/dist/tools/hono-visualize.js +64 -0
  265. package/dist/tools/hono-visualize.js.map +1 -0
  266. package/dist/tools/hotspot-tools.d.ts.map +1 -1
  267. package/dist/tools/hotspot-tools.js +9 -7
  268. package/dist/tools/hotspot-tools.js.map +1 -1
  269. package/dist/tools/index-tools.d.ts +17 -0
  270. package/dist/tools/index-tools.d.ts.map +1 -1
  271. package/dist/tools/index-tools.js +210 -10
  272. package/dist/tools/index-tools.js.map +1 -1
  273. package/dist/tools/kotlin-tools.d.ts +142 -0
  274. package/dist/tools/kotlin-tools.d.ts.map +1 -0
  275. package/dist/tools/kotlin-tools.js +572 -0
  276. package/dist/tools/kotlin-tools.js.map +1 -0
  277. package/dist/tools/legacy-hono-conventions.d.ts +14 -0
  278. package/dist/tools/legacy-hono-conventions.d.ts.map +1 -0
  279. package/dist/tools/legacy-hono-conventions.js +152 -0
  280. package/dist/tools/legacy-hono-conventions.js.map +1 -0
  281. package/dist/tools/migration-lint-tools.d.ts +26 -0
  282. package/dist/tools/migration-lint-tools.d.ts.map +1 -0
  283. package/dist/tools/migration-lint-tools.js +247 -0
  284. package/dist/tools/migration-lint-tools.js.map +1 -0
  285. package/dist/tools/model-tools.d.ts +30 -0
  286. package/dist/tools/model-tools.d.ts.map +1 -0
  287. package/dist/tools/model-tools.js +145 -0
  288. package/dist/tools/model-tools.js.map +1 -0
  289. package/dist/tools/nest-ext-tools.d.ts +207 -0
  290. package/dist/tools/nest-ext-tools.d.ts.map +1 -0
  291. package/dist/tools/nest-ext-tools.js +752 -0
  292. package/dist/tools/nest-ext-tools.js.map +1 -0
  293. package/dist/tools/nest-tools.d.ts +198 -0
  294. package/dist/tools/nest-tools.d.ts.map +1 -0
  295. package/dist/tools/nest-tools.js +1142 -0
  296. package/dist/tools/nest-tools.js.map +1 -0
  297. package/dist/tools/nextjs-api-contract-readers.d.ts +14 -0
  298. package/dist/tools/nextjs-api-contract-readers.d.ts.map +1 -0
  299. package/dist/tools/nextjs-api-contract-readers.js +204 -0
  300. package/dist/tools/nextjs-api-contract-readers.js.map +1 -0
  301. package/dist/tools/nextjs-api-contract-tools.d.ts +57 -0
  302. package/dist/tools/nextjs-api-contract-tools.d.ts.map +1 -0
  303. package/dist/tools/nextjs-api-contract-tools.js +144 -0
  304. package/dist/tools/nextjs-api-contract-tools.js.map +1 -0
  305. package/dist/tools/nextjs-boundary-tools.d.ts +39 -0
  306. package/dist/tools/nextjs-boundary-tools.d.ts.map +1 -0
  307. package/dist/tools/nextjs-boundary-tools.js +152 -0
  308. package/dist/tools/nextjs-boundary-tools.js.map +1 -0
  309. package/dist/tools/nextjs-component-readers.d.ts +101 -0
  310. package/dist/tools/nextjs-component-readers.d.ts.map +1 -0
  311. package/dist/tools/nextjs-component-readers.js +287 -0
  312. package/dist/tools/nextjs-component-readers.js.map +1 -0
  313. package/dist/tools/nextjs-component-tools.d.ts +51 -0
  314. package/dist/tools/nextjs-component-tools.d.ts.map +1 -0
  315. package/dist/tools/nextjs-component-tools.js +212 -0
  316. package/dist/tools/nextjs-component-tools.js.map +1 -0
  317. package/dist/tools/nextjs-data-flow-tools.d.ts +42 -0
  318. package/dist/tools/nextjs-data-flow-tools.d.ts.map +1 -0
  319. package/dist/tools/nextjs-data-flow-tools.js +158 -0
  320. package/dist/tools/nextjs-data-flow-tools.js.map +1 -0
  321. package/dist/tools/nextjs-framework-audit-tools.d.ts +60 -0
  322. package/dist/tools/nextjs-framework-audit-tools.d.ts.map +1 -0
  323. package/dist/tools/nextjs-framework-audit-tools.js +394 -0
  324. package/dist/tools/nextjs-framework-audit-tools.js.map +1 -0
  325. package/dist/tools/nextjs-link-tools.d.ts +41 -0
  326. package/dist/tools/nextjs-link-tools.d.ts.map +1 -0
  327. package/dist/tools/nextjs-link-tools.js +157 -0
  328. package/dist/tools/nextjs-link-tools.js.map +1 -0
  329. package/dist/tools/nextjs-metadata-tools.d.ts +74 -0
  330. package/dist/tools/nextjs-metadata-tools.d.ts.map +1 -0
  331. package/dist/tools/nextjs-metadata-tools.js +252 -0
  332. package/dist/tools/nextjs-metadata-tools.js.map +1 -0
  333. package/dist/tools/nextjs-middleware-coverage-tools.d.ts +41 -0
  334. package/dist/tools/nextjs-middleware-coverage-tools.d.ts.map +1 -0
  335. package/dist/tools/nextjs-middleware-coverage-tools.js +88 -0
  336. package/dist/tools/nextjs-middleware-coverage-tools.js.map +1 -0
  337. package/dist/tools/nextjs-route-readers.d.ts +81 -0
  338. package/dist/tools/nextjs-route-readers.d.ts.map +1 -0
  339. package/dist/tools/nextjs-route-readers.js +340 -0
  340. package/dist/tools/nextjs-route-readers.js.map +1 -0
  341. package/dist/tools/nextjs-route-tools.d.ts +36 -0
  342. package/dist/tools/nextjs-route-tools.d.ts.map +1 -0
  343. package/dist/tools/nextjs-route-tools.js +175 -0
  344. package/dist/tools/nextjs-route-tools.js.map +1 -0
  345. package/dist/tools/nextjs-security-readers.d.ts +22 -0
  346. package/dist/tools/nextjs-security-readers.d.ts.map +1 -0
  347. package/dist/tools/nextjs-security-readers.js +318 -0
  348. package/dist/tools/nextjs-security-readers.js.map +1 -0
  349. package/dist/tools/nextjs-security-scoring.d.ts +15 -0
  350. package/dist/tools/nextjs-security-scoring.d.ts.map +1 -0
  351. package/dist/tools/nextjs-security-scoring.js +65 -0
  352. package/dist/tools/nextjs-security-scoring.js.map +1 -0
  353. package/dist/tools/nextjs-security-tools.d.ts +75 -0
  354. package/dist/tools/nextjs-security-tools.d.ts.map +1 -0
  355. package/dist/tools/nextjs-security-tools.js +153 -0
  356. package/dist/tools/nextjs-security-tools.js.map +1 -0
  357. package/dist/tools/nextjs-tools.d.ts +15 -0
  358. package/dist/tools/nextjs-tools.d.ts.map +1 -0
  359. package/dist/tools/nextjs-tools.js +15 -0
  360. package/dist/tools/nextjs-tools.js.map +1 -0
  361. package/dist/tools/outline-tools.d.ts.map +1 -1
  362. package/dist/tools/outline-tools.js +20 -0
  363. package/dist/tools/outline-tools.js.map +1 -1
  364. package/dist/tools/pattern-tools.d.ts +8 -0
  365. package/dist/tools/pattern-tools.d.ts.map +1 -1
  366. package/dist/tools/pattern-tools.js +651 -3
  367. package/dist/tools/pattern-tools.js.map +1 -1
  368. package/dist/tools/perf-tools.d.ts +32 -0
  369. package/dist/tools/perf-tools.d.ts.map +1 -0
  370. package/dist/tools/perf-tools.js +227 -0
  371. package/dist/tools/perf-tools.js.map +1 -0
  372. package/dist/tools/php-tools.d.ts +185 -0
  373. package/dist/tools/php-tools.d.ts.map +1 -0
  374. package/dist/tools/php-tools.js +645 -0
  375. package/dist/tools/php-tools.js.map +1 -0
  376. package/dist/tools/plan-turn-tools.d.ts +89 -0
  377. package/dist/tools/plan-turn-tools.d.ts.map +1 -0
  378. package/dist/tools/plan-turn-tools.js +508 -0
  379. package/dist/tools/plan-turn-tools.js.map +1 -0
  380. package/dist/tools/prisma-schema-tools.d.ts +44 -0
  381. package/dist/tools/prisma-schema-tools.d.ts.map +1 -0
  382. package/dist/tools/prisma-schema-tools.js +358 -0
  383. package/dist/tools/prisma-schema-tools.js.map +1 -0
  384. package/dist/tools/project-tools.d.ts +116 -7
  385. package/dist/tools/project-tools.d.ts.map +1 -1
  386. package/dist/tools/project-tools.js +595 -218
  387. package/dist/tools/project-tools.js.map +1 -1
  388. package/dist/tools/pydantic-models.d.ts +46 -0
  389. package/dist/tools/pydantic-models.d.ts.map +1 -0
  390. package/dist/tools/pydantic-models.js +249 -0
  391. package/dist/tools/pydantic-models.js.map +1 -0
  392. package/dist/tools/pyproject-tools.d.ts +23 -0
  393. package/dist/tools/pyproject-tools.d.ts.map +1 -0
  394. package/dist/tools/pyproject-tools.js +133 -0
  395. package/dist/tools/pyproject-tools.js.map +1 -0
  396. package/dist/tools/pytest-tools.d.ts +20 -0
  397. package/dist/tools/pytest-tools.d.ts.map +1 -0
  398. package/dist/tools/pytest-tools.js +106 -0
  399. package/dist/tools/pytest-tools.js.map +1 -0
  400. package/dist/tools/python-audit.d.ts +40 -0
  401. package/dist/tools/python-audit.d.ts.map +1 -0
  402. package/dist/tools/python-audit.js +244 -0
  403. package/dist/tools/python-audit.js.map +1 -0
  404. package/dist/tools/python-callers.d.ts +28 -0
  405. package/dist/tools/python-callers.d.ts.map +1 -0
  406. package/dist/tools/python-callers.js +110 -0
  407. package/dist/tools/python-callers.js.map +1 -0
  408. package/dist/tools/python-circular-imports.d.ts +19 -0
  409. package/dist/tools/python-circular-imports.d.ts.map +1 -0
  410. package/dist/tools/python-circular-imports.js +126 -0
  411. package/dist/tools/python-circular-imports.js.map +1 -0
  412. package/dist/tools/python-constants-tools.d.ts +44 -0
  413. package/dist/tools/python-constants-tools.d.ts.map +1 -0
  414. package/dist/tools/python-constants-tools.js +525 -0
  415. package/dist/tools/python-constants-tools.js.map +1 -0
  416. package/dist/tools/python-deps-analyzer.d.ts +46 -0
  417. package/dist/tools/python-deps-analyzer.d.ts.map +1 -0
  418. package/dist/tools/python-deps-analyzer.js +227 -0
  419. package/dist/tools/python-deps-analyzer.js.map +1 -0
  420. package/dist/tools/query-tools.d.ts +23 -0
  421. package/dist/tools/query-tools.d.ts.map +1 -0
  422. package/dist/tools/query-tools.js +256 -0
  423. package/dist/tools/query-tools.js.map +1 -0
  424. package/dist/tools/react-tools.d.ts +263 -0
  425. package/dist/tools/react-tools.d.ts.map +1 -0
  426. package/dist/tools/react-tools.js +839 -0
  427. package/dist/tools/react-tools.js.map +1 -0
  428. package/dist/tools/report-tools.js +47 -0
  429. package/dist/tools/report-tools.js.map +1 -1
  430. package/dist/tools/review-diff-tools.d.ts +5 -4
  431. package/dist/tools/review-diff-tools.d.ts.map +1 -1
  432. package/dist/tools/review-diff-tools.js +157 -66
  433. package/dist/tools/review-diff-tools.js.map +1 -1
  434. package/dist/tools/room-tools.d.ts +36 -0
  435. package/dist/tools/room-tools.d.ts.map +1 -0
  436. package/dist/tools/room-tools.js +147 -0
  437. package/dist/tools/room-tools.js.map +1 -0
  438. package/dist/tools/route-tools.d.ts +27 -1
  439. package/dist/tools/route-tools.d.ts.map +1 -1
  440. package/dist/tools/route-tools.js +744 -18
  441. package/dist/tools/route-tools.js.map +1 -1
  442. package/dist/tools/ruff-tools.d.ts +32 -0
  443. package/dist/tools/ruff-tools.d.ts.map +1 -0
  444. package/dist/tools/ruff-tools.js +114 -0
  445. package/dist/tools/ruff-tools.js.map +1 -0
  446. package/dist/tools/search-ranker.d.ts.map +1 -1
  447. package/dist/tools/search-ranker.js +7 -0
  448. package/dist/tools/search-ranker.js.map +1 -1
  449. package/dist/tools/search-tools.d.ts +3 -2
  450. package/dist/tools/search-tools.d.ts.map +1 -1
  451. package/dist/tools/search-tools.js +16 -3
  452. package/dist/tools/search-tools.js.map +1 -1
  453. package/dist/tools/serialization-tools.d.ts +24 -0
  454. package/dist/tools/serialization-tools.d.ts.map +1 -0
  455. package/dist/tools/serialization-tools.js +156 -0
  456. package/dist/tools/serialization-tools.js.map +1 -0
  457. package/dist/tools/sql-tools.d.ts +274 -0
  458. package/dist/tools/sql-tools.d.ts.map +1 -0
  459. package/dist/tools/sql-tools.js +1160 -0
  460. package/dist/tools/sql-tools.js.map +1 -0
  461. package/dist/tools/status-tools.d.ts +10 -0
  462. package/dist/tools/status-tools.d.ts.map +1 -0
  463. package/dist/tools/status-tools.js +32 -0
  464. package/dist/tools/status-tools.js.map +1 -0
  465. package/dist/tools/symbol-tools.d.ts +19 -0
  466. package/dist/tools/symbol-tools.d.ts.map +1 -1
  467. package/dist/tools/symbol-tools.js +75 -4
  468. package/dist/tools/symbol-tools.js.map +1 -1
  469. package/dist/tools/taint-tools.d.ts +43 -0
  470. package/dist/tools/taint-tools.d.ts.map +1 -0
  471. package/dist/tools/taint-tools.js +922 -0
  472. package/dist/tools/taint-tools.js.map +1 -0
  473. package/dist/tools/test-impact-tools.d.ts +29 -0
  474. package/dist/tools/test-impact-tools.d.ts.map +1 -0
  475. package/dist/tools/test-impact-tools.js +156 -0
  476. package/dist/tools/test-impact-tools.js.map +1 -0
  477. package/dist/tools/typecheck-tools.d.ts +39 -0
  478. package/dist/tools/typecheck-tools.d.ts.map +1 -0
  479. package/dist/tools/typecheck-tools.js +191 -0
  480. package/dist/tools/typecheck-tools.js.map +1 -0
  481. package/dist/tools/wiring-tools.d.ts +19 -0
  482. package/dist/tools/wiring-tools.d.ts.map +1 -0
  483. package/dist/tools/wiring-tools.js +147 -0
  484. package/dist/tools/wiring-tools.js.map +1 -0
  485. package/dist/types.d.ts +9 -1
  486. package/dist/types.d.ts.map +1 -1
  487. package/dist/utils/framework-detect.d.ts +18 -2
  488. package/dist/utils/framework-detect.d.ts.map +1 -1
  489. package/dist/utils/framework-detect.js +150 -3
  490. package/dist/utils/framework-detect.js.map +1 -1
  491. package/dist/utils/import-graph.d.ts +42 -0
  492. package/dist/utils/import-graph.d.ts.map +1 -1
  493. package/dist/utils/import-graph.js +248 -9
  494. package/dist/utils/import-graph.js.map +1 -1
  495. package/dist/utils/language-detect.d.ts +21 -0
  496. package/dist/utils/language-detect.d.ts.map +1 -0
  497. package/dist/utils/language-detect.js +183 -0
  498. package/dist/utils/language-detect.js.map +1 -0
  499. package/dist/utils/nextjs-ast-readers.d.ts +44 -0
  500. package/dist/utils/nextjs-ast-readers.d.ts.map +1 -0
  501. package/dist/utils/nextjs-ast-readers.js +341 -0
  502. package/dist/utils/nextjs-ast-readers.js.map +1 -0
  503. package/dist/utils/nextjs-audit-cache.d.ts +51 -0
  504. package/dist/utils/nextjs-audit-cache.d.ts.map +1 -0
  505. package/dist/utils/nextjs-audit-cache.js +116 -0
  506. package/dist/utils/nextjs-audit-cache.js.map +1 -0
  507. package/dist/utils/nextjs-metadata-readers.d.ts +65 -0
  508. package/dist/utils/nextjs-metadata-readers.d.ts.map +1 -0
  509. package/dist/utils/nextjs-metadata-readers.js +447 -0
  510. package/dist/utils/nextjs-metadata-readers.js.map +1 -0
  511. package/dist/utils/nextjs.d.ts +42 -0
  512. package/dist/utils/nextjs.d.ts.map +1 -0
  513. package/dist/utils/nextjs.js +284 -0
  514. package/dist/utils/nextjs.js.map +1 -0
  515. package/dist/utils/python-import-resolver.d.ts +42 -0
  516. package/dist/utils/python-import-resolver.d.ts.map +1 -0
  517. package/dist/utils/python-import-resolver.js +101 -0
  518. package/dist/utils/python-import-resolver.js.map +1 -0
  519. package/dist/utils/python-imports.d.ts +28 -0
  520. package/dist/utils/python-imports.d.ts.map +1 -0
  521. package/dist/utils/python-imports.js +117 -0
  522. package/dist/utils/python-imports.js.map +1 -0
  523. package/dist/utils/react-alias.d.ts +15 -0
  524. package/dist/utils/react-alias.d.ts.map +1 -0
  525. package/dist/utils/react-alias.js +31 -0
  526. package/dist/utils/react-alias.js.map +1 -0
  527. package/dist/utils/test-file.d.ts.map +1 -1
  528. package/dist/utils/test-file.js +7 -0
  529. package/dist/utils/test-file.js.map +1 -1
  530. package/dist/utils/walk.d.ts +22 -0
  531. package/dist/utils/walk.d.ts.map +1 -1
  532. package/dist/utils/walk.js +70 -2
  533. package/dist/utils/walk.js.map +1 -1
  534. package/package.json +4 -3
  535. package/rules/codesift.md +71 -5
  536. package/rules/codesift.mdc +71 -5
  537. package/rules/codex.md +71 -5
  538. package/rules/gemini.md +71 -5
  539. package/src/parser/languages/tree-sitter-javascript.wasm +0 -0
  540. package/src/parser/languages/tree-sitter-kotlin.wasm +0 -0
  541. package/src/parser/languages/tree-sitter-php.wasm +0 -0
  542. package/src/parser/languages/tree-sitter-php_only.wasm +0 -0
  543. package/src/parser/languages/tree-sitter-python.wasm +0 -0
@@ -0,0 +1,922 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { getParser } from "../parser/parser-manager.js";
4
+ import { detectSrcLayout, resolvePythonImport } from "../utils/python-import-resolver.js";
5
+ import { getCodeIndex } from "./index-tools.js";
6
+ const DEFAULT_MAX_DEPTH = 4;
7
+ const DEFAULT_MAX_TRACES = 50;
8
+ const DEFAULT_SOURCE_PATTERNS = [
9
+ "request.GET",
10
+ "request.POST",
11
+ "request.body",
12
+ "request.data",
13
+ "request.headers",
14
+ "request.COOKIES",
15
+ "request.META",
16
+ ];
17
+ const DEFAULT_SINK_PATTERNS = [
18
+ "redirect",
19
+ "mark_safe",
20
+ "cursor.execute",
21
+ "subprocess",
22
+ "requests",
23
+ "httpx",
24
+ "open",
25
+ "session-write",
26
+ ];
27
+ const KNOWN_SANITIZERS = new Set([
28
+ "escape",
29
+ "conditional_escape",
30
+ "urlquote",
31
+ "quote",
32
+ "quote_plus",
33
+ ]);
34
+ function clonePath(path) {
35
+ return {
36
+ source: { ...path.source },
37
+ hops: path.hops.map((hop) => ({ ...hop })),
38
+ heuristic: path.heuristic,
39
+ };
40
+ }
41
+ function pathKey(path) {
42
+ return JSON.stringify({
43
+ source: path.source,
44
+ hops: path.hops,
45
+ heuristic: path.heuristic,
46
+ });
47
+ }
48
+ function dedupePaths(paths) {
49
+ const seen = new Set();
50
+ const result = [];
51
+ for (const path of paths) {
52
+ const key = pathKey(path);
53
+ if (seen.has(key))
54
+ continue;
55
+ seen.add(key);
56
+ result.push(path);
57
+ }
58
+ return result;
59
+ }
60
+ function cloneEnv(env) {
61
+ const next = new Map();
62
+ for (const [name, paths] of env.entries()) {
63
+ next.set(name, paths.map(clonePath));
64
+ }
65
+ return next;
66
+ }
67
+ function mergeEnvs(...envs) {
68
+ const merged = new Map();
69
+ for (const env of envs) {
70
+ for (const [name, paths] of env.entries()) {
71
+ const existing = merged.get(name) ?? [];
72
+ merged.set(name, dedupePaths([...existing, ...paths.map(clonePath)]));
73
+ }
74
+ }
75
+ return merged;
76
+ }
77
+ function appendHop(paths, hop, options) {
78
+ return dedupePaths(paths.map((path) => ({
79
+ source: { ...path.source },
80
+ hops: [...path.hops.map((entry) => ({ ...entry })), { ...hop }],
81
+ heuristic: path.heuristic || Boolean(options?.heuristic),
82
+ })));
83
+ }
84
+ function computeConfidence(path) {
85
+ if (path.heuristic)
86
+ return "medium";
87
+ if (path.hops.length >= 4)
88
+ return "medium";
89
+ return "high";
90
+ }
91
+ function lineForNode(symbol, node) {
92
+ return symbol.start_line + node.startPosition.row;
93
+ }
94
+ function codeForNode(node) {
95
+ return node.text.split("\n")[0]?.trim() ?? node.text.trim();
96
+ }
97
+ function getAttributePath(node) {
98
+ if (!node)
99
+ return null;
100
+ if (node.type === "identifier")
101
+ return node.text;
102
+ if (node.type === "attribute") {
103
+ const objectNode = node.childForFieldName("object") ?? node.namedChild(0);
104
+ const attributeNode = node.childForFieldName("attribute") ?? node.namedChild(1);
105
+ const objectPath = getAttributePath(objectNode);
106
+ const attributePath = getAttributePath(attributeNode);
107
+ if (!objectPath || !attributePath)
108
+ return null;
109
+ return `${objectPath}.${attributePath}`;
110
+ }
111
+ return null;
112
+ }
113
+ function getCallArguments(argsNode) {
114
+ if (!argsNode)
115
+ return [];
116
+ const args = [];
117
+ let index = 0;
118
+ for (const child of argsNode.namedChildren) {
119
+ if (child.type === "keyword_argument") {
120
+ const keywordNode = child.namedChildren[0];
121
+ const valueNode = child.namedChildren[1];
122
+ if (!valueNode)
123
+ continue;
124
+ const arg = {
125
+ node: valueNode,
126
+ index,
127
+ };
128
+ if (keywordNode?.text)
129
+ arg.keyword = keywordNode.text;
130
+ args.push(arg);
131
+ index += 1;
132
+ continue;
133
+ }
134
+ args.push({
135
+ node: child,
136
+ index,
137
+ });
138
+ index += 1;
139
+ }
140
+ return args;
141
+ }
142
+ function getParameterName(node) {
143
+ switch (node.type) {
144
+ case "identifier":
145
+ return node.text;
146
+ case "default_parameter":
147
+ case "typed_parameter":
148
+ case "typed_default_parameter":
149
+ case "list_splat_pattern":
150
+ case "dictionary_splat_pattern":
151
+ return node.namedChildren[0]?.text ?? null;
152
+ default:
153
+ return null;
154
+ }
155
+ }
156
+ function findFunctionNode(node) {
157
+ if (node.type === "function_definition" || node.type === "async_function_definition") {
158
+ return node;
159
+ }
160
+ for (const child of node.namedChildren) {
161
+ const found = findFunctionNode(child);
162
+ if (found)
163
+ return found;
164
+ }
165
+ return null;
166
+ }
167
+ function createSourcePath(sourceKind, symbol, node) {
168
+ return {
169
+ source: {
170
+ kind: sourceKind,
171
+ label: node.text,
172
+ file: symbol.file,
173
+ line: lineForNode(symbol, node),
174
+ symbol_name: symbol.name,
175
+ code: codeForNode(node),
176
+ },
177
+ hops: [],
178
+ heuristic: false,
179
+ };
180
+ }
181
+ function identifierPaths(env, name) {
182
+ return (env.get(name) ?? []).map(clonePath);
183
+ }
184
+ function isAllowedPattern(allowed, kind, label) {
185
+ if (allowed.length === 0)
186
+ return true;
187
+ return allowed.some((pattern) => pattern === kind
188
+ || label === pattern
189
+ || label.includes(pattern)
190
+ || kind.includes(pattern));
191
+ }
192
+ function buildSinkDescriptors() {
193
+ return [
194
+ {
195
+ kind: "redirect",
196
+ matches: (calleeText) => calleeText === "redirect"
197
+ || calleeText.endsWith(".redirect")
198
+ || calleeText === "HttpResponseRedirect"
199
+ || calleeText === "HttpResponsePermanentRedirect",
200
+ pickArgs: (args) => args[0] ? [args[0]] : [],
201
+ },
202
+ {
203
+ kind: "mark_safe",
204
+ matches: (calleeText) => calleeText === "mark_safe" || calleeText.endsWith(".mark_safe"),
205
+ pickArgs: (args) => args[0] ? [args[0]] : [],
206
+ },
207
+ {
208
+ kind: "cursor.execute",
209
+ matches: (calleeText) => calleeText === "cursor.execute" || calleeText.endsWith(".execute"),
210
+ pickArgs: (args) => args[0] ? [args[0]] : [],
211
+ },
212
+ {
213
+ kind: "subprocess",
214
+ matches: (calleeText) => calleeText.startsWith("subprocess.")
215
+ || calleeText.endsWith(".Popen")
216
+ || calleeText.endsWith(".run")
217
+ || calleeText.endsWith(".call")
218
+ || calleeText.endsWith(".check_call")
219
+ || calleeText.endsWith(".check_output"),
220
+ pickArgs: (args) => args[0] ? [args[0]] : [],
221
+ },
222
+ {
223
+ kind: "requests",
224
+ matches: (calleeText) => calleeText.startsWith("requests.")
225
+ || calleeText.includes(".requests.")
226
+ || calleeText.startsWith("httpx.")
227
+ || calleeText.includes(".httpx."),
228
+ pickArgs: (args) => {
229
+ if (args.length === 0)
230
+ return [];
231
+ const urlKeyword = args.find((arg) => arg.keyword === "url");
232
+ if (urlKeyword)
233
+ return [urlKeyword];
234
+ return args[1] ? [args[1]] : [args[0]];
235
+ },
236
+ },
237
+ {
238
+ kind: "httpx",
239
+ matches: (calleeText) => calleeText.startsWith("httpx.")
240
+ || calleeText.includes(".httpx."),
241
+ pickArgs: (args) => {
242
+ if (args.length === 0)
243
+ return [];
244
+ const urlKeyword = args.find((arg) => arg.keyword === "url");
245
+ if (urlKeyword)
246
+ return [urlKeyword];
247
+ return args[1] ? [args[1]] : [args[0]];
248
+ },
249
+ },
250
+ {
251
+ kind: "open",
252
+ matches: (calleeText) => calleeText === "open" || calleeText.endsWith(".open"),
253
+ pickArgs: (args) => args[0] ? [args[0]] : [],
254
+ },
255
+ ];
256
+ }
257
+ function getImportModule(node) {
258
+ const moduleNode = node.childForFieldName("module_name");
259
+ if (!moduleNode)
260
+ return { module: "", level: 0 };
261
+ if (moduleNode.type === "relative_import") {
262
+ let level = 0;
263
+ for (let i = 0; i < moduleNode.childCount; i++) {
264
+ const child = moduleNode.child(i);
265
+ if (!child)
266
+ continue;
267
+ if (child.type === "import_prefix") {
268
+ level += (child.text.match(/\./g) ?? []).length;
269
+ }
270
+ else if (child.type === ".") {
271
+ level += 1;
272
+ }
273
+ }
274
+ const dotted = moduleNode.namedChildren.find((child) => child.type === "dotted_name");
275
+ return { module: dotted?.text ?? "", level };
276
+ }
277
+ return { module: moduleNode.text, level: 0 };
278
+ }
279
+ async function loadFileContext(state, filePath) {
280
+ const cached = state.fileContextCache.get(filePath);
281
+ if (cached !== undefined)
282
+ return cached;
283
+ let source;
284
+ try {
285
+ source = await readFile(join(state.index.root, filePath), "utf-8");
286
+ }
287
+ catch {
288
+ state.fileContextCache.set(filePath, null);
289
+ return null;
290
+ }
291
+ const tree = state.pythonParser.parse(source);
292
+ const files = state.index.files.map((entry) => entry.path);
293
+ const srcLayout = detectSrcLayout(files);
294
+ const imports = new Map();
295
+ for (const node of tree.rootNode.namedChildren) {
296
+ if (node.type !== "import_from_statement")
297
+ continue;
298
+ const { module, level } = getImportModule(node);
299
+ const resolvedFile = resolvePythonImport({ module, level }, filePath, files, srcLayout);
300
+ if (!resolvedFile)
301
+ continue;
302
+ for (const child of node.namedChildren) {
303
+ if (child.type === "aliased_import") {
304
+ const importedNode = child.namedChildren[0];
305
+ const aliasNode = child.namedChildren[1];
306
+ if (importedNode && aliasNode) {
307
+ imports.set(aliasNode.text, {
308
+ imported_name: importedNode.text,
309
+ source_file: resolvedFile,
310
+ line: node.startPosition.row + 1,
311
+ });
312
+ }
313
+ continue;
314
+ }
315
+ if (child.type === "dotted_name") {
316
+ const importedName = child.text;
317
+ const localName = importedName.split(".").pop() ?? importedName;
318
+ imports.set(localName, {
319
+ imported_name: importedName,
320
+ source_file: resolvedFile,
321
+ line: node.startPosition.row + 1,
322
+ });
323
+ }
324
+ }
325
+ }
326
+ const context = { imports };
327
+ state.fileContextCache.set(filePath, context);
328
+ return context;
329
+ }
330
+ function hasPotentialSource(symbol) {
331
+ return symbol.source?.includes("request.") ?? false;
332
+ }
333
+ function hasPotentialSink(symbol) {
334
+ const source = symbol.source ?? "";
335
+ return source.includes("mark_safe")
336
+ || source.includes("redirect(")
337
+ || source.includes(".execute(")
338
+ || source.includes("subprocess.")
339
+ || source.includes("requests.")
340
+ || source.includes("httpx.")
341
+ || source.includes("open(")
342
+ || source.includes("request.session");
343
+ }
344
+ async function loadCallableContext(symbol, state) {
345
+ const cached = state.callableCache.get(symbol.id);
346
+ if (cached !== undefined)
347
+ return cached;
348
+ if (!symbol.source) {
349
+ state.callableCache.set(symbol.id, null);
350
+ return null;
351
+ }
352
+ const tree = state.pythonParser.parse(symbol.source);
353
+ const functionNode = findFunctionNode(tree.rootNode);
354
+ if (!functionNode) {
355
+ state.callableCache.set(symbol.id, null);
356
+ return null;
357
+ }
358
+ const paramsNode = functionNode.childForFieldName("parameters");
359
+ const parameterNames = paramsNode
360
+ ? paramsNode.namedChildren
361
+ .map(getParameterName)
362
+ .filter((name) => Boolean(name))
363
+ : [];
364
+ const context = {
365
+ node: functionNode,
366
+ parameter_names: parameterNames,
367
+ };
368
+ state.callableCache.set(symbol.id, context);
369
+ return context;
370
+ }
371
+ function resolveSelfMethod(currentSymbol, propertyName, state) {
372
+ if (!currentSymbol.parent)
373
+ return null;
374
+ const methods = state.methodsByParent.get(currentSymbol.parent) ?? [];
375
+ return methods.find((symbol) => symbol.name === propertyName) ?? null;
376
+ }
377
+ async function resolveHelperTarget(currentSymbol, calleeNode, state) {
378
+ const calleeText = getAttributePath(calleeNode) ?? calleeNode.text;
379
+ if (calleeNode.type === "identifier") {
380
+ const sameFile = (state.symbolsByName.get(calleeText) ?? [])
381
+ .filter((symbol) => symbol.file === currentSymbol.file
382
+ && symbol.id !== currentSymbol.id
383
+ && (symbol.kind === "function" || symbol.kind === "class" || symbol.kind === "method"));
384
+ if (sameFile.length === 1)
385
+ return sameFile[0];
386
+ const fileContext = await loadFileContext(state, currentSymbol.file);
387
+ const imported = fileContext?.imports.get(calleeText);
388
+ if (imported) {
389
+ const importedMatch = (state.symbolsByName.get(imported.imported_name) ?? [])
390
+ .find((symbol) => symbol.file === imported.source_file);
391
+ if (importedMatch)
392
+ return importedMatch;
393
+ }
394
+ const unique = (state.symbolsByName.get(calleeText) ?? [])
395
+ .filter((symbol) => symbol.file.endsWith(".py") && symbol.id !== currentSymbol.id)
396
+ .filter((symbol) => symbol.kind === "function" || symbol.kind === "method" || symbol.kind === "class");
397
+ if (unique.length === 1)
398
+ return unique[0];
399
+ return null;
400
+ }
401
+ if (calleeNode.type === "attribute") {
402
+ const objectNode = calleeNode.childForFieldName("object") ?? calleeNode.namedChild(0);
403
+ const propertyNode = calleeNode.childForFieldName("attribute") ?? calleeNode.namedChild(1);
404
+ const objectName = getAttributePath(objectNode);
405
+ const propertyName = propertyNode?.text;
406
+ if ((objectName === "self" || objectName === "cls") && propertyName) {
407
+ return resolveSelfMethod(currentSymbol, propertyName, state);
408
+ }
409
+ const importedModule = objectName ? (await loadFileContext(state, currentSymbol.file))?.imports.get(objectName) : null;
410
+ if (importedModule && propertyName) {
411
+ const candidates = state.symbolsByName.get(propertyName) ?? [];
412
+ const importedMatch = candidates.find((symbol) => symbol.file === importedModule.source_file);
413
+ if (importedMatch)
414
+ return importedMatch;
415
+ }
416
+ }
417
+ return null;
418
+ }
419
+ function matchesRequestSource(attributePath) {
420
+ if (!attributePath)
421
+ return null;
422
+ if (attributePath === "request.GET" || attributePath.startsWith("request.GET."))
423
+ return "request.GET";
424
+ if (attributePath === "request.POST" || attributePath.startsWith("request.POST."))
425
+ return "request.POST";
426
+ if (attributePath === "request.body")
427
+ return "request.body";
428
+ if (attributePath === "request.data" || attributePath.startsWith("request.data."))
429
+ return "request.data";
430
+ if (attributePath === "request.headers" || attributePath.startsWith("request.headers."))
431
+ return "request.headers";
432
+ if (attributePath === "request.COOKIES" || attributePath.startsWith("request.COOKIES."))
433
+ return "request.COOKIES";
434
+ if (attributePath === "request.META" || attributePath.startsWith("request.META."))
435
+ return "request.META";
436
+ return null;
437
+ }
438
+ function isSessionTarget(node) {
439
+ if (node.type === "attribute") {
440
+ const path = getAttributePath(node);
441
+ return path === "request.session";
442
+ }
443
+ if (node.type === "subscript") {
444
+ const base = node.childForFieldName("value") ?? node.namedChild(0);
445
+ return getAttributePath(base) === "request.session";
446
+ }
447
+ return false;
448
+ }
449
+ function sinkTraceKey(trace) {
450
+ return JSON.stringify({
451
+ entry_symbol: trace.entry_symbol,
452
+ entry_file: trace.entry_file,
453
+ source: trace.source,
454
+ sink: trace.sink,
455
+ hops: trace.hops,
456
+ heuristic: trace.heuristic,
457
+ });
458
+ }
459
+ function addTrace(state, entrySymbol, currentSymbol, sinkKind, sinkNode, paths) {
460
+ if (state.truncated)
461
+ return;
462
+ for (const path of paths) {
463
+ if (state.traces.length >= state.maxTraces) {
464
+ state.truncated = true;
465
+ return;
466
+ }
467
+ const trace = {
468
+ entry_symbol: entrySymbol.name,
469
+ entry_file: entrySymbol.file,
470
+ source: { ...path.source },
471
+ sink: {
472
+ kind: sinkKind,
473
+ label: sinkNode.text,
474
+ file: currentSymbol.file,
475
+ line: lineForNode(currentSymbol, sinkNode),
476
+ symbol_name: currentSymbol.name,
477
+ code: codeForNode(sinkNode),
478
+ },
479
+ hops: path.hops.map((hop) => ({ ...hop })),
480
+ confidence: computeConfidence(path),
481
+ heuristic: path.heuristic,
482
+ };
483
+ const key = sinkTraceKey(trace);
484
+ if (state.traceKeys.has(key))
485
+ continue;
486
+ state.traceKeys.add(key);
487
+ state.traces.push(trace);
488
+ }
489
+ }
490
+ async function evaluateExpression(node, symbol, env, state, context) {
491
+ switch (node.type) {
492
+ case "identifier":
493
+ return identifierPaths(env, node.text);
494
+ case "attribute": {
495
+ const sourceKind = matchesRequestSource(getAttributePath(node));
496
+ if (sourceKind)
497
+ return [createSourcePath(sourceKind, symbol, node)];
498
+ const objectNode = node.childForFieldName("object") ?? node.namedChild(0);
499
+ if (!objectNode)
500
+ return [];
501
+ const basePaths = await evaluateExpression(objectNode, symbol, env, state, context);
502
+ if (basePaths.length === 0)
503
+ return [];
504
+ return appendHop(basePaths, {
505
+ kind: "attribute",
506
+ file: symbol.file,
507
+ line: lineForNode(symbol, node),
508
+ symbol_name: symbol.name,
509
+ detail: `attribute access ${node.text}`,
510
+ });
511
+ }
512
+ case "subscript": {
513
+ const baseNode = node.childForFieldName("value") ?? node.namedChild(0);
514
+ const sourceKind = matchesRequestSource(getAttributePath(baseNode));
515
+ if (sourceKind)
516
+ return [createSourcePath(sourceKind, symbol, node)];
517
+ const basePaths = baseNode
518
+ ? await evaluateExpression(baseNode, symbol, env, state, context)
519
+ : [];
520
+ if (basePaths.length === 0)
521
+ return [];
522
+ return appendHop(basePaths, {
523
+ kind: "container",
524
+ file: symbol.file,
525
+ line: lineForNode(symbol, node),
526
+ symbol_name: symbol.name,
527
+ detail: `container access ${node.text}`,
528
+ });
529
+ }
530
+ case "string": {
531
+ const interpolated = node.namedChildren
532
+ .filter((child) => child.type === "interpolation")
533
+ .flatMap((child) => child.namedChildren);
534
+ if (interpolated.length === 0)
535
+ return [];
536
+ const paths = [];
537
+ for (const child of interpolated) {
538
+ paths.push(...await evaluateExpression(child, symbol, env, state, context));
539
+ }
540
+ if (paths.length === 0)
541
+ return [];
542
+ return appendHop(paths, {
543
+ kind: "container",
544
+ file: symbol.file,
545
+ line: lineForNode(symbol, node),
546
+ symbol_name: symbol.name,
547
+ detail: `formatted string ${node.text}`,
548
+ });
549
+ }
550
+ case "list":
551
+ case "tuple":
552
+ case "dictionary":
553
+ case "set": {
554
+ const paths = [];
555
+ for (const child of node.namedChildren) {
556
+ if (child.type === "pair") {
557
+ const valueNode = child.namedChildren[1];
558
+ if (!valueNode)
559
+ continue;
560
+ paths.push(...await evaluateExpression(valueNode, symbol, env, state, context));
561
+ }
562
+ else {
563
+ paths.push(...await evaluateExpression(child, symbol, env, state, context));
564
+ }
565
+ }
566
+ if (paths.length === 0)
567
+ return [];
568
+ return appendHop(paths, {
569
+ kind: "container",
570
+ file: symbol.file,
571
+ line: lineForNode(symbol, node),
572
+ symbol_name: symbol.name,
573
+ detail: `container literal ${node.text}`,
574
+ });
575
+ }
576
+ case "binary_operator":
577
+ case "boolean_operator":
578
+ case "comparison_operator": {
579
+ const paths = [];
580
+ for (const child of node.namedChildren) {
581
+ paths.push(...await evaluateExpression(child, symbol, env, state, context));
582
+ }
583
+ return dedupePaths(paths);
584
+ }
585
+ case "parenthesized_expression":
586
+ return node.namedChildren[0]
587
+ ? await evaluateExpression(node.namedChildren[0], symbol, env, state, context)
588
+ : [];
589
+ case "conditional_expression": {
590
+ const paths = [];
591
+ for (const child of node.namedChildren) {
592
+ paths.push(...await evaluateExpression(child, symbol, env, state, context));
593
+ }
594
+ return dedupePaths(paths);
595
+ }
596
+ case "call": {
597
+ const calleeNode = node.childForFieldName("function") ?? node.namedChild(0);
598
+ const argsNode = node.childForFieldName("arguments") ?? node.namedChild(1);
599
+ const callArgs = getCallArguments(argsNode);
600
+ const calleeText = getAttributePath(calleeNode) ?? calleeNode?.text ?? "";
601
+ const sourceKind = matchesRequestSource(calleeText);
602
+ if (sourceKind && calleeText.endsWith(".get")) {
603
+ return [createSourcePath(sourceKind, symbol, node)];
604
+ }
605
+ const evaluatedArgs = await Promise.all(callArgs.map(async (arg) => ({
606
+ arg,
607
+ paths: await evaluateExpression(arg.node, symbol, env, state, context),
608
+ })));
609
+ for (const descriptor of state.sinkDescriptors) {
610
+ if (!descriptor.matches(calleeText))
611
+ continue;
612
+ if (!isAllowedPattern(state.defaultSinks, descriptor.kind, calleeText))
613
+ continue;
614
+ const selectedArgs = descriptor.pickArgs(callArgs);
615
+ const taintedArgs = selectedArgs.flatMap((selected) => evaluatedArgs
616
+ .filter((entry) => entry.arg.index === selected.index)
617
+ .flatMap((entry) => entry.paths));
618
+ if (taintedArgs.length > 0) {
619
+ addTrace(state, context.entrySymbol, symbol, descriptor.kind, node, dedupePaths(taintedArgs));
620
+ }
621
+ }
622
+ const calleeLeaf = calleeText.split(".").pop() ?? calleeText;
623
+ if (KNOWN_SANITIZERS.has(calleeLeaf))
624
+ return [];
625
+ const taintedInputs = evaluatedArgs
626
+ .filter((entry) => entry.paths.length > 0)
627
+ .map((entry) => entry);
628
+ if (taintedInputs.length === 0)
629
+ return [];
630
+ const helperTarget = calleeNode
631
+ ? await resolveHelperTarget(symbol, calleeNode, state)
632
+ : null;
633
+ if (helperTarget && context.depth < state.maxDepth && !context.callStack.includes(helperTarget.id)) {
634
+ const helperContext = await loadCallableContext(helperTarget, state);
635
+ if (helperContext) {
636
+ const helperEnv = new Map();
637
+ for (const entry of taintedInputs) {
638
+ const paramName = helperContext.parameter_names[entry.arg.index];
639
+ if (!paramName)
640
+ continue;
641
+ helperEnv.set(paramName, appendHop(entry.paths, {
642
+ kind: "call",
643
+ file: symbol.file,
644
+ line: lineForNode(symbol, node),
645
+ symbol_name: symbol.name,
646
+ detail: `call ${calleeText} -> parameter ${paramName}`,
647
+ }));
648
+ }
649
+ const helperResult = await analyzeCallableSymbol(helperTarget, helperEnv, state, {
650
+ entrySymbol: context.entrySymbol,
651
+ depth: context.depth + 1,
652
+ callStack: [...context.callStack, helperTarget.id],
653
+ });
654
+ if (helperResult.return_paths.length > 0) {
655
+ return appendHop(helperResult.return_paths, {
656
+ kind: "call",
657
+ file: symbol.file,
658
+ line: lineForNode(symbol, node),
659
+ symbol_name: symbol.name,
660
+ detail: `return from ${calleeText}`,
661
+ });
662
+ }
663
+ return [];
664
+ }
665
+ }
666
+ return appendHop(taintedInputs.flatMap((entry) => entry.paths), {
667
+ kind: "call",
668
+ file: symbol.file,
669
+ line: lineForNode(symbol, node),
670
+ symbol_name: symbol.name,
671
+ detail: `heuristic propagation through ${calleeText}`,
672
+ }, { heuristic: true });
673
+ }
674
+ default:
675
+ return [];
676
+ }
677
+ }
678
+ async function analyzeAssignment(assignmentNode, symbol, env, state, context) {
679
+ const lhs = assignmentNode.childForFieldName("left") ?? assignmentNode.namedChild(0);
680
+ const rhs = assignmentNode.childForFieldName("right") ?? assignmentNode.namedChild(1);
681
+ const nextEnv = cloneEnv(env);
682
+ if (!lhs || !rhs)
683
+ return nextEnv;
684
+ const rhsPaths = await evaluateExpression(rhs, symbol, env, state, context);
685
+ if (rhsPaths.length === 0)
686
+ return nextEnv;
687
+ if (lhs.type === "identifier") {
688
+ nextEnv.set(lhs.text, appendHop(rhsPaths, {
689
+ kind: "assignment",
690
+ file: symbol.file,
691
+ line: lineForNode(symbol, assignmentNode),
692
+ symbol_name: symbol.name,
693
+ detail: `${lhs.text} = ${rhs.text}`,
694
+ }));
695
+ return nextEnv;
696
+ }
697
+ if (isSessionTarget(lhs) && isAllowedPattern(state.defaultSinks, "session-write", lhs.text)) {
698
+ addTrace(state, context.entrySymbol, symbol, "session-write", assignmentNode, rhsPaths);
699
+ }
700
+ return nextEnv;
701
+ }
702
+ async function analyzeConditionalLike(node, symbol, env, state, context) {
703
+ const conditionNodes = node.namedChildren.filter((child) => child.type !== "block" && child.type !== "else_clause" && child.type !== "elif_clause");
704
+ for (const condition of conditionNodes) {
705
+ await evaluateExpression(condition, symbol, env, state, context);
706
+ }
707
+ const branchResults = [];
708
+ let hasElseLike = false;
709
+ for (const child of node.namedChildren) {
710
+ if (child.type === "block") {
711
+ branchResults.push(await analyzeBlock(child, symbol, cloneEnv(env), state, context));
712
+ continue;
713
+ }
714
+ if (child.type === "elif_clause") {
715
+ hasElseLike = true;
716
+ branchResults.push(await analyzeConditionalLike(child, symbol, cloneEnv(env), state, context));
717
+ continue;
718
+ }
719
+ if (child.type === "else_clause") {
720
+ hasElseLike = true;
721
+ const elseBlock = child.namedChildren.find((grandchild) => grandchild.type === "block");
722
+ if (elseBlock)
723
+ branchResults.push(await analyzeBlock(elseBlock, symbol, cloneEnv(env), state, context));
724
+ }
725
+ }
726
+ const baseEnvs = hasElseLike ? [] : [env];
727
+ return {
728
+ env: mergeEnvs(...baseEnvs, ...branchResults.map((entry) => entry.env)),
729
+ return_paths: dedupePaths(branchResults.flatMap((entry) => entry.return_paths)),
730
+ };
731
+ }
732
+ async function analyzeLoopLike(node, symbol, env, state, context) {
733
+ for (const child of node.namedChildren) {
734
+ if (child.type === "block")
735
+ continue;
736
+ await evaluateExpression(child, symbol, env, state, context);
737
+ }
738
+ const blockResults = [];
739
+ for (const child of node.namedChildren) {
740
+ if (child.type !== "block")
741
+ continue;
742
+ blockResults.push(await analyzeBlock(child, symbol, cloneEnv(env), state, context));
743
+ }
744
+ return {
745
+ env: mergeEnvs(env, ...blockResults.map((entry) => entry.env)),
746
+ return_paths: dedupePaths(blockResults.flatMap((entry) => entry.return_paths)),
747
+ };
748
+ }
749
+ async function analyzeStatement(node, symbol, env, state, context) {
750
+ switch (node.type) {
751
+ case "expression_statement": {
752
+ const inner = node.namedChildren[0];
753
+ if (!inner)
754
+ return { env, return_paths: [] };
755
+ if (inner.type === "assignment") {
756
+ return {
757
+ env: await analyzeAssignment(inner, symbol, env, state, context),
758
+ return_paths: [],
759
+ };
760
+ }
761
+ await evaluateExpression(inner, symbol, env, state, context);
762
+ return { env, return_paths: [] };
763
+ }
764
+ case "return_statement": {
765
+ const valueNode = node.namedChildren[0];
766
+ if (!valueNode)
767
+ return { env, return_paths: [] };
768
+ const valuePaths = await evaluateExpression(valueNode, symbol, env, state, context);
769
+ if (valuePaths.length === 0)
770
+ return { env, return_paths: [] };
771
+ return {
772
+ env,
773
+ return_paths: appendHop(valuePaths, {
774
+ kind: "return",
775
+ file: symbol.file,
776
+ line: lineForNode(symbol, node),
777
+ symbol_name: symbol.name,
778
+ detail: `return ${valueNode.text}`,
779
+ }),
780
+ };
781
+ }
782
+ case "if_statement":
783
+ case "elif_clause":
784
+ return await analyzeConditionalLike(node, symbol, env, state, context);
785
+ case "for_statement":
786
+ case "while_statement":
787
+ case "with_statement":
788
+ case "try_statement":
789
+ return await analyzeLoopLike(node, symbol, env, state, context);
790
+ case "pass_statement":
791
+ case "break_statement":
792
+ case "continue_statement":
793
+ return { env, return_paths: [] };
794
+ case "function_definition":
795
+ case "async_function_definition":
796
+ case "class_definition":
797
+ case "decorated_definition":
798
+ return { env, return_paths: [] };
799
+ default: {
800
+ for (const child of node.namedChildren) {
801
+ if (child.type === "block") {
802
+ await analyzeBlock(child, symbol, cloneEnv(env), state, context);
803
+ }
804
+ else {
805
+ await evaluateExpression(child, symbol, env, state, context);
806
+ }
807
+ }
808
+ return { env, return_paths: [] };
809
+ }
810
+ }
811
+ }
812
+ async function analyzeBlock(blockNode, symbol, env, state, context) {
813
+ let currentEnv = cloneEnv(env);
814
+ let returnPaths = [];
815
+ for (const child of blockNode.namedChildren) {
816
+ if (state.truncated)
817
+ break;
818
+ const result = await analyzeStatement(child, symbol, currentEnv, state, context);
819
+ currentEnv = result.env;
820
+ if (result.return_paths.length > 0) {
821
+ returnPaths = dedupePaths([...returnPaths, ...result.return_paths]);
822
+ }
823
+ }
824
+ return {
825
+ env: currentEnv,
826
+ return_paths: returnPaths,
827
+ };
828
+ }
829
+ async function analyzeCallableSymbol(symbol, initialEnv, state, context) {
830
+ const callableContext = await loadCallableContext(symbol, state);
831
+ if (!callableContext) {
832
+ return { env: initialEnv, return_paths: [] };
833
+ }
834
+ const bodyNode = callableContext.node.childForFieldName("body");
835
+ if (!bodyNode) {
836
+ return { env: initialEnv, return_paths: [] };
837
+ }
838
+ return await analyzeBlock(bodyNode, symbol, initialEnv, state, context);
839
+ }
840
+ function shouldAnalyzeSymbol(symbol, filePattern) {
841
+ if (!symbol.file.endsWith(".py"))
842
+ return false;
843
+ if (filePattern && !symbol.file.includes(filePattern))
844
+ return false;
845
+ if (!symbol.source)
846
+ return false;
847
+ if (symbol.kind !== "function" && symbol.kind !== "method")
848
+ return false;
849
+ return hasPotentialSource(symbol) || hasPotentialSink(symbol);
850
+ }
851
+ function buildState(index, pythonParser, options) {
852
+ const symbolsByName = new Map();
853
+ const methodsByParent = new Map();
854
+ for (const symbol of index.symbols) {
855
+ const named = symbolsByName.get(symbol.name) ?? [];
856
+ named.push(symbol);
857
+ symbolsByName.set(symbol.name, named);
858
+ if (symbol.parent && symbol.kind === "method") {
859
+ const methods = methodsByParent.get(symbol.parent) ?? [];
860
+ methods.push(symbol);
861
+ methodsByParent.set(symbol.parent, methods);
862
+ }
863
+ }
864
+ return {
865
+ index,
866
+ pythonParser,
867
+ symbolsByName,
868
+ methodsByParent,
869
+ callableCache: new Map(),
870
+ fileContextCache: new Map(),
871
+ defaultSources: options?.source_patterns?.length
872
+ ? [...options.source_patterns]
873
+ : [...DEFAULT_SOURCE_PATTERNS],
874
+ defaultSinks: options?.sink_patterns?.length
875
+ ? [...options.sink_patterns]
876
+ : [...DEFAULT_SINK_PATTERNS],
877
+ maxDepth: options?.max_depth ?? DEFAULT_MAX_DEPTH,
878
+ maxTraces: options?.max_traces ?? DEFAULT_MAX_TRACES,
879
+ sinkDescriptors: buildSinkDescriptors(),
880
+ traceKeys: new Set(),
881
+ traces: [],
882
+ truncated: false,
883
+ };
884
+ }
885
+ export async function taintTrace(repo, options) {
886
+ const framework = options?.framework ?? "python-django";
887
+ if (framework !== "python-django") {
888
+ throw new Error(`taint_trace is not implemented for framework "${framework}" yet.`);
889
+ }
890
+ const index = await getCodeIndex(repo);
891
+ if (!index) {
892
+ throw new Error(`Repository "${repo}" not found.`);
893
+ }
894
+ const pythonParser = await getParser("python");
895
+ if (!pythonParser) {
896
+ throw new Error("Python parser unavailable");
897
+ }
898
+ const state = buildState(index, pythonParser, options);
899
+ const candidates = index.symbols
900
+ .filter((symbol) => shouldAnalyzeSymbol(symbol, options?.file_pattern))
901
+ .sort((a, b) => a.file.localeCompare(b.file) || a.start_line - b.start_line);
902
+ for (const symbol of candidates) {
903
+ if (state.truncated)
904
+ break;
905
+ await analyzeCallableSymbol(symbol, new Map(), state, {
906
+ entrySymbol: symbol,
907
+ depth: 0,
908
+ callStack: [symbol.id],
909
+ });
910
+ }
911
+ const filtered = state.traces.filter((trace) => isAllowedPattern(state.defaultSources, trace.source.kind, trace.source.label)
912
+ && isAllowedPattern(state.defaultSinks, trace.sink.kind, trace.sink.label));
913
+ return {
914
+ framework,
915
+ analyzed_symbols: candidates.length,
916
+ source_patterns: [...state.defaultSources],
917
+ sink_patterns: [...state.defaultSinks],
918
+ traces: filtered,
919
+ truncated: state.truncated,
920
+ };
921
+ }
922
+ //# sourceMappingURL=taint-tools.js.map