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,345 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`p update` — Check for and apply updates to Patchi.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
p update — check for updates, prompt to install if newer available
|
|
6
|
+
p update --check — check only, no install prompt
|
|
7
|
+
p update --force — force reinstall/refresh current version
|
|
8
|
+
p update --auto — auto-install without prompting (for CI/scripts)
|
|
9
|
+
|
|
10
|
+
Auto-update check:
|
|
11
|
+
On startup, Patchi checks for updates silently once per week.
|
|
12
|
+
A notification is shown on the next command if a newer version exists.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
|
|
19
|
+
# ── Config ────────────────────────────────────────────────────────────────────
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
import time
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from rich.prompt import Confirm
|
|
26
|
+
|
|
27
|
+
from patchi import __version__
|
|
28
|
+
from patchi.cli.console import con
|
|
29
|
+
|
|
30
|
+
UPDATE_SOURCE: dict[str, str] = {
|
|
31
|
+
"type": "github",
|
|
32
|
+
"owner": os.environ.get("PATCHI_UPDATE_OWNER", ""),
|
|
33
|
+
"repo": os.environ.get("PATCHI_UPDATE_REPO", "patchi"),
|
|
34
|
+
"pip_name": os.environ.get("PATCHI_PIP_NAME", "patchi"),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
CHECK_FILE = ".patchi/update_check.json"
|
|
38
|
+
CHECK_INTERVAL_DAYS = 7
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ── Public entry points ───────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_log = logging.getLogger("patchi.cli.update_cmd")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def run(
|
|
48
|
+
check: bool = False,
|
|
49
|
+
force: bool = False,
|
|
50
|
+
auto: bool = False,
|
|
51
|
+
root: Path | None = None,
|
|
52
|
+
) -> None:
|
|
53
|
+
"""Entry point for `p update`."""
|
|
54
|
+
from patchi.core.config import require_project_root
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
r = root or require_project_root()
|
|
58
|
+
except RuntimeError:
|
|
59
|
+
r = Path.cwd()
|
|
60
|
+
|
|
61
|
+
if force:
|
|
62
|
+
_force_reinstall(r)
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
if check:
|
|
66
|
+
_check_only(r)
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
# Full check + prompt to install
|
|
70
|
+
info = _fetch_latest(r)
|
|
71
|
+
if info is None:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
latest = info.get("version", "")
|
|
75
|
+
if not latest or not _is_newer(latest, __version__):
|
|
76
|
+
con.print(f"[#4ADE80]Already up to date:[/#4ADE80] v{__version__}")
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
_print_release_info(info)
|
|
80
|
+
if auto:
|
|
81
|
+
_do_install(r, info)
|
|
82
|
+
else:
|
|
83
|
+
if Confirm.ask(f"Update to v{latest}?", default=True):
|
|
84
|
+
_do_install(r, info)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def run_check(root: Path | None = None) -> dict | None:
|
|
88
|
+
"""Silent check — called from background thread. Returns update info or None."""
|
|
89
|
+
from patchi.core.config import require_project_root
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
r = root or require_project_root()
|
|
93
|
+
except RuntimeError:
|
|
94
|
+
r = Path.cwd()
|
|
95
|
+
try:
|
|
96
|
+
return _fetch_latest(r, silent=True)
|
|
97
|
+
except Exception as e:
|
|
98
|
+
_log.warning("run_check failed: %s", e)
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ── Auto-update check (called from main.py on startup) ────────────────────────
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def auto_check_background(root: Path | None = None) -> None:
|
|
106
|
+
"""
|
|
107
|
+
Background thread target: checks for updates once per week.
|
|
108
|
+
Stores result in .patchi/update_check.json for display on next command.
|
|
109
|
+
"""
|
|
110
|
+
from patchi.core.config import require_project_root
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
r = root or require_project_root()
|
|
114
|
+
except RuntimeError:
|
|
115
|
+
r = Path.cwd()
|
|
116
|
+
|
|
117
|
+
check_path = r / CHECK_FILE
|
|
118
|
+
try:
|
|
119
|
+
if check_path.exists():
|
|
120
|
+
data = json.loads(check_path.read_text(encoding="utf-8"))
|
|
121
|
+
last = data.get("last_check", 0)
|
|
122
|
+
if time.time() - last < CHECK_INTERVAL_DAYS * 86400:
|
|
123
|
+
return # too soon
|
|
124
|
+
except Exception as e:
|
|
125
|
+
_log.warning("auto_check_background failed: %s", e)
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
info = _fetch_latest(r, silent=True)
|
|
129
|
+
if info:
|
|
130
|
+
check_path.parent.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
check_path.write_text(json.dumps({**info, "last_check": time.time()}), encoding="utf-8")
|
|
132
|
+
except Exception as e:
|
|
133
|
+
_log.warning("auto_check_background failed: %s", e)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def print_update_available_if_needed(root: Path | None = None) -> None:
|
|
137
|
+
"""Called by main.py after command dispatch — shows notification if update available."""
|
|
138
|
+
from patchi.core.config import require_project_root
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
r = root or require_project_root()
|
|
142
|
+
except RuntimeError:
|
|
143
|
+
r = Path.cwd()
|
|
144
|
+
|
|
145
|
+
check_path = r / CHECK_FILE
|
|
146
|
+
if not check_path.exists():
|
|
147
|
+
return
|
|
148
|
+
try:
|
|
149
|
+
data = json.loads(check_path.read_text(encoding="utf-8"))
|
|
150
|
+
latest = data.get("version", "")
|
|
151
|
+
if latest and _is_newer(latest, __version__):
|
|
152
|
+
con.print(
|
|
153
|
+
f" [dim]Update available:[/dim] [#A78BFA]v{latest}[/#A78BFA] "
|
|
154
|
+
f"[dim](run 'p update')[/dim]"
|
|
155
|
+
)
|
|
156
|
+
except Exception as e:
|
|
157
|
+
_log.warning("print_update_available_if_needed failed: %s", e)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ── Core logic ────────────────────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _fetch_latest(root: Path, silent: bool = False) -> dict | None:
|
|
164
|
+
"""Fetch latest version info from GitHub releases."""
|
|
165
|
+
import httpx
|
|
166
|
+
|
|
167
|
+
owner = UPDATE_SOURCE.get("owner", "")
|
|
168
|
+
repo = UPDATE_SOURCE.get("repo", "patchi")
|
|
169
|
+
api_url = f"https://api.github.com/repos/{owner}/{repo}/releases/latest"
|
|
170
|
+
|
|
171
|
+
if not owner:
|
|
172
|
+
if not silent:
|
|
173
|
+
con.print("[yellow]Update source not configured yet.[/yellow]")
|
|
174
|
+
con.print("[dim]Set the PATCHI_UPDATE_OWNER environment variable.[/dim]")
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
resp = httpx.get(api_url, timeout=10, follow_redirects=True)
|
|
179
|
+
resp.raise_for_status()
|
|
180
|
+
data = resp.json()
|
|
181
|
+
tag = data.get("tag_name", "").lstrip("v")
|
|
182
|
+
return {
|
|
183
|
+
"version": tag,
|
|
184
|
+
"tag_name": data.get("tag_name", ""),
|
|
185
|
+
"release_url": data.get("html_url", ""),
|
|
186
|
+
"body": (data.get("body", "") or "")[:500],
|
|
187
|
+
"assets": data.get("assets", []),
|
|
188
|
+
}
|
|
189
|
+
except httpx.HTTPStatusError as e:
|
|
190
|
+
if e.response.status_code == 403:
|
|
191
|
+
if not silent:
|
|
192
|
+
con.print("[yellow]GitHub API rate limit hit. Try again later.[/yellow]")
|
|
193
|
+
elif e.response.status_code == 404:
|
|
194
|
+
if not silent:
|
|
195
|
+
con.print("[yellow]No releases found yet.[/yellow]")
|
|
196
|
+
else:
|
|
197
|
+
if not silent:
|
|
198
|
+
con.print(f"[red]Failed to check updates: {e}[/red]")
|
|
199
|
+
except httpx.RequestError as e:
|
|
200
|
+
if not silent:
|
|
201
|
+
con.print(f"[yellow]Could not reach GitHub: {e}[/yellow]")
|
|
202
|
+
except Exception as e:
|
|
203
|
+
if not silent:
|
|
204
|
+
con.print(f"[red]Update check failed: {e}[/red]")
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _is_newer(latest: str, current: str) -> bool:
|
|
209
|
+
"""Return True if latest > current (semver comparison)."""
|
|
210
|
+
try:
|
|
211
|
+
l_parts = [int(x) for x in latest.split(".")]
|
|
212
|
+
c_parts = [int(x) for x in current.split(".")]
|
|
213
|
+
# Pad to same length
|
|
214
|
+
while len(l_parts) < 3:
|
|
215
|
+
l_parts.append(0)
|
|
216
|
+
while len(c_parts) < 3:
|
|
217
|
+
c_parts.append(0)
|
|
218
|
+
return l_parts > c_parts
|
|
219
|
+
except (ValueError, AttributeError):
|
|
220
|
+
# Fall back to string comparison
|
|
221
|
+
return latest > current
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# ── UI helpers ────────────────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _print_release_info(info: dict) -> None:
|
|
228
|
+
"""Print release details."""
|
|
229
|
+
version = info.get("version", "?")
|
|
230
|
+
body = (info.get("body") or "")[:300]
|
|
231
|
+
url = info.get("release_url", "")
|
|
232
|
+
|
|
233
|
+
con.print()
|
|
234
|
+
con.print(
|
|
235
|
+
f"[bold #A78BFA]Update available:[/bold #A78BFA] v{__version__} [dim]→[/dim] [bold]v{version}[/bold]"
|
|
236
|
+
)
|
|
237
|
+
if body:
|
|
238
|
+
con.print()
|
|
239
|
+
for line in body.splitlines()[:8]:
|
|
240
|
+
con.print(f" [dim]{line}[/dim]")
|
|
241
|
+
if url:
|
|
242
|
+
con.print()
|
|
243
|
+
con.print(f" [link={url}]{url}[/link]")
|
|
244
|
+
con.print()
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _check_only(root: Path) -> None:
|
|
248
|
+
"""Just check, no install."""
|
|
249
|
+
info = _fetch_latest(root)
|
|
250
|
+
if info is None:
|
|
251
|
+
return
|
|
252
|
+
|
|
253
|
+
latest = info.get("version", "")
|
|
254
|
+
if not latest or _is_newer(latest, __version__):
|
|
255
|
+
con.print(f"[#4ADE80]Already up to date:[/#4ADE80] v{__version__}")
|
|
256
|
+
else:
|
|
257
|
+
_print_release_info(info)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# ── Install logic ─────────────────────────────────────────────────────────────
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _do_install(root: Path, info: dict) -> None:
|
|
264
|
+
"""Download and install the latest version."""
|
|
265
|
+
from patchi.cli.display.live_progress import LiveProgress
|
|
266
|
+
|
|
267
|
+
pip_name = UPDATE_SOURCE.get("pip_name", "patchi")
|
|
268
|
+
version = info.get("version", "")
|
|
269
|
+
|
|
270
|
+
lp = LiveProgress(con, title="Updating")
|
|
271
|
+
lp.start()
|
|
272
|
+
lp.log(f" Updating to v{version} via pip…")
|
|
273
|
+
lp.update()
|
|
274
|
+
|
|
275
|
+
try:
|
|
276
|
+
import subprocess
|
|
277
|
+
|
|
278
|
+
result = subprocess.run(
|
|
279
|
+
[sys.executable, "-m", "pip", "install", "--upgrade", pip_name],
|
|
280
|
+
capture_output=True,
|
|
281
|
+
text=True,
|
|
282
|
+
timeout=120,
|
|
283
|
+
)
|
|
284
|
+
if result.returncode == 0:
|
|
285
|
+
lp.log(" [#4ADE80]Update complete![/#4ADE80]")
|
|
286
|
+
lp.update()
|
|
287
|
+
lp.stop(summary=f"Updated to v{version}")
|
|
288
|
+
|
|
289
|
+
# Clear cached check so next run re-verifies
|
|
290
|
+
check_path = root / CHECK_FILE
|
|
291
|
+
if check_path.exists():
|
|
292
|
+
check_path.unlink()
|
|
293
|
+
|
|
294
|
+
con.print()
|
|
295
|
+
con.print(
|
|
296
|
+
f"[#4ADE80]✓[/#4ADE80] Patchi updated to [bold]v{version}[/bold]. "
|
|
297
|
+
"[dim]Restart your shell to use the new version.[/dim]"
|
|
298
|
+
)
|
|
299
|
+
else:
|
|
300
|
+
lp.log(f" [red]pip install failed: {result.stderr[:200]}[/red]")
|
|
301
|
+
lp.stop(summary="Update failed")
|
|
302
|
+
con.print(f"[red]Update failed:[/red] {result.stderr[:300]}")
|
|
303
|
+
except FileNotFoundError:
|
|
304
|
+
lp.stop(summary="pip not found")
|
|
305
|
+
con.print("[red]pip not found. Install pip first, then run:[/red]")
|
|
306
|
+
con.print(f" [bold]pip install --upgrade {pip_name}[/bold]")
|
|
307
|
+
except subprocess.TimeoutExpired:
|
|
308
|
+
lp.stop(summary="pip timed out")
|
|
309
|
+
con.print("[red]pip install timed out after 120s.[/red]")
|
|
310
|
+
except Exception as e:
|
|
311
|
+
lp.stop(summary=f"Update failed: {e}")
|
|
312
|
+
con.print(f"[red]Update failed: {e}[/red]")
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _force_reinstall(root: Path) -> None:
|
|
316
|
+
"""Force reinstall current version (--force)."""
|
|
317
|
+
pip_name = UPDATE_SOURCE.get("pip_name", "patchi")
|
|
318
|
+
from patchi.cli.display.live_progress import LiveProgress
|
|
319
|
+
|
|
320
|
+
lp = LiveProgress(con, title="Reinstalling")
|
|
321
|
+
lp.start()
|
|
322
|
+
lp.log(f" Reinstalling {pip_name} v{__version__}…")
|
|
323
|
+
lp.update()
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
import subprocess
|
|
327
|
+
|
|
328
|
+
result = subprocess.run(
|
|
329
|
+
[sys.executable, "-m", "pip", "install", "--force-reinstall", pip_name],
|
|
330
|
+
capture_output=True,
|
|
331
|
+
text=True,
|
|
332
|
+
timeout=120,
|
|
333
|
+
)
|
|
334
|
+
if result.returncode == 0:
|
|
335
|
+
lp.stop(summary=f"Reinstalled v{__version__}")
|
|
336
|
+
con.print(f"[#4ADE80]✓[/#4ADE80] Patchi v{__version__} reinstalled.")
|
|
337
|
+
else:
|
|
338
|
+
lp.stop(summary="Reinstall failed")
|
|
339
|
+
con.print(f"[red]Reinstall failed:[/red] {result.stderr[:300]}")
|
|
340
|
+
except FileNotFoundError:
|
|
341
|
+
lp.stop(summary="pip not found")
|
|
342
|
+
con.print("[red]pip not found.[/red]")
|
|
343
|
+
except Exception as e:
|
|
344
|
+
lp.stop(summary=f"Reinstall failed: {e}")
|
|
345
|
+
con.print(f"[red]Reinstall failed: {e}[/red]")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`p verify` — Self-Report Verifier (Dream Assistant spec, priority #1).
|
|
3
|
+
|
|
4
|
+
Independently re-runs the project's real tests (+ scan) and reports the truth
|
|
5
|
+
instead of trusting a "tests pass" claim. Flags regressions vs the last baseline.
|
|
6
|
+
|
|
7
|
+
p verify — re-run tests + scan, diff vs baseline, report
|
|
8
|
+
p verify --no-scan — only re-run tests
|
|
9
|
+
p verify --claim "tests pass" — assert a specific claim against actual truth
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from rich.panel import Panel
|
|
17
|
+
|
|
18
|
+
from patchi.cli.console import con
|
|
19
|
+
from patchi.core.brain.verify import claim_holds, verify_project
|
|
20
|
+
from patchi.core.config import require_project_root
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def run(
|
|
24
|
+
no_scan: bool = False,
|
|
25
|
+
claim: str | None = None,
|
|
26
|
+
root: Path | None = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
try:
|
|
29
|
+
r = root or require_project_root()
|
|
30
|
+
except RuntimeError as e:
|
|
31
|
+
con.print(f"[red]{e}[/red]")
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
con.print()
|
|
35
|
+
con.print("[dim]Independently re-running tests (ignoring any self-report)…[/dim]")
|
|
36
|
+
report = verify_project(r, run_scan=not no_scan)
|
|
37
|
+
|
|
38
|
+
title = "[bold #C8621A]Verification[/bold #C8621A]"
|
|
39
|
+
con.print(Panel(report.summary, title=title, border_style="#2A3D28"))
|
|
40
|
+
|
|
41
|
+
if report.regression and report.regression.get("has_baseline"):
|
|
42
|
+
res = report.regression.get("resolved_failures")
|
|
43
|
+
if res:
|
|
44
|
+
con.print(f"[dim]{len(res)} previously-failing test(s) now pass.[/dim]")
|
|
45
|
+
|
|
46
|
+
if claim is not None:
|
|
47
|
+
ok = claim_holds(claim, report)
|
|
48
|
+
verdict = "[#4ADE80]TRUE[/#4ADE80]" if ok else "[#FACC15]FALSE[/#FACC15]"
|
|
49
|
+
con.print()
|
|
50
|
+
con.print(f'[bold]Claim:[/bold] "{claim}" → holds: {verdict}')
|
|
51
|
+
if not ok:
|
|
52
|
+
con.print(
|
|
53
|
+
"[dim]Do not report this as done. Fix and re-run [bold]p verify[/bold].[/dim]"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
con.print()
|