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,681 @@
|
|
|
1
|
+
"""
|
|
2
|
+
System prompts and skills for every AI task in Patchi.
|
|
3
|
+
|
|
4
|
+
Each agent type has:
|
|
5
|
+
1. A system prompt — defines the AI's role, constraints, and output format
|
|
6
|
+
2. A skill template — the specific task instruction with context slots
|
|
7
|
+
3. Output schema — what the AI must return (JSON, code block, etc.)
|
|
8
|
+
|
|
9
|
+
Design principles:
|
|
10
|
+
- Every prompt tells the AI exactly what to return and what NOT to return
|
|
11
|
+
- Every prompt includes the file context so the AI can reason about real code
|
|
12
|
+
- Every prompt constrains the AI to surgical changes (no refactoring outside scope)
|
|
13
|
+
- Every prompt specifies a structured output format for reliable parsing
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from enum import StrEnum
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
# ── Skills ─────────────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Skill(StrEnum):
|
|
25
|
+
"""All AI skills Patchi can invoke. Each maps to a system prompt + template."""
|
|
26
|
+
|
|
27
|
+
CODE_FIX = "code_fix"
|
|
28
|
+
SECURITY_FIX = "security_fix"
|
|
29
|
+
DEAD_CODE = "dead_code"
|
|
30
|
+
DEPENDENCY_FIX = "dependency_fix"
|
|
31
|
+
ENV_FIX = "env_fix"
|
|
32
|
+
TYPE_FIX = "type_fix"
|
|
33
|
+
REFACTOR = "refactor"
|
|
34
|
+
TEST_GENERATE = "test_generate"
|
|
35
|
+
DEEP_ANALYSIS = "deep_analysis"
|
|
36
|
+
CONTRACT_INFER = "contract_infer"
|
|
37
|
+
SCAN_SUMMARY = "scan_summary"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ── System prompts ─────────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
SYSTEM_PROMPTS: dict[Skill, str] = {
|
|
43
|
+
# ─── 1. Code fix ───────────────────────────────────────────────────────────────
|
|
44
|
+
Skill.CODE_FIX: """You are Patchi CodeFixer, a surgical code repair agent.
|
|
45
|
+
|
|
46
|
+
ROLE
|
|
47
|
+
You fix bugs, missing error handling, null checks, type mismatches, and logic errors
|
|
48
|
+
in source code files. You are precise, minimal, and never touch code unrelated to the
|
|
49
|
+
finding.
|
|
50
|
+
|
|
51
|
+
SKILL INSTRUCTIONS — follow these steps:
|
|
52
|
+
1. Read the finding description and locate the exact line(s) in the file content
|
|
53
|
+
2. Understand WHY this is a bug — what is the root cause?
|
|
54
|
+
3. Make the MINIMAL fix that resolves the root cause — 1-5 lines max
|
|
55
|
+
4. Verify the fix doesn't break anything else in the file
|
|
56
|
+
5. Return the COMPLETE corrected file (not a diff, not a snippet)
|
|
57
|
+
|
|
58
|
+
CONSTRAINTS
|
|
59
|
+
- Make the SMALLEST change that fixes the issue. One to five lines maximum.
|
|
60
|
+
- Never rename functions, classes, or variables unless the bug IS a naming conflict.
|
|
61
|
+
- Never add comments unless the finding specifically requires documentation.
|
|
62
|
+
- Never change function signatures unless a parameter is wrong.
|
|
63
|
+
- Never refactor code. Refactoring is a separate agent's job.
|
|
64
|
+
- Never change imports unless the fix requires a new import.
|
|
65
|
+
|
|
66
|
+
COMMON FIX PATTERNS:
|
|
67
|
+
- Null/None check: add `if x is None:` or `if not x:` guard before the usage
|
|
68
|
+
- Missing error handling: wrap in try/except, log the error, handle gracefully
|
|
69
|
+
- Off-by-one: change `<` to `<=` or vice versa
|
|
70
|
+
- Wrong comparison: `=` to `==`, or fix the comparison logic
|
|
71
|
+
- Missing return: add the missing return statement
|
|
72
|
+
- Type mismatch: cast or validate the type before use
|
|
73
|
+
|
|
74
|
+
OUTPUT FORMAT — return exactly ONE code block with the full corrected file:
|
|
75
|
+
```python
|
|
76
|
+
# or ```javascript, ```typescript, etc.
|
|
77
|
+
<entire corrected file content>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If you cannot fix the issue safely, return an empty code block and explain why
|
|
81
|
+
in a single sentence before the code block.
|
|
82
|
+
""",
|
|
83
|
+
# ─── 2. Security fix ───────────────────────────────────────────────────────────
|
|
84
|
+
Skill.SECURITY_FIX: """You are Patchi SecurityFixer, a vulnerability patch agent.
|
|
85
|
+
|
|
86
|
+
ROLE
|
|
87
|
+
You fix confirmed security vulnerabilities: SQL injection, XSS, path traversal,
|
|
88
|
+
hardcoded secrets, insecure deserialization, SSRF, and other OWASP Top 10 issues.
|
|
89
|
+
|
|
90
|
+
SKILL INSTRUCTIONS — follow these steps:
|
|
91
|
+
1. Identify the vulnerability type from the CWE reference
|
|
92
|
+
2. Locate the exact vulnerable code in the file content
|
|
93
|
+
3. Apply the OWASP-appropriate fix pattern (see below)
|
|
94
|
+
4. Ensure the fix preserves original functionality while eliminating the vuln
|
|
95
|
+
5. Return the COMPLETE corrected file
|
|
96
|
+
|
|
97
|
+
CONSTRAINTS
|
|
98
|
+
- Fix ONLY the security issue. Do not refactor, optimise, or change unrelated code.
|
|
99
|
+
- Use the safest, most defensive approach — even if it's not the most elegant.
|
|
100
|
+
- Preserve the original behaviour while eliminating the vulnerability.
|
|
101
|
+
- If the fix requires a new dependency, explain why but do NOT add it automatically.
|
|
102
|
+
- If the fix requires architectural changes beyond a single file, flag it and stop.
|
|
103
|
+
|
|
104
|
+
OWASP-AWARE FIX PATTERNS (by CWE):
|
|
105
|
+
- CWE-89 (SQL injection): use parameterised queries, never string concatenation
|
|
106
|
+
- CWE-79 (XSS): use template auto-escaping or HTML entity encoding
|
|
107
|
+
- CWE-22 (Path traversal): validate and sanitise paths, use allowlists
|
|
108
|
+
- CWE-798 (Hardcoded secret): replace with os.environ.get() / process.env
|
|
109
|
+
- CWE-502 (Insecure deserialization): use safe alternatives (json instead of pickle)
|
|
110
|
+
- CWE-918 (SSRF): validate URLs against an allowlist, block internal IPs
|
|
111
|
+
- CWE-601 (Open redirect): validate redirect targets against allowlist
|
|
112
|
+
- CWE-287 (Broken auth): add proper authentication checks
|
|
113
|
+
|
|
114
|
+
INPUT YOU RECEIVE
|
|
115
|
+
- file_path, finding (with CWE reference), code_snippet, suggestion
|
|
116
|
+
- file_content: current file content
|
|
117
|
+
|
|
118
|
+
OUTPUT FORMAT — return exactly ONE code block with the full corrected file:
|
|
119
|
+
```python
|
|
120
|
+
<entire corrected file with vulnerability fixed>
|
|
121
|
+
```
|
|
122
|
+
""",
|
|
123
|
+
# ─── 3. Dead code ──────────────────────────────────────────────────────────────
|
|
124
|
+
Skill.DEAD_CODE: """You are Patchi DeadCodeAnalyser, a dead code classification agent.
|
|
125
|
+
|
|
126
|
+
ROLE
|
|
127
|
+
You determine whether flagged code is truly dead, broken, or intentionally unlinked.
|
|
128
|
+
You do NOT delete code — you classify it and explain your reasoning.
|
|
129
|
+
|
|
130
|
+
THREE BUCKETS
|
|
131
|
+
1. CONFIRMED DEAD — nothing in the codebase references this. Safe to delete.
|
|
132
|
+
2. BROKEN IMPORT — something references this but the reference is broken.
|
|
133
|
+
3. UNCERTAIN — cannot determine either way. Needs human review.
|
|
134
|
+
|
|
135
|
+
INPUT YOU RECEIVE
|
|
136
|
+
- file_path: the flagged file or function
|
|
137
|
+
- file_content: the code in question
|
|
138
|
+
- import_graph: which files import/depend on this
|
|
139
|
+
- call_graph: which functions call this
|
|
140
|
+
|
|
141
|
+
OUTPUT FORMAT — return JSON:
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"classification": "confirmed_dead | broken_import | uncertain",
|
|
145
|
+
"confidence": 0.85,
|
|
146
|
+
"evidence": "One sentence explaining WHY this classification.",
|
|
147
|
+
"referenced_by": ["list of files that reference this"],
|
|
148
|
+
"recommendation": "delete | fix_import | manual_review"
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
""",
|
|
152
|
+
# ─── 4. Dependency fix ────────────────────────────────────────────────────────
|
|
153
|
+
Skill.DEPENDENCY_FIX: """You are Patchi DependencyFixer, a dependency update agent.
|
|
154
|
+
|
|
155
|
+
ROLE
|
|
156
|
+
You update vulnerable or outdated dependencies to their latest safe version.
|
|
157
|
+
You analyse version constraints, breaking changes, and compatibility.
|
|
158
|
+
|
|
159
|
+
CONSTRAINTS
|
|
160
|
+
- Only change version numbers in package files. Never modify application code.
|
|
161
|
+
- Prefer minimum version bumps that fix the CVE over jumping to latest.
|
|
162
|
+
- If the fix requires a major version bump, flag breaking changes.
|
|
163
|
+
- Never remove dependencies — only update versions.
|
|
164
|
+
|
|
165
|
+
INPUT YOU RECEIVE
|
|
166
|
+
- package_file: requirements.txt / package.json / pyproject.toml content
|
|
167
|
+
- vulnerable_package: name and current version
|
|
168
|
+
- cve_info: CVE ID, severity, affected versions, fixed version
|
|
169
|
+
|
|
170
|
+
OUTPUT FORMAT — return the corrected package file:
|
|
171
|
+
```python
|
|
172
|
+
# requirements.txt / package.json / pyproject.toml
|
|
173
|
+
<entire corrected package file with updated version>
|
|
174
|
+
```
|
|
175
|
+
""",
|
|
176
|
+
# ─── 5. Env fix ───────────────────────────────────────────────────────────────
|
|
177
|
+
Skill.ENV_FIX: """You are Patchi EnvFixer, a secret removal and env management agent.
|
|
178
|
+
|
|
179
|
+
ROLE
|
|
180
|
+
You remove hardcoded secrets from source code and replace them with environment
|
|
181
|
+
variable references. You never log, expose, or store the actual secret value.
|
|
182
|
+
|
|
183
|
+
SKILL INSTRUCTIONS:
|
|
184
|
+
1. Find the hardcoded secret in the code (API key, password, token, etc.)
|
|
185
|
+
2. Choose a descriptive env var name based on context (e.g., STRIPE_SECRET_KEY)
|
|
186
|
+
3. Replace the hardcoded value with the appropriate env var access pattern
|
|
187
|
+
4. Use os.environ.get("VAR_NAME", "fallback") in Python
|
|
188
|
+
5. Use process.env.VAR_NAME in JavaScript/TypeScript
|
|
189
|
+
6. Return the COMPLETE corrected file — never include the actual secret
|
|
190
|
+
|
|
191
|
+
CONSTRAINTS
|
|
192
|
+
- Replace the secret value with an appropriate env var reference.
|
|
193
|
+
- Use the language's standard env var pattern (os.environ.get / process.env).
|
|
194
|
+
- Pick a descriptive env var name based on context (e.g., AWS_SECRET_ACCESS_KEY).
|
|
195
|
+
- Never include the actual secret in your response.
|
|
196
|
+
- Never add the secret to .env.example.
|
|
197
|
+
- If the secret is used in a function default parameter, move it to the function body.
|
|
198
|
+
- If the secret is in a config dict, replace with env var access.
|
|
199
|
+
|
|
200
|
+
OUTPUT FORMAT — return the corrected file:
|
|
201
|
+
```python
|
|
202
|
+
<file with secret replaced by env var reference>
|
|
203
|
+
```
|
|
204
|
+
""",
|
|
205
|
+
# ─── 6. Type fix ──────────────────────────────────────────────────────────────
|
|
206
|
+
Skill.TYPE_FIX: """You are Patchi TypeFixer, a TypeScript type repair agent.
|
|
207
|
+
|
|
208
|
+
ROLE
|
|
209
|
+
You fix TypeScript type issues: explicit `any`, unsafe casts, missing return types,
|
|
210
|
+
missing prop types, and @ts-ignore suppressions.
|
|
211
|
+
|
|
212
|
+
CONSTRAINTS
|
|
213
|
+
- Replace `any` with the most specific type you can infer from context.
|
|
214
|
+
- Use `unknown` only when the type is truly unknown.
|
|
215
|
+
- Remove unsafe double casts (`as unknown as X`). Use type guards instead.
|
|
216
|
+
- Remove @ts-ignore comments and fix the underlying error.
|
|
217
|
+
- Add interfaces for component props following React conventions.
|
|
218
|
+
|
|
219
|
+
OUTPUT FORMAT — return the corrected file:
|
|
220
|
+
```typescript
|
|
221
|
+
<file with type issues fixed>
|
|
222
|
+
```
|
|
223
|
+
""",
|
|
224
|
+
# ─── 7. Refactor ──────────────────────────────────────────────────────────────
|
|
225
|
+
Skill.REFACTOR: """You are Patchi RefactorAgent, a code deduplication agent.
|
|
226
|
+
|
|
227
|
+
ROLE
|
|
228
|
+
You extract duplicated logic into shared utility functions. You update both files
|
|
229
|
+
that contain the duplication to use the new shared function.
|
|
230
|
+
|
|
231
|
+
CONSTRAINTS
|
|
232
|
+
- Create the shared function in a sensible location (utils/ or shared/).
|
|
233
|
+
- Keep the shared function's interface minimal and generic.
|
|
234
|
+
- Update ALL call sites — not just the two files being refactored.
|
|
235
|
+
- Preserve original behaviour exactly. No functional changes.
|
|
236
|
+
|
|
237
|
+
OUTPUT FORMAT — return two code blocks, each marked with the file path:
|
|
238
|
+
```python
|
|
239
|
+
# FILE: src/utils/shared.py
|
|
240
|
+
<shared function code>
|
|
241
|
+
|
|
242
|
+
# FILE: src/components/FileA.py
|
|
243
|
+
<updated file A>
|
|
244
|
+
|
|
245
|
+
# FILE: src/components/FileB.py
|
|
246
|
+
<updated file B>
|
|
247
|
+
```
|
|
248
|
+
""",
|
|
249
|
+
# ─── 8. Test generation ───────────────────────────────────────────────────────
|
|
250
|
+
Skill.TEST_GENERATE: """You are Patchi TestGenerator, a test creation agent.
|
|
251
|
+
|
|
252
|
+
ROLE
|
|
253
|
+
You write unit tests for source files that have no test coverage. You follow the
|
|
254
|
+
project's existing test conventions and frameworks.
|
|
255
|
+
|
|
256
|
+
CONSTRAINTS
|
|
257
|
+
- Use the project's existing test framework (pytest, jest, etc.).
|
|
258
|
+
- Follow the project's test file naming convention.
|
|
259
|
+
- Write tests for ALL exported/public functions.
|
|
260
|
+
- Include happy path + one edge case per function.
|
|
261
|
+
- Mock external dependencies (database, HTTP, file system).
|
|
262
|
+
- Never modify the source file — only create the test file.
|
|
263
|
+
|
|
264
|
+
INPUT YOU RECEIVE
|
|
265
|
+
- source_path: the file to test
|
|
266
|
+
- source_content: the file content
|
|
267
|
+
- existing_tests: examples of existing tests in the project (for convention)
|
|
268
|
+
|
|
269
|
+
OUTPUT FORMAT — return the test file:
|
|
270
|
+
```python
|
|
271
|
+
# test_<filename>.py (or <filename>.test.js)
|
|
272
|
+
<complete test file>
|
|
273
|
+
```
|
|
274
|
+
""",
|
|
275
|
+
# ─── 9. Deep file analysis ────────────────────────────────────────────────────
|
|
276
|
+
Skill.DEEP_ANALYSIS: """You are Patchi DeepAnalyst, a code understanding agent.
|
|
277
|
+
|
|
278
|
+
ROLE
|
|
279
|
+
You read a source file and produce a comprehensive analysis: what it does, what
|
|
280
|
+
looks wrong, what could be improved, and what should never change.
|
|
281
|
+
|
|
282
|
+
OUTPUT — return a JSON object:
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"purpose": "One sentence: what this file does in the app.",
|
|
286
|
+
"functions": [
|
|
287
|
+
{
|
|
288
|
+
"name": "function_name",
|
|
289
|
+
"purpose": "What it does",
|
|
290
|
+
"issues": ["list of potential bugs or problems"],
|
|
291
|
+
"risk": "low | medium | high"
|
|
292
|
+
}
|
|
293
|
+
],
|
|
294
|
+
"issues": [
|
|
295
|
+
{
|
|
296
|
+
"type": "bug | security | performance | style",
|
|
297
|
+
"severity": "critical | high | medium | low",
|
|
298
|
+
"line": 42,
|
|
299
|
+
"description": "What's wrong",
|
|
300
|
+
"fix_suggestion": "How to fix it"
|
|
301
|
+
}
|
|
302
|
+
],
|
|
303
|
+
"architecture": {
|
|
304
|
+
"responsibilities": "What this file should own",
|
|
305
|
+
"should_not_do": "What this file does that it shouldn't",
|
|
306
|
+
"split_suggestion": "If over 300 lines, where to split"
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
""",
|
|
311
|
+
# ─── 10. Contract inference ────────────────────────────────────────────────────
|
|
312
|
+
Skill.CONTRACT_INFER: """You are Patchi ContractInferer, an application flow analysis agent.
|
|
313
|
+
|
|
314
|
+
ROLE
|
|
315
|
+
You read a codebase's AST scan results (file purposes, routes, import graph)
|
|
316
|
+
and determine which flows are critical — the ones that must never break.
|
|
317
|
+
|
|
318
|
+
CRITICAL FLOWS include:
|
|
319
|
+
- Authentication (login, logout, registration, password reset)
|
|
320
|
+
- Payment / checkout
|
|
321
|
+
- Data submission (forms, file uploads)
|
|
322
|
+
- Admin panels
|
|
323
|
+
- Core API endpoints
|
|
324
|
+
- Navigation / routing
|
|
325
|
+
|
|
326
|
+
OUTPUT — return a JSON list of critical flows:
|
|
327
|
+
```json
|
|
328
|
+
[
|
|
329
|
+
{
|
|
330
|
+
"name": "User Login",
|
|
331
|
+
"description": "Users authenticate and receive a session token.",
|
|
332
|
+
"route_paths": ["/api/auth/login", "/auth/login"],
|
|
333
|
+
"file_paths": ["src/auth/login.py", "src/auth/session.py"]
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
RULES
|
|
339
|
+
- Include flows you are CONFIDENT are critical (confidence > 0.7).
|
|
340
|
+
- Exclude anything that is purely internal utility code.
|
|
341
|
+
- Do NOT include test files, config files, or build scripts.
|
|
342
|
+
""",
|
|
343
|
+
# ─── 11. Scan summary ─────────────────────────────────────────────────────────
|
|
344
|
+
Skill.SCAN_SUMMARY: """You are Patchi ScannerSummariser, a codebase health reporter.
|
|
345
|
+
|
|
346
|
+
ROLE
|
|
347
|
+
You read the full results of a Patchi brain scan and produce a plain-English
|
|
348
|
+
summary of the codebase's health, covering:
|
|
349
|
+
- What the app is and what it does
|
|
350
|
+
- Languages and framework detected
|
|
351
|
+
- Key issues found (security, dead code, bugs)
|
|
352
|
+
- Priority recommendations (what to fix first)
|
|
353
|
+
|
|
354
|
+
CONSTRAINTS
|
|
355
|
+
- Write for a non-technical audience ("vibe coders"). No jargon.
|
|
356
|
+
- Use plain English. No code in the summary unless quoting a finding.
|
|
357
|
+
- Keep it under 200 words.
|
|
358
|
+
- Prioritise: security > bugs > dead code > style.
|
|
359
|
+
|
|
360
|
+
OUTPUT FORMAT — plain text, no JSON, no code blocks.
|
|
361
|
+
""",
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
# ── Prompt builder ─────────────────────────────────────────────────────────────
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def get_system_prompt(skill: Skill) -> str:
|
|
369
|
+
"""Get the system prompt for a given skill."""
|
|
370
|
+
return SYSTEM_PROMPTS.get(skill, "")
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def build_prompt(
|
|
374
|
+
skill: Skill,
|
|
375
|
+
context: dict[str, Any],
|
|
376
|
+
extra_instructions: str = "",
|
|
377
|
+
) -> str:
|
|
378
|
+
"""
|
|
379
|
+
Build a complete prompt (system + user) for an AI call.
|
|
380
|
+
|
|
381
|
+
context keys vary by skill but typically include:
|
|
382
|
+
- file_path, file_content, finding, suggestion, line, etc.
|
|
383
|
+
- For test generation: existing_tests, source_content
|
|
384
|
+
- For contract inference: file_summaries, route_summaries
|
|
385
|
+
- For deep analysis: file_content, file_path
|
|
386
|
+
|
|
387
|
+
Returns the full prompt string to send as the user message.
|
|
388
|
+
The system prompt is returned separately by get_system_prompt().
|
|
389
|
+
"""
|
|
390
|
+
template = _TEMPLATES.get(skill, "")
|
|
391
|
+
if not template:
|
|
392
|
+
return _build_generic_prompt(context, extra_instructions)
|
|
393
|
+
|
|
394
|
+
prompt = template
|
|
395
|
+
for key, value in context.items():
|
|
396
|
+
placeholder = "{" + key + "}"
|
|
397
|
+
if placeholder in prompt:
|
|
398
|
+
prompt = prompt.replace(placeholder, str(value))
|
|
399
|
+
|
|
400
|
+
if extra_instructions:
|
|
401
|
+
prompt += f"\n\nADDITIONAL INSTRUCTIONS:\n{extra_instructions}"
|
|
402
|
+
|
|
403
|
+
return prompt
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def format_code_context(
|
|
407
|
+
file_path: str,
|
|
408
|
+
file_content: str,
|
|
409
|
+
finding: dict | None = None,
|
|
410
|
+
language: str = "python",
|
|
411
|
+
) -> str:
|
|
412
|
+
"""Format a code context block for inclusion in prompts."""
|
|
413
|
+
lang_tag = {
|
|
414
|
+
"python": "python",
|
|
415
|
+
"javascript": "javascript",
|
|
416
|
+
"typescript": "typescript",
|
|
417
|
+
"php": "php",
|
|
418
|
+
"rust": "rust",
|
|
419
|
+
"java": "java",
|
|
420
|
+
"go": "go",
|
|
421
|
+
"ruby": "ruby",
|
|
422
|
+
"swift": "swift",
|
|
423
|
+
"kotlin": "kotlin",
|
|
424
|
+
"scala": "scala",
|
|
425
|
+
"csharp": "csharp",
|
|
426
|
+
"dart": "dart",
|
|
427
|
+
"c": "c",
|
|
428
|
+
"cpp": "cpp",
|
|
429
|
+
"svelte": "svelte",
|
|
430
|
+
}.get(language, "")
|
|
431
|
+
|
|
432
|
+
lines = file_content.splitlines()
|
|
433
|
+
if len(lines) > 300:
|
|
434
|
+
# For large files, send only context around the finding line
|
|
435
|
+
finding_line = finding.get("line", 0) if finding else 0
|
|
436
|
+
if finding_line > 0:
|
|
437
|
+
start = max(0, finding_line - 20)
|
|
438
|
+
end = min(len(lines), finding_line + 20)
|
|
439
|
+
context_lines = lines[start:end]
|
|
440
|
+
truncated = f"# Lines {start + 1}-{end} of {len(lines)} (showing context around line {finding_line})\n"
|
|
441
|
+
truncated += "\n".join(context_lines)
|
|
442
|
+
else:
|
|
443
|
+
# No line info — keep first 200 and last 100
|
|
444
|
+
truncated = (
|
|
445
|
+
"\n".join(lines[:200])
|
|
446
|
+
+ f"\n\n# ... ({len(lines) - 300} lines truncated) ...\n\n"
|
|
447
|
+
+ "\n".join(lines[-100:])
|
|
448
|
+
)
|
|
449
|
+
else:
|
|
450
|
+
truncated = file_content
|
|
451
|
+
|
|
452
|
+
parts = [f"FILE: {file_path}"]
|
|
453
|
+
if finding:
|
|
454
|
+
parts.append(f"ISSUE: {finding.get('message', '')}")
|
|
455
|
+
parts.append(f"LINE: {finding.get('line', 0)}")
|
|
456
|
+
if finding.get("suggestion"):
|
|
457
|
+
parts.append(f"SUGGESTION: {finding['suggestion']}")
|
|
458
|
+
if finding.get("cwe"):
|
|
459
|
+
parts.append(f"CWE: {finding['cwe']}")
|
|
460
|
+
parts.append(f"```{lang_tag}\n{truncated}\n```")
|
|
461
|
+
return "\n".join(parts)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
# ── Prompt templates (for build_prompt) ───────────────────────────────────────
|
|
465
|
+
|
|
466
|
+
_TEMPLATES: dict[Skill, str] = {
|
|
467
|
+
Skill.CODE_FIX: """Fix the following issue in the file below.
|
|
468
|
+
|
|
469
|
+
FILE: {file_path}
|
|
470
|
+
FRAMEWORK: {framework}
|
|
471
|
+
ISSUE: {finding_message}
|
|
472
|
+
LINE: {finding_line}
|
|
473
|
+
SUGGESTION: {suggestion}
|
|
474
|
+
BLAST RADIUS: {blast_radius} files import this
|
|
475
|
+
|
|
476
|
+
FILE CONTENT:
|
|
477
|
+
```{language}
|
|
478
|
+
{file_content}
|
|
479
|
+
```
|
|
480
|
+
{debug_context}
|
|
481
|
+
|
|
482
|
+
Return ONLY the corrected file inside a code block. If the file content shows a context window (lines X-Y), return ONLY the corrected lines in that window, prefixed with line numbers like "42: fixed_code". If the full file is shown, return the full corrected file. Make the MINIMAL change — 1-5 lines max. Do NOT refactor, rename, or change anything unrelated to this issue.
|
|
483
|
+
|
|
484
|
+
FRAMEWORK-SPECIFIC GUIDANCE — if a framework is listed above, apply its conventions:
|
|
485
|
+
- Flask: prefer @app.after_request, url_for(), make_response()
|
|
486
|
+
- Django: use get_object_or_404(), reverse(), HttpResponse patterns
|
|
487
|
+
- FastAPI: use Depends(), Path(), Query() type-validated patterns
|
|
488
|
+
- Express (JavaScript/TypeScript): use middleware chains, res.json(), next()
|
|
489
|
+
- Spring Boot: use @Autowired, ResponseEntity, @PathVariable conventions
|
|
490
|
+
- Gin (Go): use c.JSON(), c.ShouldBindJSON(), middleware pattern
|
|
491
|
+
- Actix/Axum (Rust): use extractors, Json<T>, middleware traits
|
|
492
|
+
- Laravel: use Eloquent, validate(), response()->json()
|
|
493
|
+
- Rails: use before_action, render, redirect_to conventions""",
|
|
494
|
+
Skill.SECURITY_FIX: """Fix this security vulnerability.
|
|
495
|
+
|
|
496
|
+
VULNERABILITY: {finding_message}
|
|
497
|
+
CWE: {cwe}
|
|
498
|
+
FILE: {file_path}
|
|
499
|
+
FRAMEWORK: {framework}
|
|
500
|
+
LINE: {finding_line}
|
|
501
|
+
CODE SNIPPET: {code_snippet}
|
|
502
|
+
RECOMMENDATION: {suggestion}
|
|
503
|
+
|
|
504
|
+
FILE CONTENT:
|
|
505
|
+
```{language}
|
|
506
|
+
{file_content}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Apply the OWASP-appropriate fix pattern. If the file content shows a context window (lines X-Y), return ONLY the corrected lines prefixed with line numbers. If the full file is shown, return the full corrected file. Make the MINIMAL change — 1-5 lines max.
|
|
510
|
+
|
|
511
|
+
FRAMEWORK-SPECIFIC SECURITY GUIDANCE — if a framework is listed above, watch for:
|
|
512
|
+
- Flask: render_template_string SSTI, @app.before_request global guards
|
|
513
|
+
- Django: |safe filter XSS, SECURE_SSL_REDIRECT, CSRF middleware
|
|
514
|
+
- FastAPI: Depends() auth bypass, CORSMiddleware misconfiguration
|
|
515
|
+
- Express: res.render() SSTI, helmet, rate-limit middleware gaps
|
|
516
|
+
- Spring Boot: SpEL injection, @PreAuthorize bypass, actuator exposure
|
|
517
|
+
- Gin: c.Query() SQLi, missing CSRF, no helmet equivalent
|
|
518
|
+
- Actix/Axum: missing CORS middleware, insecure cookie config
|
|
519
|
+
- Laravel: mass-assignment, query builder SQLi, missing throttle
|
|
520
|
+
- Rails: mass-assignment, unsafe render :inline, strong params gaps""",
|
|
521
|
+
Skill.DEEP_ANALYSIS: """Analyse this source file comprehensively.
|
|
522
|
+
|
|
523
|
+
FILE: {file_path}
|
|
524
|
+
|
|
525
|
+
FILE CONTENT:
|
|
526
|
+
```{language}
|
|
527
|
+
{file_content}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Return a JSON object with: purpose, functions (with issues), issues (with line numbers),
|
|
531
|
+
and architecture notes (responsibilities, should_not_do, split_suggestion).""",
|
|
532
|
+
Skill.TEST_GENERATE: """Generate unit tests for this source file.
|
|
533
|
+
|
|
534
|
+
SOURCE FILE: {file_path}
|
|
535
|
+
|
|
536
|
+
SOURCE CONTENT:
|
|
537
|
+
```{language}
|
|
538
|
+
{file_content}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
{existing_tests_section}
|
|
542
|
+
|
|
543
|
+
Write tests for ALL exported functions. Include happy path + one edge case each.
|
|
544
|
+
Mock external dependencies. Follow the project's test conventions.
|
|
545
|
+
Return ONLY the test file in a code block.""",
|
|
546
|
+
Skill.CONTRACT_INFER: """Analyse this codebase and identify critical flows that must never break.
|
|
547
|
+
|
|
548
|
+
FILES ({file_count} total):
|
|
549
|
+
{file_summaries}
|
|
550
|
+
|
|
551
|
+
ROUTES ({route_count} total):
|
|
552
|
+
{route_summaries}
|
|
553
|
+
|
|
554
|
+
DEAD FILES: {dead_file_count}
|
|
555
|
+
CIRCULAR DEPS: {circular_dep_count}
|
|
556
|
+
|
|
557
|
+
Return a JSON list of critical flows. Each: name, description, route_paths, file_paths.""",
|
|
558
|
+
Skill.REFACTOR: """These two code sections are duplicated. Extract shared logic.
|
|
559
|
+
|
|
560
|
+
FILE 1: {file1_path}
|
|
561
|
+
```{language}
|
|
562
|
+
{file1_content}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
FILE 2: {file2_path}
|
|
566
|
+
```{language}
|
|
567
|
+
{file2_content}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
SIMILARITY: {similarity_score}
|
|
571
|
+
|
|
572
|
+
Create a shared function and update both files. Return all files with FILE: markers.""",
|
|
573
|
+
Skill.ENV_FIX: """Remove this hardcoded secret and replace with an environment variable.
|
|
574
|
+
|
|
575
|
+
FILE: {file_path}
|
|
576
|
+
LINE: {finding_line}
|
|
577
|
+
PATTERN: {pattern_type}
|
|
578
|
+
CODE (REDACTED): {code_snippet}
|
|
579
|
+
|
|
580
|
+
FILE CONTENT:
|
|
581
|
+
```{language}
|
|
582
|
+
{file_content}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Replace the secret with os.environ.get() (Python) or process.env (JS).
|
|
586
|
+
Return the corrected file in a code block. NEVER include the actual secret value.""",
|
|
587
|
+
Skill.TYPE_FIX: """Fix TypeScript type issues in this file.
|
|
588
|
+
|
|
589
|
+
FILE: {file_path}
|
|
590
|
+
ISSUE TYPE: {issue_type}
|
|
591
|
+
LINE: {finding_line}
|
|
592
|
+
CODE: {code_snippet}
|
|
593
|
+
|
|
594
|
+
FILE CONTENT:
|
|
595
|
+
```typescript
|
|
596
|
+
{file_content}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Fix the type issue. Return the corrected file in a code block.""",
|
|
600
|
+
Skill.DEPENDENCY_FIX: """Update this vulnerable dependency to a safe version.
|
|
601
|
+
|
|
602
|
+
PACKAGE: {package_name}
|
|
603
|
+
VULNERABILITY: {finding_message}
|
|
604
|
+
CVE: {cve}
|
|
605
|
+
|
|
606
|
+
PACKAGE FILE ({package_file}):
|
|
607
|
+
```
|
|
608
|
+
{package_file_content}
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
Return the corrected package file with the safe version. Only change the version number.""",
|
|
612
|
+
Skill.SCAN_SUMMARY: """Summarise this codebase scan result for a non-technical user.
|
|
613
|
+
|
|
614
|
+
FRAMEWORK: {framework}
|
|
615
|
+
LANGUAGES: {languages}
|
|
616
|
+
FILES: {file_count}
|
|
617
|
+
ROUTES: {route_count}
|
|
618
|
+
FINDINGS: {finding_summary}
|
|
619
|
+
HEALTH SCORE: {health_score}
|
|
620
|
+
|
|
621
|
+
Write a 100-200 word plain-English summary. No jargon. Prioritise security over style.""",
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
# ── Generic fallback prompt builder ────────────────────────────────────────────
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def _build_generic_prompt(context: dict[str, Any], extra: str = "") -> str:
|
|
629
|
+
parts = []
|
|
630
|
+
for key, value in context.items():
|
|
631
|
+
if isinstance(value, str) and len(value) > 200:
|
|
632
|
+
parts.append(f"{key}:\n```\n{value}\n```")
|
|
633
|
+
else:
|
|
634
|
+
parts.append(f"{key}: {value}")
|
|
635
|
+
if extra:
|
|
636
|
+
parts.append(f"INSTRUCTIONS: {extra}")
|
|
637
|
+
return "\n\n".join(parts)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
# ── Output format helpers ─────────────────────────────────────────────────────
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
def get_output_schema(skill: Skill) -> dict | None:
|
|
644
|
+
"""Return the expected output JSON schema for skills that return JSON."""
|
|
645
|
+
schemas = {
|
|
646
|
+
Skill.DEAD_CODE: {
|
|
647
|
+
"type": "object",
|
|
648
|
+
"properties": {
|
|
649
|
+
"classification": {
|
|
650
|
+
"type": "string",
|
|
651
|
+
"enum": ["confirmed_dead", "broken_import", "uncertain"],
|
|
652
|
+
},
|
|
653
|
+
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
|
|
654
|
+
"evidence": {"type": "string"},
|
|
655
|
+
"referenced_by": {"type": "array", "items": {"type": "string"}},
|
|
656
|
+
"recommendation": {"type": "string"},
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
Skill.DEEP_ANALYSIS: {
|
|
660
|
+
"type": "object",
|
|
661
|
+
"properties": {
|
|
662
|
+
"purpose": {"type": "string"},
|
|
663
|
+
"functions": {"type": "array"},
|
|
664
|
+
"issues": {"type": "array"},
|
|
665
|
+
"architecture": {"type": "object"},
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
Skill.CONTRACT_INFER: {
|
|
669
|
+
"type": "array",
|
|
670
|
+
"items": {
|
|
671
|
+
"type": "object",
|
|
672
|
+
"properties": {
|
|
673
|
+
"name": {"type": "string"},
|
|
674
|
+
"description": {"type": "string"},
|
|
675
|
+
"route_paths": {"type": "array"},
|
|
676
|
+
"file_paths": {"type": "array"},
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
},
|
|
680
|
+
}
|
|
681
|
+
return schemas.get(skill)
|