empathy-framework 4.6.6__py3-none-any.whl → 4.7.1__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.
- empathy_framework-4.7.1.dist-info/METADATA +690 -0
- empathy_framework-4.7.1.dist-info/RECORD +379 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/top_level.txt +1 -2
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
- empathy_llm_toolkit/agent_factory/__init__.py +6 -6
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
- empathy_llm_toolkit/agents_md/__init__.py +22 -0
- empathy_llm_toolkit/agents_md/loader.py +218 -0
- empathy_llm_toolkit/agents_md/parser.py +271 -0
- empathy_llm_toolkit/agents_md/registry.py +307 -0
- empathy_llm_toolkit/commands/__init__.py +51 -0
- empathy_llm_toolkit/commands/context.py +375 -0
- empathy_llm_toolkit/commands/loader.py +301 -0
- empathy_llm_toolkit/commands/models.py +231 -0
- empathy_llm_toolkit/commands/parser.py +371 -0
- empathy_llm_toolkit/commands/registry.py +429 -0
- empathy_llm_toolkit/config/__init__.py +8 -8
- empathy_llm_toolkit/config/unified.py +3 -7
- empathy_llm_toolkit/context/__init__.py +22 -0
- empathy_llm_toolkit/context/compaction.py +455 -0
- empathy_llm_toolkit/context/manager.py +434 -0
- empathy_llm_toolkit/hooks/__init__.py +24 -0
- empathy_llm_toolkit/hooks/config.py +306 -0
- empathy_llm_toolkit/hooks/executor.py +289 -0
- empathy_llm_toolkit/hooks/registry.py +302 -0
- empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
- empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
- empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
- empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
- empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
- empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
- empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
- empathy_llm_toolkit/learning/__init__.py +30 -0
- empathy_llm_toolkit/learning/evaluator.py +438 -0
- empathy_llm_toolkit/learning/extractor.py +514 -0
- empathy_llm_toolkit/learning/storage.py +560 -0
- empathy_llm_toolkit/providers.py +4 -11
- empathy_llm_toolkit/security/__init__.py +17 -17
- empathy_llm_toolkit/utils/tokens.py +2 -5
- empathy_os/__init__.py +202 -70
- empathy_os/cache_monitor.py +5 -3
- empathy_os/cli/__init__.py +11 -55
- empathy_os/cli/__main__.py +29 -15
- empathy_os/cli/commands/inspection.py +21 -12
- empathy_os/cli/commands/memory.py +4 -12
- empathy_os/cli/commands/profiling.py +198 -0
- empathy_os/cli/commands/utilities.py +27 -7
- empathy_os/cli.py +28 -57
- empathy_os/cli_unified.py +525 -1164
- empathy_os/cost_tracker.py +9 -3
- empathy_os/dashboard/server.py +200 -2
- empathy_os/hot_reload/__init__.py +7 -7
- empathy_os/hot_reload/config.py +6 -7
- empathy_os/hot_reload/integration.py +35 -35
- empathy_os/hot_reload/reloader.py +57 -57
- empathy_os/hot_reload/watcher.py +28 -28
- empathy_os/hot_reload/websocket.py +2 -2
- empathy_os/memory/__init__.py +11 -4
- empathy_os/memory/claude_memory.py +1 -1
- empathy_os/memory/cross_session.py +8 -12
- empathy_os/memory/edges.py +6 -6
- empathy_os/memory/file_session.py +770 -0
- empathy_os/memory/graph.py +30 -30
- empathy_os/memory/nodes.py +6 -6
- empathy_os/memory/short_term.py +15 -9
- empathy_os/memory/unified.py +606 -140
- empathy_os/meta_workflows/agent_creator.py +3 -9
- empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
- empathy_os/meta_workflows/form_engine.py +6 -18
- empathy_os/meta_workflows/intent_detector.py +64 -24
- empathy_os/meta_workflows/models.py +3 -1
- empathy_os/meta_workflows/pattern_learner.py +13 -31
- empathy_os/meta_workflows/plan_generator.py +55 -47
- empathy_os/meta_workflows/session_context.py +2 -3
- empathy_os/meta_workflows/workflow.py +20 -51
- empathy_os/models/cli.py +2 -2
- empathy_os/models/tasks.py +1 -2
- empathy_os/models/telemetry.py +4 -1
- empathy_os/models/token_estimator.py +3 -1
- empathy_os/monitoring/alerts.py +938 -9
- empathy_os/monitoring/alerts_cli.py +346 -183
- empathy_os/orchestration/execution_strategies.py +12 -29
- empathy_os/orchestration/pattern_learner.py +20 -26
- empathy_os/orchestration/real_tools.py +6 -15
- empathy_os/platform_utils.py +2 -1
- empathy_os/plugins/__init__.py +2 -2
- empathy_os/plugins/base.py +64 -64
- empathy_os/plugins/registry.py +32 -32
- empathy_os/project_index/index.py +49 -15
- empathy_os/project_index/models.py +1 -2
- empathy_os/project_index/reports.py +1 -1
- empathy_os/project_index/scanner.py +1 -0
- empathy_os/redis_memory.py +10 -7
- empathy_os/resilience/__init__.py +1 -1
- empathy_os/resilience/health.py +10 -10
- empathy_os/routing/__init__.py +7 -7
- empathy_os/routing/chain_executor.py +37 -37
- empathy_os/routing/classifier.py +36 -36
- empathy_os/routing/smart_router.py +40 -40
- empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
- empathy_os/scaffolding/__init__.py +8 -8
- empathy_os/scaffolding/__main__.py +1 -1
- empathy_os/scaffolding/cli.py +28 -28
- empathy_os/socratic/__init__.py +3 -19
- empathy_os/socratic/ab_testing.py +25 -36
- empathy_os/socratic/blueprint.py +38 -38
- empathy_os/socratic/cli.py +34 -20
- empathy_os/socratic/collaboration.py +30 -28
- empathy_os/socratic/domain_templates.py +9 -1
- empathy_os/socratic/embeddings.py +17 -13
- empathy_os/socratic/engine.py +135 -70
- empathy_os/socratic/explainer.py +70 -60
- empathy_os/socratic/feedback.py +24 -19
- empathy_os/socratic/forms.py +15 -10
- empathy_os/socratic/generator.py +51 -35
- empathy_os/socratic/llm_analyzer.py +25 -23
- empathy_os/socratic/mcp_server.py +99 -159
- empathy_os/socratic/session.py +19 -13
- empathy_os/socratic/storage.py +98 -67
- empathy_os/socratic/success.py +38 -27
- empathy_os/socratic/visual_editor.py +51 -39
- empathy_os/socratic/web_ui.py +99 -66
- empathy_os/telemetry/cli.py +3 -1
- empathy_os/telemetry/usage_tracker.py +1 -3
- empathy_os/test_generator/__init__.py +3 -3
- empathy_os/test_generator/cli.py +28 -28
- empathy_os/test_generator/generator.py +64 -66
- empathy_os/test_generator/risk_analyzer.py +11 -11
- empathy_os/vscode_bridge 2.py +173 -0
- empathy_os/vscode_bridge.py +173 -0
- empathy_os/workflows/__init__.py +212 -120
- empathy_os/workflows/batch_processing.py +8 -24
- empathy_os/workflows/bug_predict.py +1 -1
- empathy_os/workflows/code_review.py +20 -5
- empathy_os/workflows/code_review_pipeline.py +13 -8
- empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
- empathy_os/workflows/manage_documentation.py +1 -0
- empathy_os/workflows/orchestrated_health_check.py +6 -11
- empathy_os/workflows/orchestrated_release_prep.py +3 -3
- empathy_os/workflows/pr_review.py +18 -10
- empathy_os/workflows/progressive/README 2.md +454 -0
- empathy_os/workflows/progressive/__init__ 2.py +92 -0
- empathy_os/workflows/progressive/__init__.py +2 -12
- empathy_os/workflows/progressive/cli 2.py +242 -0
- empathy_os/workflows/progressive/cli.py +14 -37
- empathy_os/workflows/progressive/core 2.py +488 -0
- empathy_os/workflows/progressive/core.py +12 -12
- empathy_os/workflows/progressive/orchestrator 2.py +701 -0
- empathy_os/workflows/progressive/orchestrator.py +166 -144
- empathy_os/workflows/progressive/reports 2.py +528 -0
- empathy_os/workflows/progressive/reports.py +22 -31
- empathy_os/workflows/progressive/telemetry 2.py +280 -0
- empathy_os/workflows/progressive/telemetry.py +8 -14
- empathy_os/workflows/progressive/test_gen 2.py +514 -0
- empathy_os/workflows/progressive/test_gen.py +29 -48
- empathy_os/workflows/progressive/workflow 2.py +628 -0
- empathy_os/workflows/progressive/workflow.py +31 -70
- empathy_os/workflows/release_prep.py +21 -6
- empathy_os/workflows/release_prep_crew.py +1 -0
- empathy_os/workflows/secure_release.py +13 -6
- empathy_os/workflows/security_audit.py +8 -3
- empathy_os/workflows/test_coverage_boost_crew.py +3 -2
- empathy_os/workflows/test_maintenance_crew.py +1 -0
- empathy_os/workflows/test_runner.py +16 -12
- empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
- empathy_software_plugin/cli.py +0 -122
- patterns/README.md +119 -0
- patterns/__init__.py +95 -0
- patterns/behavior.py +298 -0
- patterns/code_review_memory.json +441 -0
- patterns/core.py +97 -0
- patterns/debugging.json +3763 -0
- patterns/empathy.py +268 -0
- patterns/health_check_memory.json +505 -0
- patterns/input.py +161 -0
- patterns/memory_graph.json +8 -0
- patterns/refactoring_memory.json +1113 -0
- patterns/registry.py +663 -0
- patterns/security_memory.json +8 -0
- patterns/structural.py +415 -0
- patterns/validation.py +194 -0
- coach_wizards/__init__.py +0 -45
- coach_wizards/accessibility_wizard.py +0 -91
- coach_wizards/api_wizard.py +0 -91
- coach_wizards/base_wizard.py +0 -209
- coach_wizards/cicd_wizard.py +0 -91
- coach_wizards/code_reviewer_README.md +0 -60
- coach_wizards/code_reviewer_wizard.py +0 -180
- coach_wizards/compliance_wizard.py +0 -91
- coach_wizards/database_wizard.py +0 -91
- coach_wizards/debugging_wizard.py +0 -91
- coach_wizards/documentation_wizard.py +0 -91
- coach_wizards/generate_wizards.py +0 -347
- coach_wizards/localization_wizard.py +0 -173
- coach_wizards/migration_wizard.py +0 -91
- coach_wizards/monitoring_wizard.py +0 -91
- coach_wizards/observability_wizard.py +0 -91
- coach_wizards/performance_wizard.py +0 -91
- coach_wizards/prompt_engineering_wizard.py +0 -661
- coach_wizards/refactoring_wizard.py +0 -91
- coach_wizards/scaling_wizard.py +0 -90
- coach_wizards/security_wizard.py +0 -92
- coach_wizards/testing_wizard.py +0 -91
- empathy_framework-4.6.6.dist-info/METADATA +0 -1597
- empathy_framework-4.6.6.dist-info/RECORD +0 -410
- empathy_llm_toolkit/wizards/__init__.py +0 -43
- empathy_llm_toolkit/wizards/base_wizard.py +0 -364
- empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
- empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
- empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
- empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
- empathy_os/wizard_factory_cli.py +0 -170
- empathy_software_plugin/wizards/__init__.py +0 -42
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
- empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
- empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
- empathy_software_plugin/wizards/base_wizard.py +0 -288
- empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
- empathy_software_plugin/wizards/code_review_wizard.py +0 -604
- empathy_software_plugin/wizards/debugging/__init__.py +0 -50
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
- empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
- empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
- empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
- empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
- empathy_software_plugin/wizards/debugging/verification.py +0 -369
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
- empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
- empathy_software_plugin/wizards/performance/__init__.py +0 -9
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
- empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
- empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
- empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
- empathy_software_plugin/wizards/security/__init__.py +0 -32
- empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
- empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
- empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
- empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
- empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
- empathy_software_plugin/wizards/testing/__init__.py +0 -27
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
- empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
- empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
- empathy_software_plugin/wizards/testing_wizard.py +0 -274
- wizards/__init__.py +0 -82
- wizards/admission_assessment_wizard.py +0 -644
- wizards/care_plan.py +0 -321
- wizards/clinical_assessment.py +0 -769
- wizards/discharge_planning.py +0 -77
- wizards/discharge_summary_wizard.py +0 -468
- wizards/dosage_calculation.py +0 -497
- wizards/incident_report_wizard.py +0 -454
- wizards/medication_reconciliation.py +0 -85
- wizards/nursing_assessment.py +0 -171
- wizards/patient_education.py +0 -654
- wizards/quality_improvement.py +0 -705
- wizards/sbar_report.py +0 -324
- wizards/sbar_wizard.py +0 -608
- wizards/shift_handoff_wizard.py +0 -535
- wizards/soap_note_wizard.py +0 -679
- wizards/treatment_plan.py +0 -15
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/WHEEL +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/entry_points.txt +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
"""Pattern Extraction Wizard
|
|
2
|
-
|
|
3
|
-
Level 3 wizard that detects bug fixes in git diffs and suggests
|
|
4
|
-
storing them as patterns for future reference.
|
|
5
|
-
|
|
6
|
-
Copyright 2025 Smart AI Memory, LLC
|
|
7
|
-
Licensed under Fair Source 0.9
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import hashlib
|
|
11
|
-
import json
|
|
12
|
-
import logging
|
|
13
|
-
import re
|
|
14
|
-
import subprocess
|
|
15
|
-
from datetime import datetime
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
from typing import Any
|
|
18
|
-
|
|
19
|
-
from .base_wizard import BaseWizard
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class PatternExtractionWizard(BaseWizard):
|
|
25
|
-
"""Detects bug fixes and suggests pattern storage.
|
|
26
|
-
|
|
27
|
-
Analyzes git diffs to identify:
|
|
28
|
-
- Null checks added
|
|
29
|
-
- Error handling added
|
|
30
|
-
- Async/await fixes
|
|
31
|
-
- Import fixes
|
|
32
|
-
- Type fixes
|
|
33
|
-
|
|
34
|
-
Suggests pre-filled patterns for easy storage.
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def name(self) -> str:
|
|
39
|
-
return "PatternExtractionWizard"
|
|
40
|
-
|
|
41
|
-
@property
|
|
42
|
-
def level(self) -> int:
|
|
43
|
-
return 3 # Proactive
|
|
44
|
-
|
|
45
|
-
def __init__(self, patterns_dir: str = "./patterns", **kwargs):
|
|
46
|
-
super().__init__(**kwargs)
|
|
47
|
-
self.patterns_dir = Path(patterns_dir)
|
|
48
|
-
|
|
49
|
-
# Detection patterns for different fix types
|
|
50
|
-
self._fix_patterns = {
|
|
51
|
-
"null_reference": {
|
|
52
|
-
"added": [
|
|
53
|
-
r"\?\.", # Optional chaining
|
|
54
|
-
r"\?\?\s*\[", # Nullish coalescing with array
|
|
55
|
-
r"\?\?\s*\{", # Nullish coalescing with object
|
|
56
|
-
r"if\s*\(\s*\w+\s*(!=|!==)\s*null", # Explicit null check
|
|
57
|
-
r"\.get\s*\(", # Python .get() method
|
|
58
|
-
r"getattr\s*\([^,]+,\s*[^,]+,\s*", # Python getattr with default
|
|
59
|
-
r"or\s*\[\]", # Python or [] fallback
|
|
60
|
-
r"or\s*\{\}", # Python or {} fallback
|
|
61
|
-
],
|
|
62
|
-
"commit_keywords": ["null", "undefined", "none", "optional", "fallback"],
|
|
63
|
-
"description": "Null/undefined reference fix",
|
|
64
|
-
},
|
|
65
|
-
"async_timing": {
|
|
66
|
-
"added": [
|
|
67
|
-
r"\bawait\s+", # Added await
|
|
68
|
-
r"async\s+def\s+", # Made function async
|
|
69
|
-
r"\.then\s*\(", # Added promise handling
|
|
70
|
-
r"asyncio\.gather", # Added asyncio gather
|
|
71
|
-
],
|
|
72
|
-
"commit_keywords": ["await", "async", "promise", "concurrent"],
|
|
73
|
-
"description": "Async/timing fix",
|
|
74
|
-
},
|
|
75
|
-
"error_handling": {
|
|
76
|
-
"added": [
|
|
77
|
-
r"try\s*[:\{]", # Try block
|
|
78
|
-
r"except\s+", # Python except
|
|
79
|
-
r"catch\s*\(", # JS/TS catch
|
|
80
|
-
r"\.catch\s*\(", # Promise catch
|
|
81
|
-
r"finally\s*[:\{]", # Finally block
|
|
82
|
-
r"raise\s+\w+Error", # Python raise
|
|
83
|
-
r"throw\s+new\s+\w+Error", # JS throw
|
|
84
|
-
],
|
|
85
|
-
"commit_keywords": ["error", "exception", "catch", "handle", "try"],
|
|
86
|
-
"description": "Error handling improvement",
|
|
87
|
-
},
|
|
88
|
-
"type_mismatch": {
|
|
89
|
-
"added": [
|
|
90
|
-
r":\s*(str|int|float|bool|list|dict)\s*[=\)]", # Python type hints
|
|
91
|
-
r":\s*(string|number|boolean|object)\s*[;=]", # TS types
|
|
92
|
-
r"isinstance\s*\(", # Python isinstance
|
|
93
|
-
r"typeof\s+\w+\s*===", # JS typeof check
|
|
94
|
-
r"as\s+(str|int|float)", # Python cast
|
|
95
|
-
],
|
|
96
|
-
"commit_keywords": ["type", "cast", "convert", "parse"],
|
|
97
|
-
"description": "Type mismatch fix",
|
|
98
|
-
},
|
|
99
|
-
"import_error": {
|
|
100
|
-
"added": [
|
|
101
|
-
r"from\s+\w+\s+import", # Python import
|
|
102
|
-
r"import\s+\w+\s+from", # ES6 import
|
|
103
|
-
r"require\s*\(", # CommonJS require
|
|
104
|
-
r"try:\s*\n\s*import", # Conditional import
|
|
105
|
-
],
|
|
106
|
-
"commit_keywords": ["import", "module", "package", "dependency"],
|
|
107
|
-
"description": "Import/dependency fix",
|
|
108
|
-
},
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async def analyze(self, context: dict[str, Any]) -> dict[str, Any]:
|
|
112
|
-
"""Analyze git diff for potential bug fix patterns.
|
|
113
|
-
|
|
114
|
-
Args:
|
|
115
|
-
context: {
|
|
116
|
-
"diff": str - Git diff content (optional, will fetch if not provided)
|
|
117
|
-
"commit_message": str - Commit message (optional)
|
|
118
|
-
"commits": int - Number of recent commits to analyze (default 1)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
{
|
|
123
|
-
"suggested_patterns": list of suggested patterns,
|
|
124
|
-
"predictions": list of predictions,
|
|
125
|
-
"recommendations": list of recommendations,
|
|
126
|
-
"confidence": float
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
"""
|
|
130
|
-
diff = context.get("diff")
|
|
131
|
-
commit_message = context.get("commit_message", "")
|
|
132
|
-
commits = context.get("commits", 1)
|
|
133
|
-
|
|
134
|
-
# SECURITY: Validate commits parameter to prevent command injection
|
|
135
|
-
# Must be a positive integer within reasonable bounds
|
|
136
|
-
try:
|
|
137
|
-
commits = int(commits)
|
|
138
|
-
if commits < 1 or commits > 100:
|
|
139
|
-
commits = 1
|
|
140
|
-
except (TypeError, ValueError):
|
|
141
|
-
commits = 1
|
|
142
|
-
|
|
143
|
-
# Fetch diff if not provided
|
|
144
|
-
if not diff:
|
|
145
|
-
diff, commit_message = self._get_git_diff(commits)
|
|
146
|
-
|
|
147
|
-
if not diff:
|
|
148
|
-
return {
|
|
149
|
-
"suggested_patterns": [],
|
|
150
|
-
"predictions": [
|
|
151
|
-
{
|
|
152
|
-
"type": "no_changes",
|
|
153
|
-
"severity": "info",
|
|
154
|
-
"description": "No git changes detected to analyze.",
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
"recommendations": ["Make some code changes and try again."],
|
|
158
|
-
"confidence": 0.0,
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
# Analyze the diff
|
|
162
|
-
suggested_patterns = self._extract_patterns(diff, commit_message)
|
|
163
|
-
|
|
164
|
-
# Generate predictions
|
|
165
|
-
predictions = self._generate_predictions(suggested_patterns)
|
|
166
|
-
|
|
167
|
-
# Generate recommendations
|
|
168
|
-
recommendations = self._generate_recommendations(suggested_patterns)
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
"suggested_patterns": suggested_patterns,
|
|
172
|
-
"predictions": predictions,
|
|
173
|
-
"recommendations": recommendations,
|
|
174
|
-
"confidence": self._calculate_confidence(suggested_patterns),
|
|
175
|
-
"metadata": {
|
|
176
|
-
"wizard": self.name,
|
|
177
|
-
"level": self.level,
|
|
178
|
-
"timestamp": datetime.now().isoformat(),
|
|
179
|
-
"diff_lines": len(diff.split("\n")),
|
|
180
|
-
},
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
def _get_git_diff(self, commits: int = 1) -> tuple[str, str]:
|
|
184
|
-
"""Get git diff and commit message."""
|
|
185
|
-
try:
|
|
186
|
-
# Get diff
|
|
187
|
-
diff_result = subprocess.run(
|
|
188
|
-
["git", "diff", f"HEAD~{commits}", "HEAD"],
|
|
189
|
-
check=False,
|
|
190
|
-
capture_output=True,
|
|
191
|
-
text=True,
|
|
192
|
-
timeout=10,
|
|
193
|
-
)
|
|
194
|
-
diff = diff_result.stdout if diff_result.returncode == 0 else ""
|
|
195
|
-
|
|
196
|
-
# Get commit message
|
|
197
|
-
msg_result = subprocess.run(
|
|
198
|
-
["git", "log", f"-{commits}", "--format=%s%n%b"],
|
|
199
|
-
check=False,
|
|
200
|
-
capture_output=True,
|
|
201
|
-
text=True,
|
|
202
|
-
timeout=5,
|
|
203
|
-
)
|
|
204
|
-
message = msg_result.stdout if msg_result.returncode == 0 else ""
|
|
205
|
-
|
|
206
|
-
return diff, message
|
|
207
|
-
except Exception as e:
|
|
208
|
-
# Optional: Git operations unavailable (not a git repo or git not installed)
|
|
209
|
-
logger.debug(f"Could not fetch git diff/message: {e}")
|
|
210
|
-
return "", ""
|
|
211
|
-
|
|
212
|
-
def _extract_patterns(self, diff: str, commit_message: str) -> list[dict]:
|
|
213
|
-
"""Extract potential bug fix patterns from diff."""
|
|
214
|
-
suggested = []
|
|
215
|
-
commit_lower = commit_message.lower()
|
|
216
|
-
|
|
217
|
-
# Parse diff to get changed files and added lines
|
|
218
|
-
current_file = ""
|
|
219
|
-
added_lines: list[str] = []
|
|
220
|
-
|
|
221
|
-
for line in diff.split("\n"):
|
|
222
|
-
if line.startswith("diff --git"):
|
|
223
|
-
# Save previous file's patterns
|
|
224
|
-
if current_file and added_lines:
|
|
225
|
-
file_patterns = self._analyze_file_changes(
|
|
226
|
-
current_file,
|
|
227
|
-
added_lines,
|
|
228
|
-
commit_lower,
|
|
229
|
-
)
|
|
230
|
-
suggested.extend(file_patterns)
|
|
231
|
-
|
|
232
|
-
# Start new file
|
|
233
|
-
match = re.search(r"b/(.+)$", line)
|
|
234
|
-
current_file = match.group(1) if match else ""
|
|
235
|
-
added_lines = []
|
|
236
|
-
|
|
237
|
-
elif line.startswith("+") and not line.startswith("+++"):
|
|
238
|
-
added_lines.append(line[1:]) # Remove + prefix
|
|
239
|
-
|
|
240
|
-
# Don't forget last file
|
|
241
|
-
if current_file and added_lines:
|
|
242
|
-
file_patterns = self._analyze_file_changes(current_file, added_lines, commit_lower)
|
|
243
|
-
suggested.extend(file_patterns)
|
|
244
|
-
|
|
245
|
-
return suggested
|
|
246
|
-
|
|
247
|
-
def _analyze_file_changes(
|
|
248
|
-
self,
|
|
249
|
-
file_path: str,
|
|
250
|
-
added_lines: list[str],
|
|
251
|
-
commit_message: str,
|
|
252
|
-
) -> list[dict]:
|
|
253
|
-
"""Analyze changes to a single file for patterns."""
|
|
254
|
-
patterns = []
|
|
255
|
-
added_content = "\n".join(added_lines)
|
|
256
|
-
|
|
257
|
-
for pattern_type, config in self._fix_patterns.items():
|
|
258
|
-
# Check if any fix patterns were added
|
|
259
|
-
matches = []
|
|
260
|
-
for regex in config["added"]:
|
|
261
|
-
found = re.findall(regex, added_content)
|
|
262
|
-
if found:
|
|
263
|
-
matches.extend(found)
|
|
264
|
-
|
|
265
|
-
if not matches:
|
|
266
|
-
continue
|
|
267
|
-
|
|
268
|
-
# Check commit message for keywords
|
|
269
|
-
keyword_match = any(kw in commit_message for kw in config["commit_keywords"])
|
|
270
|
-
|
|
271
|
-
# Calculate confidence
|
|
272
|
-
confidence = 0.5
|
|
273
|
-
if keyword_match:
|
|
274
|
-
confidence += 0.3
|
|
275
|
-
if len(matches) > 1:
|
|
276
|
-
confidence += 0.1
|
|
277
|
-
confidence = min(confidence, 0.95)
|
|
278
|
-
|
|
279
|
-
# Generate pattern suggestion
|
|
280
|
-
pattern_id = self._generate_pattern_id(file_path, pattern_type)
|
|
281
|
-
|
|
282
|
-
patterns.append(
|
|
283
|
-
{
|
|
284
|
-
"pattern_id": pattern_id,
|
|
285
|
-
"type": pattern_type,
|
|
286
|
-
"file": file_path,
|
|
287
|
-
"matches": matches[:3], # Limit examples
|
|
288
|
-
"confidence": confidence,
|
|
289
|
-
"commit_keyword_match": keyword_match,
|
|
290
|
-
"description": config["description"],
|
|
291
|
-
"pre_filled": {
|
|
292
|
-
"bug_id": pattern_id,
|
|
293
|
-
"date": datetime.now().isoformat(),
|
|
294
|
-
"file_path": file_path,
|
|
295
|
-
"error_type": pattern_type,
|
|
296
|
-
"error_message": f"Detected {str(config['description']).lower()}",
|
|
297
|
-
"root_cause": "", # User fills in
|
|
298
|
-
"fix_applied": config["description"],
|
|
299
|
-
"fix_code": matches[0] if matches else "",
|
|
300
|
-
"status": "investigating",
|
|
301
|
-
},
|
|
302
|
-
},
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
return patterns
|
|
306
|
-
|
|
307
|
-
def _generate_pattern_id(self, file_path: str, pattern_type: str) -> str:
|
|
308
|
-
"""Generate a unique pattern ID."""
|
|
309
|
-
date_str = datetime.now().strftime("%Y%m%d")
|
|
310
|
-
content = f"{file_path}:{pattern_type}:{datetime.now().isoformat()}"
|
|
311
|
-
hash_suffix = hashlib.md5(content.encode(), usedforsecurity=False).hexdigest()[:8]
|
|
312
|
-
return f"bug_{date_str}_{hash_suffix}"
|
|
313
|
-
|
|
314
|
-
def _generate_predictions(self, patterns: list[dict]) -> list[dict]:
|
|
315
|
-
"""Generate Level 3 predictions about patterns."""
|
|
316
|
-
predictions: list[dict] = []
|
|
317
|
-
|
|
318
|
-
if not patterns:
|
|
319
|
-
return predictions
|
|
320
|
-
|
|
321
|
-
# High confidence patterns
|
|
322
|
-
high_conf = [p for p in patterns if p["confidence"] >= 0.8]
|
|
323
|
-
if high_conf:
|
|
324
|
-
predictions.append(
|
|
325
|
-
{
|
|
326
|
-
"type": "high_value_patterns",
|
|
327
|
-
"severity": "info",
|
|
328
|
-
"description": f"{len(high_conf)} high-confidence fix patterns detected. These are likely valuable for future reference.",
|
|
329
|
-
},
|
|
330
|
-
)
|
|
331
|
-
|
|
332
|
-
# Common pattern types
|
|
333
|
-
type_counts: dict[str, int] = {}
|
|
334
|
-
for p in patterns:
|
|
335
|
-
type_counts[p["type"]] = type_counts.get(p["type"], 0) + 1
|
|
336
|
-
|
|
337
|
-
most_common = max(type_counts.items(), key=lambda x: x[1]) if type_counts else None
|
|
338
|
-
if most_common and most_common[1] >= 2:
|
|
339
|
-
predictions.append(
|
|
340
|
-
{
|
|
341
|
-
"type": "recurring_fix_type",
|
|
342
|
-
"severity": "warning",
|
|
343
|
-
"description": f"Multiple {most_common[0]} fixes detected ({most_common[1]}). Consider adding preventive checks.",
|
|
344
|
-
},
|
|
345
|
-
)
|
|
346
|
-
|
|
347
|
-
return predictions
|
|
348
|
-
|
|
349
|
-
def _generate_recommendations(self, patterns: list[dict]) -> list[str]:
|
|
350
|
-
"""Generate recommendations for pattern storage."""
|
|
351
|
-
if not patterns:
|
|
352
|
-
return ["No fix patterns detected in recent changes."]
|
|
353
|
-
|
|
354
|
-
recommendations = []
|
|
355
|
-
|
|
356
|
-
# Suggest storing high confidence patterns
|
|
357
|
-
high_conf = [p for p in patterns if p["confidence"] >= 0.7]
|
|
358
|
-
if high_conf:
|
|
359
|
-
recommendations.append(
|
|
360
|
-
f"Consider storing {len(high_conf)} detected fix pattern(s) for future reference.",
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
# Add specific storage command
|
|
364
|
-
if patterns:
|
|
365
|
-
first = patterns[0]
|
|
366
|
-
recommendations.append(
|
|
367
|
-
f"To store: empathy patterns resolve {first['pattern_id']} "
|
|
368
|
-
f"--root-cause '<cause>' --fix '{first['description']}'",
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
return recommendations
|
|
372
|
-
|
|
373
|
-
def _calculate_confidence(self, patterns: list[dict]) -> float:
|
|
374
|
-
"""Calculate overall confidence score."""
|
|
375
|
-
if not patterns:
|
|
376
|
-
return 0.0
|
|
377
|
-
|
|
378
|
-
avg_conf = sum(p["confidence"] for p in patterns) / len(patterns)
|
|
379
|
-
# Boost if multiple patterns detected
|
|
380
|
-
if len(patterns) >= 2:
|
|
381
|
-
avg_conf = min(avg_conf + 0.1, 1.0)
|
|
382
|
-
|
|
383
|
-
return float(round(avg_conf, 2))
|
|
384
|
-
|
|
385
|
-
async def save_pattern(self, pattern: dict) -> bool:
|
|
386
|
-
"""Save a suggested pattern to storage.
|
|
387
|
-
|
|
388
|
-
Args:
|
|
389
|
-
pattern: Pattern dict from suggested_patterns
|
|
390
|
-
|
|
391
|
-
Returns:
|
|
392
|
-
True if saved successfully
|
|
393
|
-
|
|
394
|
-
"""
|
|
395
|
-
pre_filled = pattern.get("pre_filled", {})
|
|
396
|
-
if not pre_filled:
|
|
397
|
-
return False
|
|
398
|
-
|
|
399
|
-
# Determine output directory
|
|
400
|
-
output_dir = self.patterns_dir / "debugging"
|
|
401
|
-
output_dir.mkdir(parents=True, exist_ok=True)
|
|
402
|
-
|
|
403
|
-
# Write pattern file
|
|
404
|
-
output_file = output_dir / f"{pre_filled['bug_id']}.json"
|
|
405
|
-
try:
|
|
406
|
-
with open(output_file, "w", encoding="utf-8") as f:
|
|
407
|
-
json.dump(pre_filled, f, indent=2, default=str)
|
|
408
|
-
return True
|
|
409
|
-
except OSError:
|
|
410
|
-
return False
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
# CLI support
|
|
414
|
-
if __name__ == "__main__":
|
|
415
|
-
import asyncio
|
|
416
|
-
|
|
417
|
-
async def main():
|
|
418
|
-
wizard = PatternExtractionWizard()
|
|
419
|
-
result = await wizard.analyze({"commits": 3})
|
|
420
|
-
print(json.dumps(result, indent=2, default=str))
|
|
421
|
-
|
|
422
|
-
asyncio.run(main())
|