patchi 0.7.5__py3-none-any.whl

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 (496) hide show
  1. patchi/__init__.py +1 -0
  2. patchi/__main__.py +13 -0
  3. patchi/cli/__init__.py +0 -0
  4. patchi/cli/command_families.py +235 -0
  5. patchi/cli/commands/__init__.py +0 -0
  6. patchi/cli/commands/access_cmd.py +65 -0
  7. patchi/cli/commands/agent_stats_cmd.py +273 -0
  8. patchi/cli/commands/agents_cmd.py +187 -0
  9. patchi/cli/commands/ai_cmd.py +308 -0
  10. patchi/cli/commands/assure_cmd.py +538 -0
  11. patchi/cli/commands/audit_cmd.py +286 -0
  12. patchi/cli/commands/auto_cmd.py +110 -0
  13. patchi/cli/commands/blame_cmd.py +53 -0
  14. patchi/cli/commands/chains_cmd.py +327 -0
  15. patchi/cli/commands/charter_cmd.py +173 -0
  16. patchi/cli/commands/chat_cmd.py +597 -0
  17. patchi/cli/commands/check_cmd.py +232 -0
  18. patchi/cli/commands/cleanup_cmd.py +328 -0
  19. patchi/cli/commands/cockpit_cmd.py +208 -0
  20. patchi/cli/commands/commands_cmd.py +160 -0
  21. patchi/cli/commands/cross_repo_cmd.py +113 -0
  22. patchi/cli/commands/deps_cmd.py +110 -0
  23. patchi/cli/commands/dev_check_cmd.py +342 -0
  24. patchi/cli/commands/dev_cmd.py +445 -0
  25. patchi/cli/commands/doctor_cmd.py +457 -0
  26. patchi/cli/commands/findings_cmd.py +187 -0
  27. patchi/cli/commands/fix_cmd.py +648 -0
  28. patchi/cli/commands/fix_review_cmd.py +273 -0
  29. patchi/cli/commands/heatmap_cmd.py +62 -0
  30. patchi/cli/commands/help_cmd.py +159 -0
  31. patchi/cli/commands/hosted_cmd.py +980 -0
  32. patchi/cli/commands/init.py +456 -0
  33. patchi/cli/commands/key_cmd.py +571 -0
  34. patchi/cli/commands/learn_cmd.py +140 -0
  35. patchi/cli/commands/link_cmd.py +104 -0
  36. patchi/cli/commands/log_cmd.py +57 -0
  37. patchi/cli/commands/memory_cmd.py +215 -0
  38. patchi/cli/commands/model_cmd.py +207 -0
  39. patchi/cli/commands/notify_cmd.py +213 -0
  40. patchi/cli/commands/notify_prompts.py +29 -0
  41. patchi/cli/commands/patch_cmd.py +231 -0
  42. patchi/cli/commands/plan_cmd.py +128 -0
  43. patchi/cli/commands/plugins_cmd.py +307 -0
  44. patchi/cli/commands/queue_cmd.py +152 -0
  45. patchi/cli/commands/quick_cmd.py +159 -0
  46. patchi/cli/commands/ready_cmd.py +292 -0
  47. patchi/cli/commands/report_cmd.py +416 -0
  48. patchi/cli/commands/restrict_cmd.py +127 -0
  49. patchi/cli/commands/review_cmd.py +225 -0
  50. patchi/cli/commands/rules_cmd.py +233 -0
  51. patchi/cli/commands/scan_cmd.py +1908 -0
  52. patchi/cli/commands/settings_cmd.py +45 -0
  53. patchi/cli/commands/status_cmd.py +679 -0
  54. patchi/cli/commands/test_cmd.py +1052 -0
  55. patchi/cli/commands/trend_cmd.py +296 -0
  56. patchi/cli/commands/undo_cmd.py +235 -0
  57. patchi/cli/commands/update_cmd.py +345 -0
  58. patchi/cli/commands/verify_cmd.py +56 -0
  59. patchi/cli/commands/vr_cmd.py +440 -0
  60. patchi/cli/commands/watch_cmd.py +304 -0
  61. patchi/cli/commands/web_cmd.py +114 -0
  62. patchi/cli/console.py +101 -0
  63. patchi/cli/display/__init__.py +1 -0
  64. patchi/cli/display/live_audit.py +269 -0
  65. patchi/cli/display/live_progress.py +169 -0
  66. patchi/cli/framework.py +241 -0
  67. patchi/cli/logo.py +128 -0
  68. patchi/cli/main.py +222 -0
  69. patchi/cli/registry.py +1171 -0
  70. patchi/cli/style.py +68 -0
  71. patchi/cli/themes.py +187 -0
  72. patchi/cli/ux.py +444 -0
  73. patchi/core/__init__.py +0 -0
  74. patchi/core/agents/__init__.py +0 -0
  75. patchi/core/agents/api_fuzzer_agent.py +141 -0
  76. patchi/core/agents/attack_agent.py +242 -0
  77. patchi/core/agents/base.py +1012 -0
  78. patchi/core/agents/bug_predictor_agent.py +58 -0
  79. patchi/core/agents/build_tool_validator.py +150 -0
  80. patchi/core/agents/cache.py +192 -0
  81. patchi/core/agents/chaos_agent.py +133 -0
  82. patchi/core/agents/cicd_generator.py +240 -0
  83. patchi/core/agents/comment_scanner.py +280 -0
  84. patchi/core/agents/console_logging_agent.py +156 -0
  85. patchi/core/agents/coordinator.py +858 -0
  86. patchi/core/agents/core_scanner.py +269 -0
  87. patchi/core/agents/coverage_prioritizer.py +181 -0
  88. patchi/core/agents/dead_code_hygiene.py +296 -0
  89. patchi/core/agents/dead_code_scanner.py +692 -0
  90. patchi/core/agents/dependency_scanner.py +725 -0
  91. patchi/core/agents/doc_claim_agent.py +573 -0
  92. patchi/core/agents/duplicate_scanner.py +568 -0
  93. patchi/core/agents/env_scanner.py +410 -0
  94. patchi/core/agents/feature_flag_agent.py +89 -0
  95. patchi/core/agents/frontend_framework_agent.py +133 -0
  96. patchi/core/agents/goroutine_agent.py +82 -0
  97. patchi/core/agents/governor.py +1972 -0
  98. patchi/core/agents/i18n_agent.py +95 -0
  99. patchi/core/agents/license_compliance.py +247 -0
  100. patchi/core/agents/linking_agent.py +251 -0
  101. patchi/core/agents/memory_profiler_agent.py +102 -0
  102. patchi/core/agents/modernization_agent.py +84 -0
  103. patchi/core/agents/mutation_agent.py +174 -0
  104. patchi/core/agents/nl_query_agent.py +74 -0
  105. patchi/core/agents/promise_rejection_agent.py +100 -0
  106. patchi/core/agents/refactoring_agent.py +286 -0
  107. patchi/core/agents/resource_leak_agent.py +91 -0
  108. patchi/core/agents/route_graph_scanner.py +951 -0
  109. patchi/core/agents/run_agent.py +106 -0
  110. patchi/core/agents/rust_unwrap_agent.py +100 -0
  111. patchi/core/agents/sbom_generator.py +284 -0
  112. patchi/core/agents/scanners.py +67 -0
  113. patchi/core/agents/side/__init__.py +1 -0
  114. patchi/core/agents/side/build_agent.py +65 -0
  115. patchi/core/agents/side/format_agent.py +50 -0
  116. patchi/core/agents/side/install_agent.py +63 -0
  117. patchi/core/agents/side_file_scanner.py +549 -0
  118. patchi/core/agents/snapshot_drift_detector.py +146 -0
  119. patchi/core/agents/spa_route_inventory.py +203 -0
  120. patchi/core/agents/test_scanner.py +442 -0
  121. patchi/core/agents/tool_health.py +109 -0
  122. patchi/core/agents/tool_runner.py +162 -0
  123. patchi/core/agents/type_scanner.py +168 -0
  124. patchi/core/agents/ui_scanner.py +558 -0
  125. patchi/core/ai/__init__.py +20 -0
  126. patchi/core/ai/agent_audit.py +153 -0
  127. patchi/core/ai/agent_profiler.py +277 -0
  128. patchi/core/ai/client.py +499 -0
  129. patchi/core/ai/cost_tracker.py +107 -0
  130. patchi/core/ai/model_router.py +318 -0
  131. patchi/core/ai/orchestrator.py +625 -0
  132. patchi/core/ai/prompts.py +681 -0
  133. patchi/core/ai/smart.py +302 -0
  134. patchi/core/ai/tool_executor.py +24 -0
  135. patchi/core/ai/tools/__init__.py +10 -0
  136. patchi/core/ai/tools/executor.py +621 -0
  137. patchi/core/ai/tools/realize.py +1160 -0
  138. patchi/core/ai/tools/registry.py +1577 -0
  139. patchi/core/assurance/__init__.py +33 -0
  140. patchi/core/assurance/builder.py +211 -0
  141. patchi/core/assurance/graph.py +342 -0
  142. patchi/core/assurance/invariants.py +168 -0
  143. patchi/core/atomic.py +61 -0
  144. patchi/core/attackers/__init__.py +17 -0
  145. patchi/core/attackers/api_abuse.py +89 -0
  146. patchi/core/attackers/auth_bypass.py +73 -0
  147. patchi/core/attackers/base.py +91 -0
  148. patchi/core/attackers/business_logic.py +88 -0
  149. patchi/core/attackers/planner.py +108 -0
  150. patchi/core/attackers/priv_escalation.py +88 -0
  151. patchi/core/attackers/recon.py +87 -0
  152. patchi/core/brain/__init__.py +0 -0
  153. patchi/core/brain/ast_utils/__init__.py +81 -0
  154. patchi/core/brain/ast_utils/assignments.py +219 -0
  155. patchi/core/brain/ast_utils/calls.py +139 -0
  156. patchi/core/brain/ast_utils/config.py +132 -0
  157. patchi/core/brain/ast_utils/control_flow.py +74 -0
  158. patchi/core/brain/ast_utils/dead_symbols.py +205 -0
  159. patchi/core/brain/ast_utils/decorators.py +108 -0
  160. patchi/core/brain/ast_utils/helpers.py +144 -0
  161. patchi/core/brain/ast_utils/imports.py +169 -0
  162. patchi/core/brain/ast_utils/scan.py +143 -0
  163. patchi/core/brain/ast_utils/taint.py +310 -0
  164. patchi/core/brain/audit.py +379 -0
  165. patchi/core/brain/baseline.py +195 -0
  166. patchi/core/brain/blast_radius.py +312 -0
  167. patchi/core/brain/body_tags.py +144 -0
  168. patchi/core/brain/brain.py +1161 -0
  169. patchi/core/brain/brain_context.py +393 -0
  170. patchi/core/brain/brain_watcher.py +340 -0
  171. patchi/core/brain/charter.py +473 -0
  172. patchi/core/brain/classifier.py +214 -0
  173. patchi/core/brain/cockpit.py +350 -0
  174. patchi/core/brain/code_query.py +710 -0
  175. patchi/core/brain/contract.py +889 -0
  176. patchi/core/brain/contract_diff.py +155 -0
  177. patchi/core/brain/council.py +800 -0
  178. patchi/core/brain/cross_repo.py +104 -0
  179. patchi/core/brain/dead_code_tools.py +157 -0
  180. patchi/core/brain/doc_validator.py +197 -0
  181. patchi/core/brain/domain_activator.py +2183 -0
  182. patchi/core/brain/enriched_context.py +220 -0
  183. patchi/core/brain/file_corpus.py +220 -0
  184. patchi/core/brain/framework.py +953 -0
  185. patchi/core/brain/freshness.py +273 -0
  186. patchi/core/brain/git_aware.py +206 -0
  187. patchi/core/brain/heatmap.py +104 -0
  188. patchi/core/brain/ignore_parser.py +153 -0
  189. patchi/core/brain/import_graph.py +486 -0
  190. patchi/core/brain/languages.py +397 -0
  191. patchi/core/brain/layered_brain.py +419 -0
  192. patchi/core/brain/learning.py +229 -0
  193. patchi/core/brain/orphaned_endpoints.py +313 -0
  194. patchi/core/brain/personas/__init__.py +648 -0
  195. patchi/core/brain/personas/bad_user.py +165 -0
  196. patchi/core/brain/personas/base.py +349 -0
  197. patchi/core/brain/proactive.py +807 -0
  198. patchi/core/brain/project_context.py +121 -0
  199. patchi/core/brain/project_reader.py +521 -0
  200. patchi/core/brain/reasoning.py +269 -0
  201. patchi/core/brain/route_detector/__init__.py +15 -0
  202. patchi/core/brain/route_detector/base.py +31 -0
  203. patchi/core/brain/route_detector/csharp.py +209 -0
  204. patchi/core/brain/route_detector/file_based.py +81 -0
  205. patchi/core/brain/route_detector/go.py +152 -0
  206. patchi/core/brain/route_detector/java.py +195 -0
  207. patchi/core/brain/route_detector/javascript.py +197 -0
  208. patchi/core/brain/route_detector/php.py +158 -0
  209. patchi/core/brain/route_detector/python.py +193 -0
  210. patchi/core/brain/route_detector/registry.py +25 -0
  211. patchi/core/brain/route_detector/ruby.py +134 -0
  212. patchi/core/brain/route_detector/rust.py +216 -0
  213. patchi/core/brain/route_detector/swift.py +118 -0
  214. patchi/core/brain/route_mapper.py +265 -0
  215. patchi/core/brain/scanner.py +2136 -0
  216. patchi/core/brain/secrets.py +280 -0
  217. patchi/core/brain/symbol_graph.py +1955 -0
  218. patchi/core/brain/team.py +28 -0
  219. patchi/core/brain/trace_log.py +132 -0
  220. patchi/core/brain/type_checker/__init__.py +65 -0
  221. patchi/core/brain/type_checker/base.py +60 -0
  222. patchi/core/brain/type_checker/csharp.py +59 -0
  223. patchi/core/brain/type_checker/dart.py +59 -0
  224. patchi/core/brain/type_checker/go.py +81 -0
  225. patchi/core/brain/type_checker/java.py +75 -0
  226. patchi/core/brain/type_checker/kotlin.py +75 -0
  227. patchi/core/brain/type_checker/php.py +88 -0
  228. patchi/core/brain/type_checker/python.py +87 -0
  229. patchi/core/brain/type_checker/rust.py +81 -0
  230. patchi/core/brain/type_checker/swift.py +59 -0
  231. patchi/core/brain/type_checker/typescript.py +298 -0
  232. patchi/core/brain/understander.py +130 -0
  233. patchi/core/brain/verify.py +379 -0
  234. patchi/core/campaigns/__init__.py +14 -0
  235. patchi/core/campaigns/base.py +62 -0
  236. patchi/core/campaigns/data_flow_abuse.py +153 -0
  237. patchi/core/campaigns/orchestrator.py +140 -0
  238. patchi/core/campaigns/state_transitions.py +178 -0
  239. patchi/core/ci_bundle.py +104 -0
  240. patchi/core/config.py +311 -0
  241. patchi/core/constants.py +245 -0
  242. patchi/core/debug/__init__.py +25 -0
  243. patchi/core/debug/adapters/__init__.py +11 -0
  244. patchi/core/debug/adapters/codelldb.py +379 -0
  245. patchi/core/debug/adapters/node.py +222 -0
  246. patchi/core/debug/adapters/powershell.py +210 -0
  247. patchi/core/debug/adapters/python.py +244 -0
  248. patchi/core/debug/capture.py +210 -0
  249. patchi/core/debug/dap_client.py +268 -0
  250. patchi/core/detector/__init__.py +0 -0
  251. patchi/core/detector/audit.py +194 -0
  252. patchi/core/detector/bus.py +226 -0
  253. patchi/core/detector/dispatcher.py +275 -0
  254. patchi/core/detector/event.py +254 -0
  255. patchi/core/detector/sigma_engine.py +378 -0
  256. patchi/core/detector/triage.py +289 -0
  257. patchi/core/export/sarif.py +113 -0
  258. patchi/core/fix/__init__.py +17 -0
  259. patchi/core/fix/applier.py +574 -0
  260. patchi/core/fix/base.py +510 -0
  261. patchi/core/fix/code_fixer.py +169 -0
  262. patchi/core/fix/dead_code_remover.py +131 -0
  263. patchi/core/fix/fix_agents.py +775 -0
  264. patchi/core/fix/patch.py +444 -0
  265. patchi/core/fix/risk_gate.py +383 -0
  266. patchi/core/fix/security_fixer.py +93 -0
  267. patchi/core/fix/verify_loop.py +204 -0
  268. patchi/core/fuzz/__init__.py +8 -0
  269. patchi/core/fuzz/corpus.py +137 -0
  270. patchi/core/fuzz/input_fuzzer.py +256 -0
  271. patchi/core/fuzz/sequence_fuzzer.py +162 -0
  272. patchi/core/fuzz/state_fuzzer.py +236 -0
  273. patchi/core/health.py +407 -0
  274. patchi/core/hosted/__init__.py +1 -0
  275. patchi/core/hosted/anomaly.py +298 -0
  276. patchi/core/hosted/audit_log.py +102 -0
  277. patchi/core/hosted/compliance_report.py +148 -0
  278. patchi/core/hosted/ip_reputation.py +169 -0
  279. patchi/core/hosted/log_parsers.py +251 -0
  280. patchi/core/hosted/tokens.py +127 -0
  281. patchi/core/hosted/watchlist.py +164 -0
  282. patchi/core/hosted/webhooks.py +156 -0
  283. patchi/core/memory.py +437 -0
  284. patchi/core/notifications/__init__.py +18 -0
  285. patchi/core/notifications/channels.py +192 -0
  286. patchi/core/notifications/digest.py +141 -0
  287. patchi/core/notifications/escalation.py +158 -0
  288. patchi/core/notifications/notifier.py +182 -0
  289. patchi/core/notifications/quiet_hours.py +69 -0
  290. patchi/core/plugins/__init__.py +48 -0
  291. patchi/core/plugins/analyzer.py +326 -0
  292. patchi/core/plugins/analyzers/__init__.py +6 -0
  293. patchi/core/plugins/analyzers/dead_code_analyzer.py +120 -0
  294. patchi/core/plugins/analyzers/secret_scanner.py +158 -0
  295. patchi/core/plugins/analyzers/todo_scanner.py +115 -0
  296. patchi/core/plugins/registry.py +335 -0
  297. patchi/core/queue.py +375 -0
  298. patchi/core/reliability/__init__.py +13 -0
  299. patchi/core/reliability/chaos.py +163 -0
  300. patchi/core/reliability/fault_injector.py +172 -0
  301. patchi/core/reliability/idempotency.py +128 -0
  302. patchi/core/reliability/recovery.py +147 -0
  303. patchi/core/runtime/__init__.py +5 -0
  304. patchi/core/runtime/tracer.py +230 -0
  305. patchi/core/scan_bus.py +156 -0
  306. patchi/core/security/__init__.py +1 -0
  307. patchi/core/security/ai_validator.py +462 -0
  308. patchi/core/security/app_mapper.py +216 -0
  309. patchi/core/security/app_profile.py +464 -0
  310. patchi/core/security/attack_feedback.py +141 -0
  311. patchi/core/security/attack_scenarios/__init__.py +1 -0
  312. patchi/core/security/attack_tree.py +176 -0
  313. patchi/core/security/auth_audit_agent.py +344 -0
  314. patchi/core/security/authz_agent.py +602 -0
  315. patchi/core/security/auto_fix_proactive.py +620 -0
  316. patchi/core/security/auto_fixer.py +660 -0
  317. patchi/core/security/auto_ticket.py +53 -0
  318. patchi/core/security/bandit_agent.py +152 -0
  319. patchi/core/security/blast_radius.py +226 -0
  320. patchi/core/security/browser_tester.py +333 -0
  321. patchi/core/security/business_logic_agent.py +263 -0
  322. patchi/core/security/catch_block_auditor.py +395 -0
  323. patchi/core/security/cdn_cache_agent.py +357 -0
  324. patchi/core/security/chain_analyzer.py +321 -0
  325. patchi/core/security/chain_to_assurance.py +168 -0
  326. patchi/core/security/charter.py +510 -0
  327. patchi/core/security/cloud_waf_detector.py +295 -0
  328. patchi/core/security/codeql_agent.py +233 -0
  329. patchi/core/security/compliance_agent.py +348 -0
  330. patchi/core/security/confidence_gate.py +423 -0
  331. patchi/core/security/container_scanner.py +282 -0
  332. patchi/core/security/crypto_agent.py +378 -0
  333. patchi/core/security/cve_monitor.py +262 -0
  334. patchi/core/security/dast_agent.py +865 -0
  335. patchi/core/security/defectdojo.py +238 -0
  336. patchi/core/security/defenders/__init__.py +75 -0
  337. patchi/core/security/defenders/auth_middleware.py +115 -0
  338. patchi/core/security/defenders/base.py +97 -0
  339. patchi/core/security/defenders/block_ip.py +71 -0
  340. patchi/core/security/defenders/block_ws_origin.py +36 -0
  341. patchi/core/security/defenders/crypto_fix.py +118 -0
  342. patchi/core/security/defenders/enforce_rate_limit.py +108 -0
  343. patchi/core/security/defenders/fix_code.py +93 -0
  344. patchi/core/security/defenders/invalidate_session.py +40 -0
  345. patchi/core/security/defenders/patch_config.py +70 -0
  346. patchi/core/security/defenders/rotate_secret.py +54 -0
  347. patchi/core/security/defenders/suspend_account.py +41 -0
  348. patchi/core/security/defenders/update_dependency.py +160 -0
  349. patchi/core/security/defense_layer.py +217 -0
  350. patchi/core/security/dependency_vulnerability_agent.py +616 -0
  351. patchi/core/security/detection_pipeline.py +289 -0
  352. patchi/core/security/dns_security_agent.py +497 -0
  353. patchi/core/security/domain_activator_v2.py +913 -0
  354. patchi/core/security/domain_loader.py +1004 -0
  355. patchi/core/security/domains/__init__.py +0 -0
  356. patchi/core/security/email_authentication_agent.py +417 -0
  357. patchi/core/security/env_var_validator.py +304 -0
  358. patchi/core/security/evidence.py +100 -0
  359. patchi/core/security/falco_runtime_agent.py +387 -0
  360. patchi/core/security/fix-playbooks/__init__.py +0 -0
  361. patchi/core/security/gated_finding.py +85 -0
  362. patchi/core/security/git_diff_activator.py +367 -0
  363. patchi/core/security/governance.py +208 -0
  364. patchi/core/security/gradual_gate.py +34 -0
  365. patchi/core/security/history.py +315 -0
  366. patchi/core/security/iac_scanner.py +250 -0
  367. patchi/core/security/ignore_expiry.py +111 -0
  368. patchi/core/security/ignore_learner.py +416 -0
  369. patchi/core/security/injection_agent.py +319 -0
  370. patchi/core/security/insecure_randomness_agent.py +288 -0
  371. patchi/core/security/intent_analyzer.py +326 -0
  372. patchi/core/security/jwt_agent.py +453 -0
  373. patchi/core/security/kubernetes_agent.py +638 -0
  374. patchi/core/security/layer2_orchestrator.py +341 -0
  375. patchi/core/security/llm_security_agent.py +252 -0
  376. patchi/core/security/misconfig_agent.py +600 -0
  377. patchi/core/security/mobile_security_agent.py +474 -0
  378. patchi/core/security/network_agent.py +376 -0
  379. patchi/core/security/noise_filter.py +274 -0
  380. patchi/core/security/orchestrator.py +313 -0
  381. patchi/core/security/pattern_context.py +125 -0
  382. patchi/core/security/pattern_loader.py +101 -0
  383. patchi/core/security/pentest/__init__.py +4 -0
  384. patchi/core/security/pentest/base.py +58 -0
  385. patchi/core/security/pentest/dalfox_adapter.py +40 -0
  386. patchi/core/security/pentest/ffuf_adapter.py +48 -0
  387. patchi/core/security/pentest/nuclei_adapter.py +50 -0
  388. patchi/core/security/pentest/registry.py +80 -0
  389. patchi/core/security/pentest/shannon_adapter.py +107 -0
  390. patchi/core/security/pentest/sqlmap_adapter.py +56 -0
  391. patchi/core/security/pentest/zap_adapter.py +52 -0
  392. patchi/core/security/plan_auditor.py +276 -0
  393. patchi/core/security/policy_engine.py +272 -0
  394. patchi/core/security/prechecks.py +172 -0
  395. patchi/core/security/precommit_hook.py +247 -0
  396. patchi/core/security/privacy_agent.py +361 -0
  397. patchi/core/security/push_notification_agent.py +417 -0
  398. patchi/core/security/pysa_agent.py +143 -0
  399. patchi/core/security/reasoning.py +442 -0
  400. patchi/core/security/red_team_agent.py +184 -0
  401. patchi/core/security/red_team_engine.py +1142 -0
  402. patchi/core/security/remediation.py +360 -0
  403. patchi/core/security/request_interceptor.py +294 -0
  404. patchi/core/security/runtime_validator.py +245 -0
  405. patchi/core/security/saml_sso_agent.py +401 -0
  406. patchi/core/security/sast_agent.py +213 -0
  407. patchi/core/security/sast_gate.py +95 -0
  408. patchi/core/security/scheduler.py +287 -0
  409. patchi/core/security/secrets_runtime_agent.py +476 -0
  410. patchi/core/security/security_agents.py +175 -0
  411. patchi/core/security/security_config.py +551 -0
  412. patchi/core/security/security_probe.py +762 -0
  413. patchi/core/security/security_taint.py +1005 -0
  414. patchi/core/security/sensitive_data_agent.py +271 -0
  415. patchi/core/security/service_mesh_agent.py +412 -0
  416. patchi/core/security/session_management_agent.py +245 -0
  417. patchi/core/security/ssrf_agent.py +422 -0
  418. patchi/core/security/supply_chain.py +449 -0
  419. patchi/core/security/threat_model_generator.py +378 -0
  420. patchi/core/security/threat_model_updater.py +196 -0
  421. patchi/core/security/tool_adapters.py +135 -0
  422. patchi/core/security/tool_verify.py +173 -0
  423. patchi/core/security/websocket_security_agent.py +188 -0
  424. patchi/core/snapshot.py +242 -0
  425. patchi/core/tenant.py +386 -0
  426. patchi/core/testing/__init__.py +17 -0
  427. patchi/core/testing/_browser.py +147 -0
  428. patchi/core/testing/ads_agent.py +141 -0
  429. patchi/core/testing/api_contract_agent.py +450 -0
  430. patchi/core/testing/app_discovery_agent.py +641 -0
  431. patchi/core/testing/app_launcher.py +184 -0
  432. patchi/core/testing/browser_test_agent.py +516 -0
  433. patchi/core/testing/e2e_flow_agent.py +354 -0
  434. patchi/core/testing/flake_detector_agent.py +292 -0
  435. patchi/core/testing/gate.py +31 -0
  436. patchi/core/testing/live_test_runner.py +304 -0
  437. patchi/core/testing/live_v2/__init__.py +1 -0
  438. patchi/core/testing/live_v2/browser_pool.py +349 -0
  439. patchi/core/testing/live_v2/browser_test_runner.py +313 -0
  440. patchi/core/testing/live_v2/runner.py +626 -0
  441. patchi/core/testing/live_v2/screenshot_manager.py +474 -0
  442. patchi/core/testing/live_v2/stress_orchestrator.py +523 -0
  443. patchi/core/testing/live_v2/video_recorder.py +303 -0
  444. patchi/core/testing/regression_agent.py +302 -0
  445. patchi/core/testing/security_test_agent.py +253 -0
  446. patchi/core/testing/stress_test_agent.py +203 -0
  447. patchi/core/testing/test_agents.py +50 -0
  448. patchi/core/testing/test_config.py +194 -0
  449. patchi/core/testing/ui_accessibility_agent.py +324 -0
  450. patchi/core/testing/ui_button_agent.py +294 -0
  451. patchi/core/testing/ui_layout_agent.py +330 -0
  452. patchi/core/testing/unit_test_agent.py +1149 -0
  453. patchi/core/testing/visual_regression_agent.py +260 -0
  454. patchi/web/__init__.py +1 -0
  455. patchi/web/api/__init__.py +1 -0
  456. patchi/web/api/brain_map.py +114 -0
  457. patchi/web/api/charts.py +47 -0
  458. patchi/web/api/chat.py +224 -0
  459. patchi/web/api/cicd.py +576 -0
  460. patchi/web/api/dast_evidence.py +49 -0
  461. patchi/web/api/dev_check.py +320 -0
  462. patchi/web/api/fix.py +134 -0
  463. patchi/web/api/guard.py +65 -0
  464. patchi/web/api/hosted.py +128 -0
  465. patchi/web/api/hosted_v2.py +234 -0
  466. patchi/web/api/live_testing.py +699 -0
  467. patchi/web/api/scan.py +582 -0
  468. patchi/web/api/smart.py +111 -0
  469. patchi/web/api/tenant.py +117 -0
  470. patchi/web/api/tools.py +85 -0
  471. patchi/web/api_legacy.py +2401 -0
  472. patchi/web/app.py +310 -0
  473. patchi/web/events.py +483 -0
  474. patchi/web/routes/__init__.py +1 -0
  475. patchi/web/routes/assurance.py +541 -0
  476. patchi/web/routes/brain.py +36 -0
  477. patchi/web/routes/charter.py +227 -0
  478. patchi/web/routes/chat.py +23 -0
  479. patchi/web/routes/dashboard.py +558 -0
  480. patchi/web/routes/dashboard_v2.py +402 -0
  481. patchi/web/routes/findings.py +330 -0
  482. patchi/web/routes/guard.py +35 -0
  483. patchi/web/routes/history.py +126 -0
  484. patchi/web/routes/landing.py +52 -0
  485. patchi/web/routes/live_testing.py +24 -0
  486. patchi/web/routes/review.py +57 -0
  487. patchi/web/routes/self_improvement.py +110 -0
  488. patchi/web/routes/settings.py +49 -0
  489. patchi/web/routes/tokens.py +29 -0
  490. patchi/web/spawn.py +139 -0
  491. patchi/web/ws.py +141 -0
  492. patchi-0.7.5.dist-info/METADATA +315 -0
  493. patchi-0.7.5.dist-info/RECORD +496 -0
  494. patchi-0.7.5.dist-info/WHEEL +5 -0
  495. patchi-0.7.5.dist-info/licenses/LICENSE +60 -0
  496. patchi-0.7.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,216 @@
