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.
- patchi/__init__.py +1 -0
- patchi/__main__.py +13 -0
- patchi/cli/__init__.py +0 -0
- patchi/cli/command_families.py +235 -0
- patchi/cli/commands/__init__.py +0 -0
- patchi/cli/commands/access_cmd.py +65 -0
- patchi/cli/commands/agent_stats_cmd.py +273 -0
- patchi/cli/commands/agents_cmd.py +187 -0
- patchi/cli/commands/ai_cmd.py +308 -0
- patchi/cli/commands/assure_cmd.py +538 -0
- patchi/cli/commands/audit_cmd.py +286 -0
- patchi/cli/commands/auto_cmd.py +110 -0
- patchi/cli/commands/blame_cmd.py +53 -0
- patchi/cli/commands/chains_cmd.py +327 -0
- patchi/cli/commands/charter_cmd.py +173 -0
- patchi/cli/commands/chat_cmd.py +597 -0
- patchi/cli/commands/check_cmd.py +232 -0
- patchi/cli/commands/cleanup_cmd.py +328 -0
- patchi/cli/commands/cockpit_cmd.py +208 -0
- patchi/cli/commands/commands_cmd.py +160 -0
- patchi/cli/commands/cross_repo_cmd.py +113 -0
- patchi/cli/commands/deps_cmd.py +110 -0
- patchi/cli/commands/dev_check_cmd.py +342 -0
- patchi/cli/commands/dev_cmd.py +445 -0
- patchi/cli/commands/doctor_cmd.py +457 -0
- patchi/cli/commands/findings_cmd.py +187 -0
- patchi/cli/commands/fix_cmd.py +648 -0
- patchi/cli/commands/fix_review_cmd.py +273 -0
- patchi/cli/commands/heatmap_cmd.py +62 -0
- patchi/cli/commands/help_cmd.py +159 -0
- patchi/cli/commands/hosted_cmd.py +980 -0
- patchi/cli/commands/init.py +456 -0
- patchi/cli/commands/key_cmd.py +571 -0
- patchi/cli/commands/learn_cmd.py +140 -0
- patchi/cli/commands/link_cmd.py +104 -0
- patchi/cli/commands/log_cmd.py +57 -0
- patchi/cli/commands/memory_cmd.py +215 -0
- patchi/cli/commands/model_cmd.py +207 -0
- patchi/cli/commands/notify_cmd.py +213 -0
- patchi/cli/commands/notify_prompts.py +29 -0
- patchi/cli/commands/patch_cmd.py +231 -0
- patchi/cli/commands/plan_cmd.py +128 -0
- patchi/cli/commands/plugins_cmd.py +307 -0
- patchi/cli/commands/queue_cmd.py +152 -0
- patchi/cli/commands/quick_cmd.py +159 -0
- patchi/cli/commands/ready_cmd.py +292 -0
- patchi/cli/commands/report_cmd.py +416 -0
- patchi/cli/commands/restrict_cmd.py +127 -0
- patchi/cli/commands/review_cmd.py +225 -0
- patchi/cli/commands/rules_cmd.py +233 -0
- patchi/cli/commands/scan_cmd.py +1908 -0
- patchi/cli/commands/settings_cmd.py +45 -0
- patchi/cli/commands/status_cmd.py +679 -0
- patchi/cli/commands/test_cmd.py +1052 -0
- patchi/cli/commands/trend_cmd.py +296 -0
- patchi/cli/commands/undo_cmd.py +235 -0
- patchi/cli/commands/update_cmd.py +345 -0
- patchi/cli/commands/verify_cmd.py +56 -0
- patchi/cli/commands/vr_cmd.py +440 -0
- patchi/cli/commands/watch_cmd.py +304 -0
- patchi/cli/commands/web_cmd.py +114 -0
- patchi/cli/console.py +101 -0
- patchi/cli/display/__init__.py +1 -0
- patchi/cli/display/live_audit.py +269 -0
- patchi/cli/display/live_progress.py +169 -0
- patchi/cli/framework.py +241 -0
- patchi/cli/logo.py +128 -0
- patchi/cli/main.py +222 -0
- patchi/cli/registry.py +1171 -0
- patchi/cli/style.py +68 -0
- patchi/cli/themes.py +187 -0
- patchi/cli/ux.py +444 -0
- patchi/core/__init__.py +0 -0
- patchi/core/agents/__init__.py +0 -0
- patchi/core/agents/api_fuzzer_agent.py +141 -0
- patchi/core/agents/attack_agent.py +242 -0
- patchi/core/agents/base.py +1012 -0
- patchi/core/agents/bug_predictor_agent.py +58 -0
- patchi/core/agents/build_tool_validator.py +150 -0
- patchi/core/agents/cache.py +192 -0
- patchi/core/agents/chaos_agent.py +133 -0
- patchi/core/agents/cicd_generator.py +240 -0
- patchi/core/agents/comment_scanner.py +280 -0
- patchi/core/agents/console_logging_agent.py +156 -0
- patchi/core/agents/coordinator.py +858 -0
- patchi/core/agents/core_scanner.py +269 -0
- patchi/core/agents/coverage_prioritizer.py +181 -0
- patchi/core/agents/dead_code_hygiene.py +296 -0
- patchi/core/agents/dead_code_scanner.py +692 -0
- patchi/core/agents/dependency_scanner.py +725 -0
- patchi/core/agents/doc_claim_agent.py +573 -0
- patchi/core/agents/duplicate_scanner.py +568 -0
- patchi/core/agents/env_scanner.py +410 -0
- patchi/core/agents/feature_flag_agent.py +89 -0
- patchi/core/agents/frontend_framework_agent.py +133 -0
- patchi/core/agents/goroutine_agent.py +82 -0
- patchi/core/agents/governor.py +1972 -0
- patchi/core/agents/i18n_agent.py +95 -0
- patchi/core/agents/license_compliance.py +247 -0
- patchi/core/agents/linking_agent.py +251 -0
- patchi/core/agents/memory_profiler_agent.py +102 -0
- patchi/core/agents/modernization_agent.py +84 -0
- patchi/core/agents/mutation_agent.py +174 -0
- patchi/core/agents/nl_query_agent.py +74 -0
- patchi/core/agents/promise_rejection_agent.py +100 -0
- patchi/core/agents/refactoring_agent.py +286 -0
- patchi/core/agents/resource_leak_agent.py +91 -0
- patchi/core/agents/route_graph_scanner.py +951 -0
- patchi/core/agents/run_agent.py +106 -0
- patchi/core/agents/rust_unwrap_agent.py +100 -0
- patchi/core/agents/sbom_generator.py +284 -0
- patchi/core/agents/scanners.py +67 -0
- patchi/core/agents/side/__init__.py +1 -0
- patchi/core/agents/side/build_agent.py +65 -0
- patchi/core/agents/side/format_agent.py +50 -0
- patchi/core/agents/side/install_agent.py +63 -0
- patchi/core/agents/side_file_scanner.py +549 -0
- patchi/core/agents/snapshot_drift_detector.py +146 -0
- patchi/core/agents/spa_route_inventory.py +203 -0
- patchi/core/agents/test_scanner.py +442 -0
- patchi/core/agents/tool_health.py +109 -0
- patchi/core/agents/tool_runner.py +162 -0
- patchi/core/agents/type_scanner.py +168 -0
- patchi/core/agents/ui_scanner.py +558 -0
- patchi/core/ai/__init__.py +20 -0
- patchi/core/ai/agent_audit.py +153 -0
- patchi/core/ai/agent_profiler.py +277 -0
- patchi/core/ai/client.py +499 -0
- patchi/core/ai/cost_tracker.py +107 -0
- patchi/core/ai/model_router.py +318 -0
- patchi/core/ai/orchestrator.py +625 -0
- patchi/core/ai/prompts.py +681 -0
- patchi/core/ai/smart.py +302 -0
- patchi/core/ai/tool_executor.py +24 -0
- patchi/core/ai/tools/__init__.py +10 -0
- patchi/core/ai/tools/executor.py +621 -0
- patchi/core/ai/tools/realize.py +1160 -0
- patchi/core/ai/tools/registry.py +1577 -0
- patchi/core/assurance/__init__.py +33 -0
- patchi/core/assurance/builder.py +211 -0
- patchi/core/assurance/graph.py +342 -0
- patchi/core/assurance/invariants.py +168 -0
- patchi/core/atomic.py +61 -0
- patchi/core/attackers/__init__.py +17 -0
- patchi/core/attackers/api_abuse.py +89 -0
- patchi/core/attackers/auth_bypass.py +73 -0
- patchi/core/attackers/base.py +91 -0
- patchi/core/attackers/business_logic.py +88 -0
- patchi/core/attackers/planner.py +108 -0
- patchi/core/attackers/priv_escalation.py +88 -0
- patchi/core/attackers/recon.py +87 -0
- patchi/core/brain/__init__.py +0 -0
- patchi/core/brain/ast_utils/__init__.py +81 -0
- patchi/core/brain/ast_utils/assignments.py +219 -0
- patchi/core/brain/ast_utils/calls.py +139 -0
- patchi/core/brain/ast_utils/config.py +132 -0
- patchi/core/brain/ast_utils/control_flow.py +74 -0
- patchi/core/brain/ast_utils/dead_symbols.py +205 -0
- patchi/core/brain/ast_utils/decorators.py +108 -0
- patchi/core/brain/ast_utils/helpers.py +144 -0
- patchi/core/brain/ast_utils/imports.py +169 -0
- patchi/core/brain/ast_utils/scan.py +143 -0
- patchi/core/brain/ast_utils/taint.py +310 -0
- patchi/core/brain/audit.py +379 -0
- patchi/core/brain/baseline.py +195 -0
- patchi/core/brain/blast_radius.py +312 -0
- patchi/core/brain/body_tags.py +144 -0
- patchi/core/brain/brain.py +1161 -0
- patchi/core/brain/brain_context.py +393 -0
- patchi/core/brain/brain_watcher.py +340 -0
- patchi/core/brain/charter.py +473 -0
- patchi/core/brain/classifier.py +214 -0
- patchi/core/brain/cockpit.py +350 -0
- patchi/core/brain/code_query.py +710 -0
- patchi/core/brain/contract.py +889 -0
- patchi/core/brain/contract_diff.py +155 -0
- patchi/core/brain/council.py +800 -0
- patchi/core/brain/cross_repo.py +104 -0
- patchi/core/brain/dead_code_tools.py +157 -0
- patchi/core/brain/doc_validator.py +197 -0
- patchi/core/brain/domain_activator.py +2183 -0
- patchi/core/brain/enriched_context.py +220 -0
- patchi/core/brain/file_corpus.py +220 -0
- patchi/core/brain/framework.py +953 -0
- patchi/core/brain/freshness.py +273 -0
- patchi/core/brain/git_aware.py +206 -0
- patchi/core/brain/heatmap.py +104 -0
- patchi/core/brain/ignore_parser.py +153 -0
- patchi/core/brain/import_graph.py +486 -0
- patchi/core/brain/languages.py +397 -0
- patchi/core/brain/layered_brain.py +419 -0
- patchi/core/brain/learning.py +229 -0
- patchi/core/brain/orphaned_endpoints.py +313 -0
- patchi/core/brain/personas/__init__.py +648 -0
- patchi/core/brain/personas/bad_user.py +165 -0
- patchi/core/brain/personas/base.py +349 -0
- patchi/core/brain/proactive.py +807 -0
- patchi/core/brain/project_context.py +121 -0
- patchi/core/brain/project_reader.py +521 -0
- patchi/core/brain/reasoning.py +269 -0
- patchi/core/brain/route_detector/__init__.py +15 -0
- patchi/core/brain/route_detector/base.py +31 -0
- patchi/core/brain/route_detector/csharp.py +209 -0
- patchi/core/brain/route_detector/file_based.py +81 -0
- patchi/core/brain/route_detector/go.py +152 -0
- patchi/core/brain/route_detector/java.py +195 -0
- patchi/core/brain/route_detector/javascript.py +197 -0
- patchi/core/brain/route_detector/php.py +158 -0
- patchi/core/brain/route_detector/python.py +193 -0
- patchi/core/brain/route_detector/registry.py +25 -0
- patchi/core/brain/route_detector/ruby.py +134 -0
- patchi/core/brain/route_detector/rust.py +216 -0
- patchi/core/brain/route_detector/swift.py +118 -0
- patchi/core/brain/route_mapper.py +265 -0
- patchi/core/brain/scanner.py +2136 -0
- patchi/core/brain/secrets.py +280 -0
- patchi/core/brain/symbol_graph.py +1955 -0
- patchi/core/brain/team.py +28 -0
- patchi/core/brain/trace_log.py +132 -0
- patchi/core/brain/type_checker/__init__.py +65 -0
- patchi/core/brain/type_checker/base.py +60 -0
- patchi/core/brain/type_checker/csharp.py +59 -0
- patchi/core/brain/type_checker/dart.py +59 -0
- patchi/core/brain/type_checker/go.py +81 -0
- patchi/core/brain/type_checker/java.py +75 -0
- patchi/core/brain/type_checker/kotlin.py +75 -0
- patchi/core/brain/type_checker/php.py +88 -0
- patchi/core/brain/type_checker/python.py +87 -0
- patchi/core/brain/type_checker/rust.py +81 -0
- patchi/core/brain/type_checker/swift.py +59 -0
- patchi/core/brain/type_checker/typescript.py +298 -0
- patchi/core/brain/understander.py +130 -0
- patchi/core/brain/verify.py +379 -0
- patchi/core/campaigns/__init__.py +14 -0
- patchi/core/campaigns/base.py +62 -0
- patchi/core/campaigns/data_flow_abuse.py +153 -0
- patchi/core/campaigns/orchestrator.py +140 -0
- patchi/core/campaigns/state_transitions.py +178 -0
- patchi/core/ci_bundle.py +104 -0
- patchi/core/config.py +311 -0
- patchi/core/constants.py +245 -0
- patchi/core/debug/__init__.py +25 -0
- patchi/core/debug/adapters/__init__.py +11 -0
- patchi/core/debug/adapters/codelldb.py +379 -0
- patchi/core/debug/adapters/node.py +222 -0
- patchi/core/debug/adapters/powershell.py +210 -0
- patchi/core/debug/adapters/python.py +244 -0
- patchi/core/debug/capture.py +210 -0
- patchi/core/debug/dap_client.py +268 -0
- patchi/core/detector/__init__.py +0 -0
- patchi/core/detector/audit.py +194 -0
- patchi/core/detector/bus.py +226 -0
- patchi/core/detector/dispatcher.py +275 -0
- patchi/core/detector/event.py +254 -0
- patchi/core/detector/sigma_engine.py +378 -0
- patchi/core/detector/triage.py +289 -0
- patchi/core/export/sarif.py +113 -0
- patchi/core/fix/__init__.py +17 -0
- patchi/core/fix/applier.py +574 -0
- patchi/core/fix/base.py +510 -0
- patchi/core/fix/code_fixer.py +169 -0
- patchi/core/fix/dead_code_remover.py +131 -0
- patchi/core/fix/fix_agents.py +775 -0
- patchi/core/fix/patch.py +444 -0
- patchi/core/fix/risk_gate.py +383 -0
- patchi/core/fix/security_fixer.py +93 -0
- patchi/core/fix/verify_loop.py +204 -0
- patchi/core/fuzz/__init__.py +8 -0
- patchi/core/fuzz/corpus.py +137 -0
- patchi/core/fuzz/input_fuzzer.py +256 -0
- patchi/core/fuzz/sequence_fuzzer.py +162 -0
- patchi/core/fuzz/state_fuzzer.py +236 -0
- patchi/core/health.py +407 -0
- patchi/core/hosted/__init__.py +1 -0
- patchi/core/hosted/anomaly.py +298 -0
- patchi/core/hosted/audit_log.py +102 -0
- patchi/core/hosted/compliance_report.py +148 -0
- patchi/core/hosted/ip_reputation.py +169 -0
- patchi/core/hosted/log_parsers.py +251 -0
- patchi/core/hosted/tokens.py +127 -0
- patchi/core/hosted/watchlist.py +164 -0
- patchi/core/hosted/webhooks.py +156 -0
- patchi/core/memory.py +437 -0
- patchi/core/notifications/__init__.py +18 -0
- patchi/core/notifications/channels.py +192 -0
- patchi/core/notifications/digest.py +141 -0
- patchi/core/notifications/escalation.py +158 -0
- patchi/core/notifications/notifier.py +182 -0
- patchi/core/notifications/quiet_hours.py +69 -0
- patchi/core/plugins/__init__.py +48 -0
- patchi/core/plugins/analyzer.py +326 -0
- patchi/core/plugins/analyzers/__init__.py +6 -0
- patchi/core/plugins/analyzers/dead_code_analyzer.py +120 -0
- patchi/core/plugins/analyzers/secret_scanner.py +158 -0
- patchi/core/plugins/analyzers/todo_scanner.py +115 -0
- patchi/core/plugins/registry.py +335 -0
- patchi/core/queue.py +375 -0
- patchi/core/reliability/__init__.py +13 -0
- patchi/core/reliability/chaos.py +163 -0
- patchi/core/reliability/fault_injector.py +172 -0
- patchi/core/reliability/idempotency.py +128 -0
- patchi/core/reliability/recovery.py +147 -0
- patchi/core/runtime/__init__.py +5 -0
- patchi/core/runtime/tracer.py +230 -0
- patchi/core/scan_bus.py +156 -0
- patchi/core/security/__init__.py +1 -0
- patchi/core/security/ai_validator.py +462 -0
- patchi/core/security/app_mapper.py +216 -0
- patchi/core/security/app_profile.py +464 -0
- patchi/core/security/attack_feedback.py +141 -0
- patchi/core/security/attack_scenarios/__init__.py +1 -0
- patchi/core/security/attack_tree.py +176 -0
- patchi/core/security/auth_audit_agent.py +344 -0
- patchi/core/security/authz_agent.py +602 -0
- patchi/core/security/auto_fix_proactive.py +620 -0
- patchi/core/security/auto_fixer.py +660 -0
- patchi/core/security/auto_ticket.py +53 -0
- patchi/core/security/bandit_agent.py +152 -0
- patchi/core/security/blast_radius.py +226 -0
- patchi/core/security/browser_tester.py +333 -0
- patchi/core/security/business_logic_agent.py +263 -0
- patchi/core/security/catch_block_auditor.py +395 -0
- patchi/core/security/cdn_cache_agent.py +357 -0
- patchi/core/security/chain_analyzer.py +321 -0
- patchi/core/security/chain_to_assurance.py +168 -0
- patchi/core/security/charter.py +510 -0
- patchi/core/security/cloud_waf_detector.py +295 -0
- patchi/core/security/codeql_agent.py +233 -0
- patchi/core/security/compliance_agent.py +348 -0
- patchi/core/security/confidence_gate.py +423 -0
- patchi/core/security/container_scanner.py +282 -0
- patchi/core/security/crypto_agent.py +378 -0
- patchi/core/security/cve_monitor.py +262 -0
- patchi/core/security/dast_agent.py +865 -0
- patchi/core/security/defectdojo.py +238 -0
- patchi/core/security/defenders/__init__.py +75 -0
- patchi/core/security/defenders/auth_middleware.py +115 -0
- patchi/core/security/defenders/base.py +97 -0
- patchi/core/security/defenders/block_ip.py +71 -0
- patchi/core/security/defenders/block_ws_origin.py +36 -0
- patchi/core/security/defenders/crypto_fix.py +118 -0
- patchi/core/security/defenders/enforce_rate_limit.py +108 -0
- patchi/core/security/defenders/fix_code.py +93 -0
- patchi/core/security/defenders/invalidate_session.py +40 -0
- patchi/core/security/defenders/patch_config.py +70 -0
- patchi/core/security/defenders/rotate_secret.py +54 -0
- patchi/core/security/defenders/suspend_account.py +41 -0
- patchi/core/security/defenders/update_dependency.py +160 -0
- patchi/core/security/defense_layer.py +217 -0
- patchi/core/security/dependency_vulnerability_agent.py +616 -0
- patchi/core/security/detection_pipeline.py +289 -0
- patchi/core/security/dns_security_agent.py +497 -0
- patchi/core/security/domain_activator_v2.py +913 -0
- patchi/core/security/domain_loader.py +1004 -0
- patchi/core/security/domains/__init__.py +0 -0
- patchi/core/security/email_authentication_agent.py +417 -0
- patchi/core/security/env_var_validator.py +304 -0
- patchi/core/security/evidence.py +100 -0
- patchi/core/security/falco_runtime_agent.py +387 -0
- patchi/core/security/fix-playbooks/__init__.py +0 -0
- patchi/core/security/gated_finding.py +85 -0
- patchi/core/security/git_diff_activator.py +367 -0
- patchi/core/security/governance.py +208 -0
- patchi/core/security/gradual_gate.py +34 -0
- patchi/core/security/history.py +315 -0
- patchi/core/security/iac_scanner.py +250 -0
- patchi/core/security/ignore_expiry.py +111 -0
- patchi/core/security/ignore_learner.py +416 -0
- patchi/core/security/injection_agent.py +319 -0
- patchi/core/security/insecure_randomness_agent.py +288 -0
- patchi/core/security/intent_analyzer.py +326 -0
- patchi/core/security/jwt_agent.py +453 -0
- patchi/core/security/kubernetes_agent.py +638 -0
- patchi/core/security/layer2_orchestrator.py +341 -0
- patchi/core/security/llm_security_agent.py +252 -0
- patchi/core/security/misconfig_agent.py +600 -0
- patchi/core/security/mobile_security_agent.py +474 -0
- patchi/core/security/network_agent.py +376 -0
- patchi/core/security/noise_filter.py +274 -0
- patchi/core/security/orchestrator.py +313 -0
- patchi/core/security/pattern_context.py +125 -0
- patchi/core/security/pattern_loader.py +101 -0
- patchi/core/security/pentest/__init__.py +4 -0
- patchi/core/security/pentest/base.py +58 -0
- patchi/core/security/pentest/dalfox_adapter.py +40 -0
- patchi/core/security/pentest/ffuf_adapter.py +48 -0
- patchi/core/security/pentest/nuclei_adapter.py +50 -0
- patchi/core/security/pentest/registry.py +80 -0
- patchi/core/security/pentest/shannon_adapter.py +107 -0
- patchi/core/security/pentest/sqlmap_adapter.py +56 -0
- patchi/core/security/pentest/zap_adapter.py +52 -0
- patchi/core/security/plan_auditor.py +276 -0
- patchi/core/security/policy_engine.py +272 -0
- patchi/core/security/prechecks.py +172 -0
- patchi/core/security/precommit_hook.py +247 -0
- patchi/core/security/privacy_agent.py +361 -0
- patchi/core/security/push_notification_agent.py +417 -0
- patchi/core/security/pysa_agent.py +143 -0
- patchi/core/security/reasoning.py +442 -0
- patchi/core/security/red_team_agent.py +184 -0
- patchi/core/security/red_team_engine.py +1142 -0
- patchi/core/security/remediation.py +360 -0
- patchi/core/security/request_interceptor.py +294 -0
- patchi/core/security/runtime_validator.py +245 -0
- patchi/core/security/saml_sso_agent.py +401 -0
- patchi/core/security/sast_agent.py +213 -0
- patchi/core/security/sast_gate.py +95 -0
- patchi/core/security/scheduler.py +287 -0
- patchi/core/security/secrets_runtime_agent.py +476 -0
- patchi/core/security/security_agents.py +175 -0
- patchi/core/security/security_config.py +551 -0
- patchi/core/security/security_probe.py +762 -0
- patchi/core/security/security_taint.py +1005 -0
- patchi/core/security/sensitive_data_agent.py +271 -0
- patchi/core/security/service_mesh_agent.py +412 -0
- patchi/core/security/session_management_agent.py +245 -0
- patchi/core/security/ssrf_agent.py +422 -0
- patchi/core/security/supply_chain.py +449 -0
- patchi/core/security/threat_model_generator.py +378 -0
- patchi/core/security/threat_model_updater.py +196 -0
- patchi/core/security/tool_adapters.py +135 -0
- patchi/core/security/tool_verify.py +173 -0
- patchi/core/security/websocket_security_agent.py +188 -0
- patchi/core/snapshot.py +242 -0
- patchi/core/tenant.py +386 -0
- patchi/core/testing/__init__.py +17 -0
- patchi/core/testing/_browser.py +147 -0
- patchi/core/testing/ads_agent.py +141 -0
- patchi/core/testing/api_contract_agent.py +450 -0
- patchi/core/testing/app_discovery_agent.py +641 -0
- patchi/core/testing/app_launcher.py +184 -0
- patchi/core/testing/browser_test_agent.py +516 -0
- patchi/core/testing/e2e_flow_agent.py +354 -0
- patchi/core/testing/flake_detector_agent.py +292 -0
- patchi/core/testing/gate.py +31 -0
- patchi/core/testing/live_test_runner.py +304 -0
- patchi/core/testing/live_v2/__init__.py +1 -0
- patchi/core/testing/live_v2/browser_pool.py +349 -0
- patchi/core/testing/live_v2/browser_test_runner.py +313 -0
- patchi/core/testing/live_v2/runner.py +626 -0
- patchi/core/testing/live_v2/screenshot_manager.py +474 -0
- patchi/core/testing/live_v2/stress_orchestrator.py +523 -0
- patchi/core/testing/live_v2/video_recorder.py +303 -0
- patchi/core/testing/regression_agent.py +302 -0
- patchi/core/testing/security_test_agent.py +253 -0
- patchi/core/testing/stress_test_agent.py +203 -0
- patchi/core/testing/test_agents.py +50 -0
- patchi/core/testing/test_config.py +194 -0
- patchi/core/testing/ui_accessibility_agent.py +324 -0
- patchi/core/testing/ui_button_agent.py +294 -0
- patchi/core/testing/ui_layout_agent.py +330 -0
- patchi/core/testing/unit_test_agent.py +1149 -0
- patchi/core/testing/visual_regression_agent.py +260 -0
- patchi/web/__init__.py +1 -0
- patchi/web/api/__init__.py +1 -0
- patchi/web/api/brain_map.py +114 -0
- patchi/web/api/charts.py +47 -0
- patchi/web/api/chat.py +224 -0
- patchi/web/api/cicd.py +576 -0
- patchi/web/api/dast_evidence.py +49 -0
- patchi/web/api/dev_check.py +320 -0
- patchi/web/api/fix.py +134 -0
- patchi/web/api/guard.py +65 -0
- patchi/web/api/hosted.py +128 -0
- patchi/web/api/hosted_v2.py +234 -0
- patchi/web/api/live_testing.py +699 -0
- patchi/web/api/scan.py +582 -0
- patchi/web/api/smart.py +111 -0
- patchi/web/api/tenant.py +117 -0
- patchi/web/api/tools.py +85 -0
- patchi/web/api_legacy.py +2401 -0
- patchi/web/app.py +310 -0
- patchi/web/events.py +483 -0
- patchi/web/routes/__init__.py +1 -0
- patchi/web/routes/assurance.py +541 -0
- patchi/web/routes/brain.py +36 -0
- patchi/web/routes/charter.py +227 -0
- patchi/web/routes/chat.py +23 -0
- patchi/web/routes/dashboard.py +558 -0
- patchi/web/routes/dashboard_v2.py +402 -0
- patchi/web/routes/findings.py +330 -0
- patchi/web/routes/guard.py +35 -0
- patchi/web/routes/history.py +126 -0
- patchi/web/routes/landing.py +52 -0
- patchi/web/routes/live_testing.py +24 -0
- patchi/web/routes/review.py +57 -0
- patchi/web/routes/self_improvement.py +110 -0
- patchi/web/routes/settings.py +49 -0
- patchi/web/routes/tokens.py +29 -0
- patchi/web/spawn.py +139 -0
- patchi/web/ws.py +141 -0
- patchi-0.7.5.dist-info/METADATA +315 -0
- patchi-0.7.5.dist-info/RECORD +496 -0
- patchi-0.7.5.dist-info/WHEEL +5 -0
- patchi-0.7.5.dist-info/licenses/LICENSE +60 -0
- patchi-0.7.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enhanced Web Dashboard v2 — Real-time monitoring and control interface.
|
|
3
|
+
|
|
4
|
+
Features:
|
|
5
|
+
- Live agent execution stream
|
|
6
|
+
- Council deliberation viewer
|
|
7
|
+
- Brain map visualization
|
|
8
|
+
- Attack timeline
|
|
9
|
+
- Test session monitoring
|
|
10
|
+
- Command palette for AI tool calls
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import json
|
|
16
|
+
import logging
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from fastapi import APIRouter, Request, WebSocket, WebSocketDisconnect
|
|
20
|
+
from starlette.templating import Jinja2Templates
|
|
21
|
+
|
|
22
|
+
router = APIRouter()
|
|
23
|
+
|
|
24
|
+
templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))
|
|
25
|
+
templates.env.filters["tojson"] = lambda v: json.dumps(v)
|
|
26
|
+
|
|
27
|
+
_log = logging.getLogger("patchi.web.dashboard_v2")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Page routes removed — all pages now served from v1 templates/ via main dashboard.py
|
|
31
|
+
# Only API endpoints and WebSocket remain here
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# WebSocket endpoints for real-time updates
|
|
35
|
+
@router.websocket("/ws/v2")
|
|
36
|
+
async def websocket_v2(ws: WebSocket):
|
|
37
|
+
"""Enhanced WebSocket for real-time dashboard updates."""
|
|
38
|
+
await ws.accept()
|
|
39
|
+
|
|
40
|
+
root = ws.app.state.root
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
# Send initial state
|
|
44
|
+
await _send_initial_state(ws, root)
|
|
45
|
+
|
|
46
|
+
# Listen for messages
|
|
47
|
+
while True:
|
|
48
|
+
raw = await ws.receive_text()
|
|
49
|
+
await _handle_ws_message(ws, root, raw)
|
|
50
|
+
|
|
51
|
+
except WebSocketDisconnect:
|
|
52
|
+
pass
|
|
53
|
+
except Exception as e:
|
|
54
|
+
_log.error(f"WebSocket error: {e}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
async def _send_initial_state(ws: WebSocket, root: Path):
|
|
58
|
+
"""Send initial dashboard state."""
|
|
59
|
+
from patchi.core import config as cfg
|
|
60
|
+
from patchi.core import memory as mem
|
|
61
|
+
from patchi.core.health import compute as compute_health
|
|
62
|
+
|
|
63
|
+
brain = mem.get_brain(root)
|
|
64
|
+
conf = cfg.load(root)
|
|
65
|
+
hs = compute_health(root)
|
|
66
|
+
|
|
67
|
+
await ws.send_json(
|
|
68
|
+
{
|
|
69
|
+
"event": "initial_state",
|
|
70
|
+
"data": {
|
|
71
|
+
"health_score": hs.total,
|
|
72
|
+
"health_grade": hs.grade,
|
|
73
|
+
"health_components": hs.to_dict()["components"],
|
|
74
|
+
"file_count": brain.get("file_count", 0),
|
|
75
|
+
"route_count": brain.get("route_count", 0),
|
|
76
|
+
"framework": brain.get("framework", "Unknown"),
|
|
77
|
+
"mode": conf.get("mode", "confirm"),
|
|
78
|
+
"active_domains": brain.get("active_security_domains", []),
|
|
79
|
+
"project_purpose": brain.get("project_purpose", ""),
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
async def _handle_ws_message(ws: WebSocket, root: Path, raw: str):
|
|
86
|
+
"""Handle incoming WebSocket messages."""
|
|
87
|
+
try:
|
|
88
|
+
import json
|
|
89
|
+
|
|
90
|
+
msg = json.loads(raw)
|
|
91
|
+
action = msg.get("action", "")
|
|
92
|
+
data = msg.get("data", {})
|
|
93
|
+
|
|
94
|
+
if action == "ping":
|
|
95
|
+
await ws.send_json({"event": "pong", "data": {}})
|
|
96
|
+
|
|
97
|
+
elif action == "subscribe":
|
|
98
|
+
# Subscribe to event streams
|
|
99
|
+
channels = data.get("channels", [])
|
|
100
|
+
await ws.send_json({"event": "subscribed", "data": {"channels": channels}})
|
|
101
|
+
|
|
102
|
+
elif action == "council_query":
|
|
103
|
+
# Query council for analysis
|
|
104
|
+
from patchi.core.brain.council import run_council
|
|
105
|
+
|
|
106
|
+
issue = data.get("issue", "")
|
|
107
|
+
session = await run_council(root, issue)
|
|
108
|
+
await ws.send_json(
|
|
109
|
+
{
|
|
110
|
+
"event": "council_result",
|
|
111
|
+
"data": {
|
|
112
|
+
"issue": issue,
|
|
113
|
+
"synthesis": session.synthesis,
|
|
114
|
+
"action_plan": session.action_plan,
|
|
115
|
+
"consensus": session.consensus_reached,
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
elif action == "tool_call":
|
|
121
|
+
# Execute AI tool call
|
|
122
|
+
from patchi.core.ai.tool_executor import ToolExecutor, WebConfirmationProvider
|
|
123
|
+
|
|
124
|
+
tool_name = data.get("tool")
|
|
125
|
+
parameters = data.get("parameters", {})
|
|
126
|
+
|
|
127
|
+
executor = ToolExecutor(root, confirmation_provider=WebConfirmationProvider())
|
|
128
|
+
exec_result = await executor.execute(tool_name, parameters, invoked_by="dashboard")
|
|
129
|
+
|
|
130
|
+
await ws.send_json(
|
|
131
|
+
{
|
|
132
|
+
"event": "tool_result",
|
|
133
|
+
"data": {
|
|
134
|
+
"tool": tool_name,
|
|
135
|
+
"success": exec_result.success,
|
|
136
|
+
"result": exec_result.result,
|
|
137
|
+
"error": exec_result.error,
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
elif action == "start_scan":
|
|
143
|
+
# 1:1 with the CLI: run the actual `p scan` pipeline, not a
|
|
144
|
+
# stripped-down Brain.scan(). Results are read back from memory
|
|
145
|
+
# because the CLI handler reports via rich console instead of
|
|
146
|
+
# returning values. Offloaded to a thread so the socket stays live.
|
|
147
|
+
import asyncio as _asyncio
|
|
148
|
+
|
|
149
|
+
from patchi.core import memory as mem
|
|
150
|
+
|
|
151
|
+
def _cli_scan():
|
|
152
|
+
from patchi.cli.commands.scan_cmd import run as cli_scan
|
|
153
|
+
|
|
154
|
+
cli_scan(root=root, quiet=True, no_logo=True)
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
await _asyncio.to_thread(_cli_scan)
|
|
158
|
+
brain_mem = mem.get_brain(root)
|
|
159
|
+
scans = mem.get_scan_results(root)
|
|
160
|
+
brain_meta = scans.get("Brain", {})
|
|
161
|
+
await ws.send_json(
|
|
162
|
+
{
|
|
163
|
+
"event": "scan_completed",
|
|
164
|
+
"data": {
|
|
165
|
+
"file_count": brain_mem.get("file_count", 0),
|
|
166
|
+
"route_count": brain_mem.get("route_count", 0),
|
|
167
|
+
"duration": brain_meta.get("duration", 0),
|
|
168
|
+
},
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
_log.error("CLI scan failed: %s", e)
|
|
173
|
+
await ws.send_json({"event": "error", "data": {"message": f"Scan failed: {e}"}})
|
|
174
|
+
|
|
175
|
+
elif action == "start_red_team":
|
|
176
|
+
# Trigger red team assessment
|
|
177
|
+
from patchi.core.security.red_team_engine import run_red_team
|
|
178
|
+
|
|
179
|
+
report = await run_red_team(root, safe_mode=data.get("safe_mode", True))
|
|
180
|
+
await ws.send_json(
|
|
181
|
+
{
|
|
182
|
+
"event": "red_team_completed",
|
|
183
|
+
"data": {
|
|
184
|
+
"assessment_id": report.assessment_id,
|
|
185
|
+
"findings": report.total_findings,
|
|
186
|
+
"by_severity": report.by_severity,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
elif action == "start_live_test":
|
|
192
|
+
# Trigger live test
|
|
193
|
+
from patchi.core.testing.live_v2.runner import LiveTestConfigV2, run_live_tests_v2
|
|
194
|
+
from patchi.core.testing.live_v2.stress_orchestrator import StressConfig
|
|
195
|
+
|
|
196
|
+
test_config = LiveTestConfigV2(
|
|
197
|
+
test_types=data.get("test_types", ["browser", "visual"]),
|
|
198
|
+
base_url=data.get("base_url"),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
if data.get("stress"):
|
|
202
|
+
test_config.stress_config = StressConfig(
|
|
203
|
+
base_url=data.get("base_url"),
|
|
204
|
+
scenario=data.get("stress_scenario", "load"),
|
|
205
|
+
users=data.get("stress_users", 10),
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
result = await run_live_tests_v2(root, test_config)
|
|
209
|
+
await ws.send_json(
|
|
210
|
+
{
|
|
211
|
+
"event": "live_test_completed",
|
|
212
|
+
"data": result.to_dict(),
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
_log.error(f"WebSocket message handling failed: {e}")
|
|
218
|
+
await ws.send_json({"event": "error", "data": {"message": str(e)}})
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# API endpoints for dashboard data
|
|
222
|
+
@router.get("/api/v2/agents/stream")
|
|
223
|
+
async def agents_stream(request: Request):
|
|
224
|
+
"""Stream agent execution events."""
|
|
225
|
+
# This would return Server-Sent Events
|
|
226
|
+
from fastapi.responses import StreamingResponse
|
|
227
|
+
|
|
228
|
+
async def event_generator():
|
|
229
|
+
# Stream agent events from memory
|
|
230
|
+
from patchi.core import memory as mem
|
|
231
|
+
|
|
232
|
+
root = request.app.state.root
|
|
233
|
+
scan_results = mem.get_scan_results(root)
|
|
234
|
+
|
|
235
|
+
for scanner, data in scan_results.items():
|
|
236
|
+
yield f"data: {json.dumps({'agent': scanner, 'status': 'completed', 'findings': len(data.get('findings', []))})}\n\n"
|
|
237
|
+
await asyncio.sleep(0.1)
|
|
238
|
+
|
|
239
|
+
return StreamingResponse(event_generator(), media_type="text/event-stream")
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
@router.get("/api/v2/brain/layers")
|
|
243
|
+
async def get_brain_layers(request: Request):
|
|
244
|
+
"""Get layered brain data for visualization."""
|
|
245
|
+
from patchi.core import memory as mem
|
|
246
|
+
|
|
247
|
+
root = request.app.state.root
|
|
248
|
+
layers_data = mem.get_layers(root)
|
|
249
|
+
return layers_data
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@router.get("/api/v2/council/sessions")
|
|
253
|
+
async def get_council_sessions(request: Request):
|
|
254
|
+
"""Get council session history."""
|
|
255
|
+
from patchi.core import memory as mem
|
|
256
|
+
|
|
257
|
+
root = request.app.state.root
|
|
258
|
+
history = mem.read(mem.MemoryCategory.ISSUES, root)
|
|
259
|
+
sessions = [s for s in history if s.get("type") == "council_session"]
|
|
260
|
+
return {"sessions": sessions[-50:]}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@router.get("/api/v2/attack/timeline")
|
|
264
|
+
async def get_attack_timeline(request: Request):
|
|
265
|
+
"""Get attack simulation timeline."""
|
|
266
|
+
from patchi.core import memory as mem
|
|
267
|
+
|
|
268
|
+
root = request.app.state.root
|
|
269
|
+
scan_results = mem.get_scan_results(root)
|
|
270
|
+
attack_data = scan_results.get("RedTeamEngineAgent", {})
|
|
271
|
+
return attack_data
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@router.get("/api/v2/live-tests/status")
|
|
275
|
+
async def get_live_test_status(request: Request):
|
|
276
|
+
"""Get live test status."""
|
|
277
|
+
from patchi.core import memory as mem
|
|
278
|
+
|
|
279
|
+
root = request.app.state.root
|
|
280
|
+
scan_results = mem.get_scan_results(root)
|
|
281
|
+
test_data = scan_results.get("TestRunner", {})
|
|
282
|
+
return test_data
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@router.post("/api/v2/tools/execute")
|
|
286
|
+
async def execute_tool(request: Request):
|
|
287
|
+
"""Execute an AI tool call from dashboard."""
|
|
288
|
+
from patchi.core.ai.tool_executor import ToolExecutor, WebConfirmationProvider
|
|
289
|
+
|
|
290
|
+
root = request.app.state.root
|
|
291
|
+
|
|
292
|
+
data = await request.json()
|
|
293
|
+
tool_name = data.get("tool")
|
|
294
|
+
parameters = data.get("parameters", {})
|
|
295
|
+
|
|
296
|
+
executor = ToolExecutor(root, confirmation_provider=WebConfirmationProvider())
|
|
297
|
+
result = await executor.execute(tool_name, parameters, invoked_by="dashboard")
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
"success": result.success,
|
|
301
|
+
"result": result.result,
|
|
302
|
+
"error": result.error,
|
|
303
|
+
"invocation_id": result.invocation_id,
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@router.get("/api/v2/tools/list")
|
|
308
|
+
async def list_tools(request: Request):
|
|
309
|
+
"""List all available AI tools."""
|
|
310
|
+
from patchi.core.ai.tools.registry import get_tool_registry
|
|
311
|
+
|
|
312
|
+
registry = get_tool_registry()
|
|
313
|
+
|
|
314
|
+
category = request.query_params.get("category")
|
|
315
|
+
tools = registry.list_tools(category)
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
"tools": [
|
|
319
|
+
{
|
|
320
|
+
"name": t.name,
|
|
321
|
+
"description": t.description,
|
|
322
|
+
"category": t.category,
|
|
323
|
+
"requires_confirmation": t.requires_confirmation,
|
|
324
|
+
"side_effects": t.side_effects,
|
|
325
|
+
}
|
|
326
|
+
for t in tools
|
|
327
|
+
]
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
@router.post("/api/v2/council/deliberate")
|
|
332
|
+
async def deliberate(request: Request):
|
|
333
|
+
"""Run a full Council deliberation on an issue (REST form of the WS action).
|
|
334
|
+
|
|
335
|
+
Persists the session into memory so /council history shows it.
|
|
336
|
+
Body: {"issue": "..."}
|
|
337
|
+
"""
|
|
338
|
+
from fastapi.responses import JSONResponse
|
|
339
|
+
|
|
340
|
+
root = request.app.state.root
|
|
341
|
+
try:
|
|
342
|
+
body = await request.json()
|
|
343
|
+
except Exception:
|
|
344
|
+
return JSONResponse({"error": "JSON body required"}, status_code=400)
|
|
345
|
+
|
|
346
|
+
issue = (body.get("issue") or "").strip()
|
|
347
|
+
if not issue:
|
|
348
|
+
return JSONResponse({"error": "issue is required"}, status_code=400)
|
|
349
|
+
|
|
350
|
+
try:
|
|
351
|
+
from patchi.core.brain.council import run_council
|
|
352
|
+
|
|
353
|
+
session = await run_council(root, issue)
|
|
354
|
+
except Exception as e:
|
|
355
|
+
_log.error("Council deliberation failed: %s", e)
|
|
356
|
+
return JSONResponse({"error": f"Deliberation failed: {e}"}, status_code=500)
|
|
357
|
+
|
|
358
|
+
# Persist so the history panel on /council shows it
|
|
359
|
+
try:
|
|
360
|
+
from patchi.core import memory as mem
|
|
361
|
+
|
|
362
|
+
mem.save_issue(
|
|
363
|
+
{
|
|
364
|
+
"type": "council_session",
|
|
365
|
+
"issue": issue,
|
|
366
|
+
"synthesis": session.synthesis,
|
|
367
|
+
"consensus": session.consensus_reached,
|
|
368
|
+
"timestamp": session.started_at,
|
|
369
|
+
"decisions": [
|
|
370
|
+
{
|
|
371
|
+
"persona_name": d.persona_name,
|
|
372
|
+
"analysis": d.analysis,
|
|
373
|
+
"recommendation": d.recommendation,
|
|
374
|
+
"confidence": d.confidence,
|
|
375
|
+
}
|
|
376
|
+
for d in session.persona_decisions
|
|
377
|
+
],
|
|
378
|
+
"action_plan": session.action_plan,
|
|
379
|
+
},
|
|
380
|
+
root,
|
|
381
|
+
)
|
|
382
|
+
except Exception as e:
|
|
383
|
+
_log.warning("Failed to persist council session: %s", e)
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
"issue": issue,
|
|
387
|
+
"synthesis": session.synthesis,
|
|
388
|
+
"consensus": session.consensus_reached,
|
|
389
|
+
"action_plan": session.action_plan,
|
|
390
|
+
"decisions": [
|
|
391
|
+
{
|
|
392
|
+
"persona_name": d.persona_name,
|
|
393
|
+
"analysis": d.analysis,
|
|
394
|
+
"recommendation": d.recommendation,
|
|
395
|
+
"confidence": d.confidence,
|
|
396
|
+
}
|
|
397
|
+
for d in session.persona_decisions
|
|
398
|
+
],
|
|
399
|
+
"duration_ms": session.duration_ms,
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
|