1
+ import logging
2
+ import re
3
+
4
+ from patchi.core.brain.route_detector.base import BaseRouteDetector
5
+ from patchi.core.brain.route_detector.registry import register_detector
6
+
7
+ _RUST_HTTP_METHODS = {
8
+ "get",
9
+ "post",
10
+ "put",
11
+ "delete",
12
+ "patch",
13
+ "head",
14
+ "options",
15
+ "connect",
16
+ "trace",
17
+ "any",
18
+ }
19
+
20
+
21
+ _log = logging.getLogger("patchi.brain.rust")
22
+
23
+
24
+ @register_detector("rust")
25
+ class RustRouteDetector(BaseRouteDetector):
26
+ def detect(self, content: str, file_path: str) -> list[dict]:
27
+ routes = self._detect_ts(content, file_path)
28
+ if routes:
29
+ return routes
30
+ return self._detect_fallback(content, file_path)
31
+
32
+ def _detect_ts(self, content: str, file_path: str) -> list[dict] | None:
33
+ try:
34
+ from patchi.core.brain.languages import Lang, _build_parser
35
+
36
+ parser = _build_parser(Lang.RUST)
37
+ tree = parser.parse(bytes(content, "utf-8"))
38
+ except Exception as e:
39
+ _log.warning("RustRouteDetector._detect_ts failed: %s", e)
40
+ return None
41
+
42
+ routes: list[dict] = []
43
+ self._walk(tree.root_node, bytes(content, "utf-8"), content, file_path, routes)
44
+ return routes
45
+
46
+ def _walk(
47
+ self, node: object, buf: bytes, content: str, file_path: str, routes: list[dict]
48
+ ) -> None:
49
+ ntype = getattr(node, "type", "")
50
+ if ntype == "attribute_item":
51
+ self._check_actix_attr(node, buf, content, file_path, routes)
52
+ elif ntype == "call_expression":
53
+ self._check_axum_call(node, buf, content, file_path, routes)
54
+
55
+ for child in getattr(node, "named_children", None) or getattr(node, "children", []):
56
+ self._walk(child, buf, content, file_path, routes)
57
+
58
+ def _check_actix_attr(
59
+ self, node: object, buf: bytes, content: str, file_path: str, routes: list[dict]
60
+ ) -> None:
61
+ attr = self._child_by_field(node, "attribute")
62
+ if attr is None:
63
+ return
64
+ attr_type = getattr(attr, "type", "")
65
+ if attr_type != "attribute":
66
+ return
67
+
68
+ path_node = self._child_by_field(attr, "path") or self._child_by_field(attr, "name")
69
+ if path_node is None:
70
+ return
71
+ try:
72
+ raw = self._node_text(path_node).lower()
73
+ except Exception as e:
74
+ _log.warning("RustRouteDetector._check_actix_attr failed: %s", e)
75
+ return
76
+
77
+ if raw not in _RUST_HTTP_METHODS:
78
+ return
79
+
80
+ args = self._child_by_field(attr, "arguments")
81
+ path = ""
82
+ if args:
83
+ for child in getattr(args, "named_children", None) or getattr(args, "children", []):
84
+ if child.type in ("string_literal", "raw_string_literal"):
85
+ raw = self._node_text(child)
86
+ path = raw.strip('"')
87
+ break
88
+
89
+ handler = self._find_fn_name(node)
90
+ line = getattr(node, "start_point", (0, 0))[0] + 1
91
+
92
+ routes.append(
93
+ self._make_route(raw.upper(), path, handler, file_path, line, framework="Actix Web")
94
+ )
95
+
96
+ def _check_axum_call(
97
+ self, node: object, buf: bytes, content: str, file_path: str, routes: list[dict]
98
+ ) -> None:
99
+ func = self._child_by_field(node, "function")
100
+ if func is None:
101
+ return
102
+ if getattr(func, "type", "") != "field_expression":
103
+ return
104
+ method_name = self._child_by_field(func, "field")
105
+ if method_name is None or self._node_text(method_name) != "route":
106
+ return
107
+
108
+ args = self._child_by_field(node, "arguments")
109
+ if args is None or getattr(args, "named_child_count", 0) < 2:
110
+ return
111
+
112
+ path = ""
113
+ first = args.named_child(0)
114
+ if first and first.type in ("string_literal", "raw_string_literal"):
115
+ path = self._node_text(first).strip('"')
116
+ if not path:
117
+ return
118
+
119
+ second = args.named_child(1)
120
+ http_method = ""
121
+ handler = ""
122
+ if second and second.type == "call_expression":
123
+ inner_fn = self._child_by_field(second, "function")
124
+ if inner_fn and inner_fn.type == "identifier":
125
+ http_method = self._node_text(inner_fn).lower()
126
+ if http_method in _RUST_HTTP_METHODS:
127
+ inner_args = self._child_by_field(second, "arguments")
128
+ if inner_args and inner_args.named_child_count > 0:
129
+ h = inner_args.named_child(0)
130
+ if h and h.type == "identifier":
131
+ handler = self._node_text(h)
132
+
133
+ if not http_method:
134
+ return
135
+
136
+ line = getattr(node, "start_point", (0, 0))[0] + 1
137
+ routes.append(
138
+ self._make_route(http_method.upper(), path, handler, file_path, line, framework="Axum")
139
+ )
140
+
141
+ def _find_fn_name(self, node: object) -> str:
142
+ cur = node
143
+ for _ in range(10):
144
+ cur = getattr(cur, "parent", None)
145
+ if cur is None:
146
+ break
147
+ if getattr(cur, "type", "") == "function_item":
148
+ name_node = self._child_by_field(cur, "name")
149
+ if name_node:
150
+ return self._node_text(name_node)
151
+ return ""
152
+
153
+ def _child_by_field(self, node: object, field: str) -> object | None:
154
+ if hasattr(node, "child_by_field_name"):
155
+ return node.child_by_field_name(field)
156
+ return None
157
+
158
+ def _node_text(self, node: object) -> str:
159
+ try:
160
+ raw = getattr(node, "text", b"")
161
+ if isinstance(raw, bytes):
162
+ return raw.decode("utf-8", errors="replace")
163
+ return str(raw)
164
+ except Exception as e:
165
+ _log.debug("RustRouteDetector._node_text failed: %s", e)
166
+ return ""
167
+
168
+ def _detect_fallback(self, content: str, file_path: str) -> list[dict]:
169
+ routes: list[dict] = []
170
+ http = "|".join(_RUST_HTTP_METHODS)
171
+
172
+ actix_pat = re.compile(
173
+ rf"#\[\s*({http})\s*\(\s*\"([^\"]+)\"\s*\)",
174
+ re.IGNORECASE,
175
+ )
176
+ lines = content.splitlines()
177
+ for i, line in enumerate(lines, 1):
178
+ m = actix_pat.search(line)
179
+ if not m:
180
+ continue
181
+ method = m.group(1).upper()
182
+ path = m.group(2)
183
+ handler = ""
184
+ for j in range(i, min(i + 5, len(lines) + 1)):
185
+ hline = lines[j - 1].strip()
186
+ if not hline or hline.startswith("#["):
187
+ continue
188
+ hm = re.match(r"\s*(?:pub\s+)?(?:async\s+)?fn\s+(\w+)", hline)
189
+ if hm:
190
+ handler = hm.group(1)
191
+ break
192
+ routes.append(
193
+ self._make_route(method, path, handler, file_path, i, framework="Actix Web")
194
+ )
195
+
196
+ axum_pat = re.compile(
197
+ rf"""\.route\s*\(\s*["']([^"']+)["']\s*,\s*({http})\s*\(""",
198
+ re.IGNORECASE,
199
+ )
200
+ for i, line in enumerate(lines, 1):
201
+ m = axum_pat.search(line)
202
+ if not m:
203
+ continue
204
+ path = m.group(1)
205
+ method = m.group(2).upper()
206
+ handler = ""
207
+ hm = re.search(
208
+ rf"""({http})\s*\(\s*(\w+)""",
209
+ line[m.end() :] if m.end() < len(line) else line,
210
+ re.IGNORECASE,
211
+ )
212
+ if hm:
213
+ handler = hm.group(2)
214
+ routes.append(self._make_route(method, path, handler, file_path, i, framework="Axum"))
215
+
216
+ return routes
@@ -0,0 +1,118 @@
1
+ import logging
2
+ import re
3
+
4
+ from patchi.core.brain.route_detector.base import BaseRouteDetector
5
+ from patchi.core.brain.route_detector.registry import register_detector
6
+
7
+ _SWIFT_HTTP_METHODS = {"get", "post", "put", "patch", "delete", "options"}
8
+
9
+
10
+ _log = logging.getLogger("patchi.brain.swift")
11
+
12
+
13
+ @register_detector("swift")
14
+ class SwiftRouteDetector(BaseRouteDetector):
15
+ def detect(self, content: str, file_path: str) -> list[dict]:
16
+ routes = self._detect_ts(content, file_path)
17
+ if routes:
18
+ return routes
19
+ return self._detect_fallback(content, file_path)
20
+
21
+ def _detect_ts(self, content: str, file_path: str) -> list[dict] | None:
22
+ try:
23
+ from patchi.core.brain.languages import Lang, _build_parser
24
+
25
+ parser = _build_parser(Lang.SWIFT)
26
+ tree = parser.parse(bytes(content, "utf-8"))
27
+ except Exception as e:
28
+ _log.warning("SwiftRouteDetector._detect_ts failed: %s", e)
29
+ return None
30
+
31
+ routes: list[dict] = []
32
+ self._walk(tree.root_node, bytes(content, "utf-8"), content, file_path, routes)
33
+ return routes
34
+
35
+ def _walk(
36
+ self, node: object, buf: bytes, content: str, file_path: str, routes: list[dict]
37
+ ) -> None:
38
+ ntype = getattr(node, "type", "")
39
+ if ntype == "function_call_expression":
40
+ self._check_call(node, buf, content, file_path, routes)
41
+ for child in getattr(node, "named_children", None) or getattr(node, "children", []):
42
+ self._walk(child, buf, content, file_path, routes)
43
+
44
+ def _check_call(
45
+ self, node: object, buf: bytes, content: str, file_path: str, routes: list[dict]
46
+ ) -> None:
47
+ func = self._child_by_field(node, "function") or self._child_by_field(node, "name")
48
+ if func is None:
49
+ return
50
+
51
+ ftype = getattr(func, "type", "")
52
+ if ftype == "member_access_expression":
53
+ obj = self._child_by_field(func, "object")
54
+ member = self._child_by_field(func, "member") or self._child_by_field(func, "name")
55
+ if obj is None or member is None:
56
+ return
57
+ obj_name = self._node_text(obj).lower()
58
+ if obj_name != "app":
59
+ return
60
+ method_name = self._node_text(member).lower()
61
+ elif ftype == "identifier":
62
+ method_name = self._node_text(func).lower()
63
+ if method_name not in _SWIFT_HTTP_METHODS:
64
+ return
65
+ else:
66
+ return
67
+
68
+ if method_name not in _SWIFT_HTTP_METHODS:
69
+ return
70
+
71
+ args = self._child_by_field(node, "arguments")
72
+ path = ""
73
+ if args:
74
+ for child in getattr(args, "named_children", None) or getattr(args, "children", []):
75
+ if child.type == "string_literal":
76
+ path = self._node_text(child).strip('"')
77
+ break
78
+
79
+ if not path:
80
+ return
81
+
82
+ line = getattr(node, "start_point", (0, 0))[0] + 1
83
+ routes.append(
84
+ self._make_route(method_name.upper(), path, "", file_path, line, framework="Vapor")
85
+ )
86
+
87
+ def _child_by_field(self, node: object, field: str) -> object | None:
88
+ if hasattr(node, "child_by_field_name"):
89
+ return node.child_by_field_name(field)
90
+ return None
91
+
92
+ def _node_text(self, node: object) -> str:
93
+ try:
94
+ raw = getattr(node, "text", b"")
95
+ if isinstance(raw, bytes):
96
+ return raw.decode("utf-8", errors="replace")
97
+ return str(raw)
98
+ except Exception as e:
99
+ _log.debug("SwiftRouteDetector._node_text failed: %s", e)
100
+ return ""
101
+
102
+ def _detect_fallback(self, content: str, file_path: str) -> list[dict]:
103
+ routes: list[dict] = []
104
+ http = "|".join(_SWIFT_HTTP_METHODS)
105
+ pat = re.compile(
106
+ rf"""app\.({http})\s*\(\s*["']([^"']+)["']""",
107
+ re.IGNORECASE,
108
+ )
109
+ for i, line in enumerate(content.splitlines(), 1):
110
+ m = pat.search(line)
111
+ if not m:
112
+ continue
113
+ routes.append(
114
+ self._make_route(
115
+ m.group(1).upper(), m.group(2), "", file_path, i, framework="Vapor"
116
+ )
117
+ )
118
+ return routes
@@ -0,0 +1,265 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING
6
+
7
+ if TYPE_CHECKING:
8
+ from patchi.core.brain.framework import StackInfo
9
+ from patchi.core.brain.scanner import FileInfo
10
+
11
+
12
+ @dataclass
13
+ class RouteInfo:
14
+ method: str
15
+ path: str
16
+ handler: str
17
+ file: str
18
+ line: int
19
+ middleware: list[str] = field(default_factory=list)
20
+ auth_required: bool | None = None
21
+ framework: str = ""
22
+
23
+ def to_dict(self) -> dict:
24
+ return {
25
+ "method": self.method,
26
+ "path": self.path,
27
+ "handler": self.handler,
28
+ "file": self.file,
29
+ "line": self.line,
30
+ "middleware": self.middleware,
31
+ "auth_required": self.auth_required,
32
+ "framework": self.framework,
33
+ }
34
+
35
+
36
+ _LANG_FW_MAP: dict[str, set[str]] = {
37
+ "python": {"FastAPI", "Flask", "Django", "Starlette"},
38
+ "javascript": {"Express", "Fastify", "Next.js", "Nuxt", "SvelteKit"},
39
+ "typescript": {"Express", "Fastify", "Next.js", "Nuxt", "SvelteKit"},
40
+ "java": {"Spring Boot"},
41
+ "go": {"Gin", "Echo", "Fiber"},
42
+ "rust": {"Actix Web", "Axum", "Rocket"},
43
+ "swift": {"Vapor"},
44
+ "ruby": {"Ruby on Rails", "Sinatra", "Grape"},
45
+ "php": {"Laravel"},
46
+ "c_sharp": {"ASP.NET Core"},
47
+ }
48
+
49
+
50
+ class RouteMapper:
51
+ def __init__(self, root: Path, stack: StackInfo):
52
+ self.root = root
53
+ self.stack = stack
54
+
55
+ def extract(self, file_infos: list[FileInfo]) -> list[RouteInfo]:
56
+ from patchi.core.brain.route_detector.csharp import CSharpRouteDetector
57
+ from patchi.core.brain.route_detector.file_based import (
58
+ NextJsRouteDetector,
59
+ NuxtRouteDetector,
60
+ SvelteKitRouteDetector,
61
+ )
62
+ from patchi.core.brain.route_detector.go import GoRouteDetector
63
+ from patchi.core.brain.route_detector.java import JavaRouteDetector
64
+ from patchi.core.brain.route_detector.javascript import JavaScriptRouteDetector
65
+ from patchi.core.brain.route_detector.php import PhpRouteDetector
66
+ from patchi.core.brain.route_detector.python import PythonRouteDetector
67
+ from patchi.core.brain.route_detector.ruby import RubyRouteDetector
68
+ from patchi.core.brain.route_detector.rust import RustRouteDetector
69
+ from patchi.core.brain.route_detector.swift import SwiftRouteDetector
70
+
71
+ active_fw = {f.name for f in self.stack.frameworks}
72
+
73
+ # Map from language to list of (default_fw_str, route_dicts)
74
+ detector_map: dict[str, list] = {}
75
+ for lang, frameworks in _LANG_FW_MAP.items():
76
+ matched = frameworks & active_fw
77
+ if not matched:
78
+ continue
79
+ detectors = []
80
+ if lang == "python":
81
+ detectors.append(("", PythonRouteDetector()))
82
+ elif lang in ("javascript", "typescript"):
83
+ detectors.append(("", JavaScriptRouteDetector()))
84
+ if "Next.js" in matched:
85
+ detectors.append(("Next.js", NextJsRouteDetector()))
86
+ if "Nuxt" in matched:
87
+ detectors.append(("Nuxt", NuxtRouteDetector()))
88
+ if "SvelteKit" in matched:
89
+ detectors.append(("SvelteKit", SvelteKitRouteDetector()))
90
+ elif lang == "java":
91
+ detectors.append(("", JavaRouteDetector()))
92
+ elif lang == "go":
93
+ detectors.append(("", GoRouteDetector()))
94
+ elif lang == "rust":
95
+ detectors.append(("", RustRouteDetector()))
96
+ elif lang == "swift":
97
+ detectors.append(("", SwiftRouteDetector()))
98
+ elif lang == "ruby":
99
+ detectors.append(("", RubyRouteDetector()))
100
+ elif lang == "php":
101
+ detectors.append(("", PhpRouteDetector()))
102
+ elif lang == "c_sharp":
103
+ detectors.append(("", CSharpRouteDetector()))
104
+ if detectors:
105
+ detector_map[lang] = detectors
106
+
107
+ routes: list[RouteInfo] = []
108
+
109
+ for fi in file_infos:
110
+ lang = fi.language.value
111
+ detectors = detector_map.get(lang)
112
+ if not detectors:
113
+ continue
114
+
115
+ try:
116
+ content = (self.root / fi.path).read_text(encoding="utf-8", errors="replace")
117
+ except OSError:
118
+ continue
119
+
120
+ for _fw_prefix, detector in detectors:
121
+ dicts = detector.detect(content, str(fi.path))
122
+ for d in dicts:
123
+ routes.append(
124
+ RouteInfo(
125
+ method=d.get("method", "GET"),
126
+ path=d.get("path", "/"),
127
+ handler=d.get("handler", ""),
128
+ file=d.get("file", str(fi.path)),
129
+ line=d.get("line", 0),
130
+ middleware=d.get("middleware", []),
131
+ auth_required=d.get("auth_required"),
132
+ framework=d.get("framework", _fw_prefix),
133
+ )
134
+ )
135
+
136
+ seen: set[tuple] = set()
137
+ unique: list[RouteInfo] = []
138
+ for r in routes:
139
+ key = (r.method, r.path, r.file)
140
+ if key not in seen:
141
+ seen.add(key)
142
+ unique.append(r)
143
+ return unique
144
+
145
+
146
+ # ── Backward-compat extractors for tests ─────────────────────────────────────
147
+
148
+
149
+ def _extract_fastapi(content: str, file_path: str) -> list[RouteInfo]:
150
+ from patchi.core.brain.route_detector.python import PythonRouteDetector
151
+
152
+ return [RouteInfo(**d) for d in PythonRouteDetector().detect(content, file_path)]
153
+
154
+
155
+ def _extract_flask(content: str, file_path: str) -> list[RouteInfo]:
156
+ from patchi.core.brain.route_detector.python import PythonRouteDetector
157
+
158
+ return [RouteInfo(**d) for d in PythonRouteDetector().detect(content, file_path)]
159
+
160
+
161
+ def _extract_django(content: str, file_path: str) -> list[RouteInfo]:
162
+ from patchi.core.brain.route_detector.python import PythonRouteDetector
163
+
164
+ return [RouteInfo(**d) for d in PythonRouteDetector().detect(content, file_path)]
165
+
166
+
167
+ def _extract_express(content: str, file_path: str) -> list[RouteInfo]:
168
+ from patchi.core.brain.route_detector.javascript import JavaScriptRouteDetector
169
+
170
+ return [RouteInfo(**d) for d in JavaScriptRouteDetector().detect(content, file_path)]
171
+
172
+
173
+ def _extract_fastify(content: str, file_path: str) -> list[RouteInfo]:
174
+ from patchi.core.brain.route_detector.javascript import JavaScriptRouteDetector
175
+
176
+ return [RouteInfo(**d) for d in JavaScriptRouteDetector().detect(content, file_path)]
177
+
178
+
179
+ def _extract_laravel(content: str, file_path: str) -> list[RouteInfo]:
180
+ from patchi.core.brain.route_detector.php import PhpRouteDetector
181
+
182
+ return [RouteInfo(**d) for d in PhpRouteDetector().detect(content, file_path)]
183
+
184
+
185
+ def _extract_spring(content: str, file_path: str) -> list[RouteInfo]:
186
+ from patchi.core.brain.route_detector.java import JavaRouteDetector
187
+
188
+ return [RouteInfo(**d) for d in JavaRouteDetector().detect(content, file_path)]
189
+
190
+
191
+ def _extract_gin(content: str, file_path: str) -> list[RouteInfo]:
192
+ from patchi.core.brain.route_detector.go import GoRouteDetector
193
+
194
+ return [RouteInfo(**d) for d in GoRouteDetector().detect(content, file_path)]
195
+
196
+
197
+ def _extract_echo(content: str, file_path: str) -> list[RouteInfo]:
198
+ from patchi.core.brain.route_detector.go import GoRouteDetector
199
+
200
+ return [RouteInfo(**d) for d in GoRouteDetector().detect(content, file_path)]
201
+
202
+
203
+ def _extract_fiber(content: str, file_path: str) -> list[RouteInfo]:
204
+ from patchi.core.brain.route_detector.go import GoRouteDetector
205
+
206
+ return [RouteInfo(**d) for d in GoRouteDetector().detect(content, file_path)]
207
+
208
+
209
+ def _extract_actix(content: str, file_path: str) -> list[RouteInfo]:
210
+ from patchi.core.brain.route_detector.rust import RustRouteDetector
211
+
212
+ return [RouteInfo(**d) for d in RustRouteDetector().detect(content, file_path)]
213
+
214
+
215
+ def _extract_axum(content: str, file_path: str) -> list[RouteInfo]:
216
+ from patchi.core.brain.route_detector.rust import RustRouteDetector
217
+
218
+ return [RouteInfo(**d) for d in RustRouteDetector().detect(content, file_path)]
219
+
220
+
221
+ def _extract_rocket(content: str, file_path: str) -> list[RouteInfo]:
222
+ routes = _extract_actix(content, file_path)
223
+ for r in routes:
224
+ r.framework = "Rocket"
225
+ return routes
226
+
227
+
228
+ def _extract_vapor(content: str, file_path: str) -> list[RouteInfo]:
229
+ from patchi.core.brain.route_detector.swift import SwiftRouteDetector
230
+
231
+ return [RouteInfo(**d) for d in SwiftRouteDetector().detect(content, file_path)]
232
+
233
+
234
+ def _extract_rails(content: str, file_path: str) -> list[RouteInfo]:
235
+ from patchi.core.brain.route_detector.ruby import RubyRouteDetector
236
+
237
+ return [RouteInfo(**d) for d in RubyRouteDetector().detect(content, file_path)]
238
+
239
+
240
+ def _extract_sinatra(content: str, file_path: str) -> list[RouteInfo]:
241
+ from patchi.core.brain.route_detector.ruby import RubyRouteDetector
242
+
243
+ return [RouteInfo(**d) for d in RubyRouteDetector().detect(content, file_path)]
244
+
245
+
246
+ def _extract_grape(content: str, file_path: str) -> list[RouteInfo]:
247
+ return _extract_sinatra(content, file_path)
248
+
249
+
250
+ def _extract_nextjs_file_routes(file_path: str, root: Path | None = None) -> list[RouteInfo]:
251
+ from patchi.core.brain.route_detector.file_based import NextJsRouteDetector
252
+
253
+ return [RouteInfo(**d) for d in NextJsRouteDetector().detect("", file_path)]
254
+
255
+
256
+ def _extract_nuxt_file_routes(file_path: str, root: Path | None = None) -> list[RouteInfo]:
257
+ from patchi.core.brain.route_detector.file_based import NuxtRouteDetector
258
+
259
+ return [RouteInfo(**d) for d in NuxtRouteDetector().detect("", file_path)]
260
+
261
+
262
+ def _extract_sveltekit_file_routes(file_path: str) -> list[RouteInfo]:
263
+ from patchi.core.brain.route_detector.file_based import SvelteKitRouteDetector
264
+
265
+ return [RouteInfo(**d) for d in SvelteKitRouteDetector().detect("", file_path)]