empathy-framework 3.2.3__py3-none-any.whl → 3.8.2__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.
- coach_wizards/__init__.py +11 -12
- coach_wizards/accessibility_wizard.py +12 -12
- coach_wizards/api_wizard.py +12 -12
- coach_wizards/base_wizard.py +26 -20
- coach_wizards/cicd_wizard.py +15 -13
- coach_wizards/code_reviewer_README.md +60 -0
- coach_wizards/code_reviewer_wizard.py +180 -0
- coach_wizards/compliance_wizard.py +12 -12
- coach_wizards/database_wizard.py +12 -12
- coach_wizards/debugging_wizard.py +12 -12
- coach_wizards/documentation_wizard.py +12 -12
- coach_wizards/generate_wizards.py +1 -2
- coach_wizards/localization_wizard.py +101 -19
- coach_wizards/migration_wizard.py +12 -12
- coach_wizards/monitoring_wizard.py +12 -12
- coach_wizards/observability_wizard.py +12 -12
- coach_wizards/performance_wizard.py +12 -12
- coach_wizards/prompt_engineering_wizard.py +22 -25
- coach_wizards/refactoring_wizard.py +12 -12
- coach_wizards/scaling_wizard.py +12 -12
- coach_wizards/security_wizard.py +12 -12
- coach_wizards/testing_wizard.py +12 -12
- {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/METADATA +513 -58
- empathy_framework-3.8.2.dist-info/RECORD +333 -0
- empathy_framework-3.8.2.dist-info/entry_points.txt +22 -0
- {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/top_level.txt +5 -1
- empathy_healthcare_plugin/__init__.py +1 -2
- empathy_healthcare_plugin/monitors/__init__.py +9 -0
- empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
- empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
- empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
- empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
- empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
- empathy_llm_toolkit/__init__.py +7 -7
- empathy_llm_toolkit/agent_factory/__init__.py +53 -0
- empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
- empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
- empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
- empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
- empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
- empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
- empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
- empathy_llm_toolkit/agent_factory/base.py +305 -0
- empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
- empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
- empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
- empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
- empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
- empathy_llm_toolkit/agent_factory/decorators.py +286 -0
- empathy_llm_toolkit/agent_factory/factory.py +558 -0
- empathy_llm_toolkit/agent_factory/framework.py +192 -0
- empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
- empathy_llm_toolkit/agent_factory/resilient.py +320 -0
- empathy_llm_toolkit/claude_memory.py +14 -15
- empathy_llm_toolkit/cli/__init__.py +8 -0
- empathy_llm_toolkit/cli/sync_claude.py +487 -0
- empathy_llm_toolkit/code_health.py +177 -22
- empathy_llm_toolkit/config/__init__.py +29 -0
- empathy_llm_toolkit/config/unified.py +295 -0
- empathy_llm_toolkit/contextual_patterns.py +11 -12
- empathy_llm_toolkit/core.py +51 -49
- empathy_llm_toolkit/git_pattern_extractor.py +16 -12
- empathy_llm_toolkit/levels.py +6 -13
- empathy_llm_toolkit/pattern_confidence.py +14 -18
- empathy_llm_toolkit/pattern_resolver.py +10 -12
- empathy_llm_toolkit/pattern_summary.py +13 -11
- empathy_llm_toolkit/providers.py +194 -28
- empathy_llm_toolkit/routing/__init__.py +32 -0
- empathy_llm_toolkit/routing/model_router.py +362 -0
- empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
- empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
- empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
- empathy_llm_toolkit/security/README.md +262 -0
- empathy_llm_toolkit/security/__init__.py +62 -0
- empathy_llm_toolkit/security/audit_logger.py +929 -0
- empathy_llm_toolkit/security/audit_logger_example.py +152 -0
- empathy_llm_toolkit/security/pii_scrubber.py +640 -0
- empathy_llm_toolkit/security/secrets_detector.py +678 -0
- empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
- empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
- empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
- empathy_llm_toolkit/session_status.py +18 -20
- empathy_llm_toolkit/state.py +20 -21
- empathy_llm_toolkit/wizards/__init__.py +38 -0
- empathy_llm_toolkit/wizards/base_wizard.py +364 -0
- empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
- empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
- empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
- empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
- empathy_os/__init__.py +76 -77
- empathy_os/adaptive/__init__.py +13 -0
- empathy_os/adaptive/task_complexity.py +127 -0
- empathy_os/{monitoring.py → agent_monitoring.py} +27 -27
- empathy_os/cache/__init__.py +117 -0
- empathy_os/cache/base.py +166 -0
- empathy_os/cache/dependency_manager.py +253 -0
- empathy_os/cache/hash_only.py +248 -0
- empathy_os/cache/hybrid.py +390 -0
- empathy_os/cache/storage.py +282 -0
- empathy_os/cli.py +515 -109
- empathy_os/cli_unified.py +189 -42
- empathy_os/config/__init__.py +63 -0
- empathy_os/config/xml_config.py +239 -0
- empathy_os/config.py +87 -36
- empathy_os/coordination.py +48 -54
- empathy_os/core.py +90 -99
- empathy_os/cost_tracker.py +20 -23
- empathy_os/dashboard/__init__.py +15 -0
- empathy_os/dashboard/server.py +743 -0
- empathy_os/discovery.py +9 -11
- empathy_os/emergence.py +20 -21
- empathy_os/exceptions.py +18 -30
- empathy_os/feedback_loops.py +27 -30
- empathy_os/levels.py +31 -34
- empathy_os/leverage_points.py +27 -28
- empathy_os/logging_config.py +11 -12
- empathy_os/memory/__init__.py +195 -0
- empathy_os/memory/claude_memory.py +466 -0
- empathy_os/memory/config.py +224 -0
- empathy_os/memory/control_panel.py +1298 -0
- empathy_os/memory/edges.py +179 -0
- empathy_os/memory/graph.py +567 -0
- empathy_os/memory/long_term.py +1194 -0
- empathy_os/memory/nodes.py +179 -0
- empathy_os/memory/redis_bootstrap.py +540 -0
- empathy_os/memory/security/__init__.py +31 -0
- empathy_os/memory/security/audit_logger.py +930 -0
- empathy_os/memory/security/pii_scrubber.py +640 -0
- empathy_os/memory/security/secrets_detector.py +678 -0
- empathy_os/memory/short_term.py +2119 -0
- empathy_os/memory/storage/__init__.py +15 -0
- empathy_os/memory/summary_index.py +583 -0
- empathy_os/memory/unified.py +619 -0
- empathy_os/metrics/__init__.py +12 -0
- empathy_os/metrics/prompt_metrics.py +190 -0
- empathy_os/models/__init__.py +136 -0
- empathy_os/models/__main__.py +13 -0
- empathy_os/models/cli.py +655 -0
- empathy_os/models/empathy_executor.py +354 -0
- empathy_os/models/executor.py +252 -0
- empathy_os/models/fallback.py +671 -0
- empathy_os/models/provider_config.py +563 -0
- empathy_os/models/registry.py +382 -0
- empathy_os/models/tasks.py +302 -0
- empathy_os/models/telemetry.py +548 -0
- empathy_os/models/token_estimator.py +378 -0
- empathy_os/models/validation.py +274 -0
- empathy_os/monitoring/__init__.py +52 -0
- empathy_os/monitoring/alerts.py +23 -0
- empathy_os/monitoring/alerts_cli.py +268 -0
- empathy_os/monitoring/multi_backend.py +271 -0
- empathy_os/monitoring/otel_backend.py +363 -0
- empathy_os/optimization/__init__.py +19 -0
- empathy_os/optimization/context_optimizer.py +272 -0
- empathy_os/pattern_library.py +29 -28
- empathy_os/persistence.py +30 -34
- empathy_os/platform_utils.py +261 -0
- empathy_os/plugins/__init__.py +28 -0
- empathy_os/plugins/base.py +361 -0
- empathy_os/plugins/registry.py +268 -0
- empathy_os/project_index/__init__.py +30 -0
- empathy_os/project_index/cli.py +335 -0
- empathy_os/project_index/crew_integration.py +430 -0
- empathy_os/project_index/index.py +425 -0
- empathy_os/project_index/models.py +501 -0
- empathy_os/project_index/reports.py +473 -0
- empathy_os/project_index/scanner.py +538 -0
- empathy_os/prompts/__init__.py +61 -0
- empathy_os/prompts/config.py +77 -0
- empathy_os/prompts/context.py +177 -0
- empathy_os/prompts/parser.py +285 -0
- empathy_os/prompts/registry.py +313 -0
- empathy_os/prompts/templates.py +208 -0
- empathy_os/redis_config.py +144 -58
- empathy_os/redis_memory.py +53 -56
- empathy_os/resilience/__init__.py +56 -0
- empathy_os/resilience/circuit_breaker.py +256 -0
- empathy_os/resilience/fallback.py +179 -0
- empathy_os/resilience/health.py +300 -0
- empathy_os/resilience/retry.py +209 -0
- empathy_os/resilience/timeout.py +135 -0
- empathy_os/routing/__init__.py +43 -0
- empathy_os/routing/chain_executor.py +433 -0
- empathy_os/routing/classifier.py +217 -0
- empathy_os/routing/smart_router.py +234 -0
- empathy_os/routing/wizard_registry.py +307 -0
- empathy_os/templates.py +12 -11
- empathy_os/trust/__init__.py +28 -0
- empathy_os/trust/circuit_breaker.py +579 -0
- empathy_os/trust_building.py +44 -36
- empathy_os/validation/__init__.py +19 -0
- empathy_os/validation/xml_validator.py +281 -0
- empathy_os/wizard_factory_cli.py +170 -0
- empathy_os/{workflows.py → workflow_commands.py} +123 -31
- empathy_os/workflows/__init__.py +360 -0
- empathy_os/workflows/base.py +1660 -0
- empathy_os/workflows/bug_predict.py +962 -0
- empathy_os/workflows/code_review.py +960 -0
- empathy_os/workflows/code_review_adapters.py +310 -0
- empathy_os/workflows/code_review_pipeline.py +720 -0
- empathy_os/workflows/config.py +600 -0
- empathy_os/workflows/dependency_check.py +648 -0
- empathy_os/workflows/document_gen.py +1069 -0
- empathy_os/workflows/documentation_orchestrator.py +1205 -0
- empathy_os/workflows/health_check.py +679 -0
- empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
- empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
- empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
- empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
- empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
- empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
- empathy_os/workflows/manage_documentation.py +804 -0
- empathy_os/workflows/new_sample_workflow1.py +146 -0
- empathy_os/workflows/new_sample_workflow1_README.md +150 -0
- empathy_os/workflows/perf_audit.py +687 -0
- empathy_os/workflows/pr_review.py +748 -0
- empathy_os/workflows/progress.py +445 -0
- empathy_os/workflows/progress_server.py +322 -0
- empathy_os/workflows/refactor_plan.py +693 -0
- empathy_os/workflows/release_prep.py +808 -0
- empathy_os/workflows/research_synthesis.py +404 -0
- empathy_os/workflows/secure_release.py +585 -0
- empathy_os/workflows/security_adapters.py +297 -0
- empathy_os/workflows/security_audit.py +1046 -0
- empathy_os/workflows/step_config.py +234 -0
- empathy_os/workflows/test5.py +125 -0
- empathy_os/workflows/test5_README.md +158 -0
- empathy_os/workflows/test_gen.py +1855 -0
- empathy_os/workflows/test_lifecycle.py +526 -0
- empathy_os/workflows/test_maintenance.py +626 -0
- empathy_os/workflows/test_maintenance_cli.py +590 -0
- empathy_os/workflows/test_maintenance_crew.py +821 -0
- empathy_os/workflows/xml_enhanced_crew.py +285 -0
- empathy_software_plugin/__init__.py +1 -2
- empathy_software_plugin/cli/__init__.py +120 -0
- empathy_software_plugin/cli/inspect.py +362 -0
- empathy_software_plugin/cli.py +35 -26
- empathy_software_plugin/plugin.py +4 -8
- empathy_software_plugin/wizards/__init__.py +42 -0
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
- empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
- empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
- empathy_software_plugin/wizards/base_wizard.py +288 -0
- empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
- empathy_software_plugin/wizards/code_review_wizard.py +606 -0
- empathy_software_plugin/wizards/debugging/__init__.py +50 -0
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
- empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
- empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
- empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
- empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
- empathy_software_plugin/wizards/debugging/verification.py +369 -0
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
- empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
- empathy_software_plugin/wizards/performance/__init__.py +9 -0
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
- empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
- empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
- empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
- empathy_software_plugin/wizards/security/__init__.py +32 -0
- empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
- empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
- empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
- empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
- empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
- empathy_software_plugin/wizards/testing/__init__.py +27 -0
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
- empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
- empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
- empathy_software_plugin/wizards/testing_wizard.py +274 -0
- hot_reload/README.md +473 -0
- hot_reload/__init__.py +62 -0
- hot_reload/config.py +84 -0
- hot_reload/integration.py +228 -0
- hot_reload/reloader.py +298 -0
- hot_reload/watcher.py +179 -0
- hot_reload/websocket.py +176 -0
- scaffolding/README.md +589 -0
- scaffolding/__init__.py +35 -0
- scaffolding/__main__.py +14 -0
- scaffolding/cli.py +240 -0
- test_generator/__init__.py +38 -0
- test_generator/__main__.py +14 -0
- test_generator/cli.py +226 -0
- test_generator/generator.py +325 -0
- test_generator/risk_analyzer.py +216 -0
- workflow_patterns/__init__.py +33 -0
- workflow_patterns/behavior.py +249 -0
- workflow_patterns/core.py +76 -0
- workflow_patterns/output.py +99 -0
- workflow_patterns/registry.py +255 -0
- workflow_patterns/structural.py +288 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
- agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
- agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
- agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
- agents/compliance_anticipation_agent.py +0 -1427
- agents/epic_integration_wizard.py +0 -541
- agents/trust_building_behaviors.py +0 -891
- empathy_framework-3.2.3.dist-info/RECORD +0 -104
- empathy_framework-3.2.3.dist-info/entry_points.txt +0 -7
- empathy_llm_toolkit/htmlcov/status.json +0 -1
- empathy_llm_toolkit/security/htmlcov/status.json +0 -1
- {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/WHEEL +0 -0
- {empathy_framework-3.2.3.dist-info → empathy_framework-3.8.2.dist-info}/licenses/LICENSE +0 -0
empathy_os/cli.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Command-Line Interface for Empathy Framework
|
|
1
|
+
"""Command-Line Interface for Empathy Framework
|
|
3
2
|
|
|
4
3
|
Provides CLI commands for:
|
|
5
4
|
- Running interactive REPL (empathy run)
|
|
@@ -25,9 +24,10 @@ from empathy_os.discovery import show_tip_if_available
|
|
|
25
24
|
from empathy_os.logging_config import get_logger
|
|
26
25
|
from empathy_os.pattern_library import PatternLibrary
|
|
27
26
|
from empathy_os.persistence import MetricsCollector, PatternPersistence, StateManager
|
|
27
|
+
from empathy_os.platform_utils import setup_asyncio_policy
|
|
28
28
|
from empathy_os.templates import cmd_new
|
|
29
|
+
from empathy_os.wizard_factory_cli import add_wizard_factory_commands
|
|
29
30
|
from empathy_os.workflows import (
|
|
30
|
-
WorkflowConfig,
|
|
31
31
|
cmd_fix_all,
|
|
32
32
|
cmd_learn,
|
|
33
33
|
cmd_morning,
|
|
@@ -285,7 +285,9 @@ def cmd_version(args):
|
|
|
285
285
|
logger.info("Displaying version information")
|
|
286
286
|
try:
|
|
287
287
|
version = get_version("empathy")
|
|
288
|
-
except Exception:
|
|
288
|
+
except Exception as e:
|
|
289
|
+
# Package metadata not available or invalid (development install)
|
|
290
|
+
logger.debug(f"Version not available: {e}")
|
|
289
291
|
version = "unknown"
|
|
290
292
|
logger.info(f"Empathy v{version}")
|
|
291
293
|
logger.info("Copyright 2025 Smart-AI-Memory")
|
|
@@ -482,10 +484,9 @@ for a quick reference of all commands.
|
|
|
482
484
|
print(" Congratulations! You've completed the onboarding!")
|
|
483
485
|
print()
|
|
484
486
|
_show_achievements(engine)
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
print(" Then run 'empathy onboard' to continue")
|
|
487
|
+
elif step_data["action"]:
|
|
488
|
+
print(f" NEXT: Run '{step_data['action']}'")
|
|
489
|
+
print(" Then run 'empathy onboard' to continue")
|
|
489
490
|
|
|
490
491
|
print()
|
|
491
492
|
print("-" * 60)
|
|
@@ -642,10 +643,21 @@ def cmd_validate(args):
|
|
|
642
643
|
logger.info(f" Confidence Threshold: {config.confidence_threshold}")
|
|
643
644
|
logger.info(f" Persistence Backend: {config.persistence_backend}")
|
|
644
645
|
logger.info(f" Metrics Enabled: {config.metrics_enabled}")
|
|
645
|
-
except
|
|
646
|
+
except (OSError, FileNotFoundError) as e:
|
|
647
|
+
# Config file not found or cannot be read
|
|
648
|
+
logger.error(f"Configuration file error: {e}")
|
|
649
|
+
logger.error(f"✗ Cannot read configuration file: {e}")
|
|
650
|
+
sys.exit(1)
|
|
651
|
+
except ValueError as e:
|
|
652
|
+
# Invalid configuration values
|
|
646
653
|
logger.error(f"Configuration validation failed: {e}")
|
|
647
654
|
logger.error(f"✗ Configuration invalid: {e}")
|
|
648
655
|
sys.exit(1)
|
|
656
|
+
except Exception as e:
|
|
657
|
+
# Unexpected errors during config validation
|
|
658
|
+
logger.exception(f"Unexpected error validating configuration: {e}")
|
|
659
|
+
logger.error(f"✗ Configuration invalid: {e}")
|
|
660
|
+
sys.exit(1)
|
|
649
661
|
|
|
650
662
|
|
|
651
663
|
def cmd_info(args):
|
|
@@ -736,8 +748,19 @@ def cmd_patterns_export(args):
|
|
|
736
748
|
|
|
737
749
|
logger.info(f"Loaded {len(library.patterns)} patterns from {input_file}")
|
|
738
750
|
logger.info(f"✓ Loaded {len(library.patterns)} patterns from {input_file}")
|
|
751
|
+
except (OSError, FileNotFoundError) as e:
|
|
752
|
+
# Input file not found or cannot be read
|
|
753
|
+
logger.error(f"Pattern file error: {e}")
|
|
754
|
+
logger.error(f"✗ Cannot read pattern file: {e}")
|
|
755
|
+
sys.exit(1)
|
|
756
|
+
except (ValueError, KeyError) as e:
|
|
757
|
+
# Invalid pattern data format
|
|
758
|
+
logger.error(f"Pattern data error: {e}")
|
|
759
|
+
logger.error(f"✗ Invalid pattern data: {e}")
|
|
760
|
+
sys.exit(1)
|
|
739
761
|
except Exception as e:
|
|
740
|
-
|
|
762
|
+
# Unexpected errors loading patterns
|
|
763
|
+
logger.exception(f"Unexpected error loading patterns: {e}")
|
|
741
764
|
logger.error(f"✗ Failed to load patterns: {e}")
|
|
742
765
|
sys.exit(1)
|
|
743
766
|
|
|
@@ -750,8 +773,14 @@ def cmd_patterns_export(args):
|
|
|
750
773
|
|
|
751
774
|
logger.info(f"Saved {len(library.patterns)} patterns to {output_file}")
|
|
752
775
|
logger.info(f"✓ Saved {len(library.patterns)} patterns to {output_file}")
|
|
776
|
+
except (OSError, FileNotFoundError, PermissionError) as e:
|
|
777
|
+
# Cannot write output file
|
|
778
|
+
logger.error(f"Pattern file write error: {e}")
|
|
779
|
+
logger.error(f"✗ Cannot write pattern file: {e}")
|
|
780
|
+
sys.exit(1)
|
|
753
781
|
except Exception as e:
|
|
754
|
-
|
|
782
|
+
# Unexpected errors saving patterns
|
|
783
|
+
logger.exception(f"Unexpected error saving patterns: {e}")
|
|
755
784
|
logger.error(f"✗ Failed to save patterns: {e}")
|
|
756
785
|
sys.exit(1)
|
|
757
786
|
|
|
@@ -783,7 +812,7 @@ def cmd_patterns_resolve(args):
|
|
|
783
812
|
if not args.root_cause or not args.fix:
|
|
784
813
|
print("✗ --root-cause and --fix are required when resolving a bug")
|
|
785
814
|
print(
|
|
786
|
-
" Example: empathy patterns resolve bug_123 --root-cause 'Null check' --fix 'Added ?.'"
|
|
815
|
+
" Example: empathy patterns resolve bug_123 --root-cause 'Null check' --fix 'Added ?.'",
|
|
787
816
|
)
|
|
788
817
|
sys.exit(1)
|
|
789
818
|
|
|
@@ -870,8 +899,8 @@ def cmd_review(args):
|
|
|
870
899
|
"files": args.files,
|
|
871
900
|
"staged_only": args.staged,
|
|
872
901
|
"severity_threshold": args.severity,
|
|
873
|
-
}
|
|
874
|
-
)
|
|
902
|
+
},
|
|
903
|
+
),
|
|
875
904
|
)
|
|
876
905
|
|
|
877
906
|
# Output results
|
|
@@ -972,7 +1001,7 @@ def cmd_health(args):
|
|
|
972
1001
|
print(f"\n⚠ Skipped {len(result['skipped'])} issue(s) (could not auto-fix)")
|
|
973
1002
|
else:
|
|
974
1003
|
print(
|
|
975
|
-
f"\n⚠ Skipped {len(result['skipped'])} issue(s) (use --interactive to review)"
|
|
1004
|
+
f"\n⚠ Skipped {len(result['skipped'])} issue(s) (use --interactive to review)",
|
|
976
1005
|
)
|
|
977
1006
|
|
|
978
1007
|
if result["failed"]:
|
|
@@ -1043,8 +1072,19 @@ def cmd_metrics_show(args):
|
|
|
1043
1072
|
logger.info(f" Level 3: {stats.get('level_3_count', 0)} uses")
|
|
1044
1073
|
logger.info(f" Level 4: {stats.get('level_4_count', 0)} uses")
|
|
1045
1074
|
logger.info(f" Level 5: {stats.get('level_5_count', 0)} uses")
|
|
1075
|
+
except (OSError, FileNotFoundError) as e:
|
|
1076
|
+
# Database file not found
|
|
1077
|
+
logger.error(f"Metrics database error: {e}")
|
|
1078
|
+
logger.error(f"✗ Cannot read metrics database: {e}")
|
|
1079
|
+
sys.exit(1)
|
|
1080
|
+
except KeyError as e:
|
|
1081
|
+
# User not found in database
|
|
1082
|
+
logger.error(f"User not found in metrics: {e}")
|
|
1083
|
+
logger.error(f"✗ User {user_id} not found: {e}")
|
|
1084
|
+
sys.exit(1)
|
|
1046
1085
|
except Exception as e:
|
|
1047
|
-
|
|
1086
|
+
# Unexpected errors retrieving metrics
|
|
1087
|
+
logger.exception(f"Unexpected error retrieving metrics for user {user_id}: {e}")
|
|
1048
1088
|
logger.error(f"✗ Failed to retrieve metrics: {e}")
|
|
1049
1089
|
sys.exit(1)
|
|
1050
1090
|
|
|
@@ -1098,7 +1138,17 @@ def cmd_run(args):
|
|
|
1098
1138
|
persistence_enabled=config.persistence_enabled,
|
|
1099
1139
|
)
|
|
1100
1140
|
print("✓ Empathy OS initialized")
|
|
1141
|
+
except ValueError as e:
|
|
1142
|
+
# Invalid configuration parameters
|
|
1143
|
+
print(f"✗ Configuration error: {e}")
|
|
1144
|
+
sys.exit(1)
|
|
1145
|
+
except (OSError, FileNotFoundError, PermissionError) as e:
|
|
1146
|
+
# Cannot access required files/directories
|
|
1147
|
+
print(f"✗ File system error: {e}")
|
|
1148
|
+
sys.exit(1)
|
|
1101
1149
|
except Exception as e:
|
|
1150
|
+
# Unexpected initialization failure
|
|
1151
|
+
logger.exception(f"Unexpected error initializing Empathy OS: {e}")
|
|
1102
1152
|
print(f"✗ Failed to initialize Empathy OS: {e}")
|
|
1103
1153
|
sys.exit(1)
|
|
1104
1154
|
|
|
@@ -1182,7 +1232,12 @@ def cmd_run(args):
|
|
|
1182
1232
|
except KeyboardInterrupt:
|
|
1183
1233
|
print("\n\n👋 Goodbye!")
|
|
1184
1234
|
break
|
|
1235
|
+
except (ValueError, KeyError) as e:
|
|
1236
|
+
# Invalid input or response structure
|
|
1237
|
+
print(f"\n✗ Input error: {e}\n")
|
|
1185
1238
|
except Exception as e:
|
|
1239
|
+
# Unexpected errors in interactive loop - log and continue
|
|
1240
|
+
logger.exception(f"Unexpected error in interactive loop: {e}")
|
|
1186
1241
|
print(f"\n✗ Error: {e}\n")
|
|
1187
1242
|
|
|
1188
1243
|
|
|
@@ -1225,7 +1280,13 @@ def cmd_inspect(args):
|
|
|
1225
1280
|
print(f"✗ Pattern library not found: {db_path}")
|
|
1226
1281
|
print(" Tip: Use 'empathy-framework wizard' to set up your first project")
|
|
1227
1282
|
sys.exit(1)
|
|
1283
|
+
except (ValueError, KeyError) as e:
|
|
1284
|
+
# Invalid pattern data format
|
|
1285
|
+
print(f"✗ Invalid pattern data: {e}")
|
|
1286
|
+
sys.exit(1)
|
|
1228
1287
|
except Exception as e:
|
|
1288
|
+
# Unexpected errors loading patterns
|
|
1289
|
+
logger.exception(f"Unexpected error loading patterns: {e}")
|
|
1229
1290
|
print(f"✗ Failed to load patterns: {e}")
|
|
1230
1291
|
sys.exit(1)
|
|
1231
1292
|
|
|
@@ -1247,7 +1308,17 @@ def cmd_inspect(args):
|
|
|
1247
1308
|
for level in range(1, 6):
|
|
1248
1309
|
count = stats.get(f"level_{level}_count", 0)
|
|
1249
1310
|
print(f" Level {level}: {count} times")
|
|
1311
|
+
except (OSError, FileNotFoundError) as e:
|
|
1312
|
+
# Database file not found
|
|
1313
|
+
print(f"✗ Metrics database not found: {e}")
|
|
1314
|
+
sys.exit(1)
|
|
1315
|
+
except KeyError as e:
|
|
1316
|
+
# User not found
|
|
1317
|
+
print(f"✗ User {user_id} not found: {e}")
|
|
1318
|
+
sys.exit(1)
|
|
1250
1319
|
except Exception as e:
|
|
1320
|
+
# Unexpected errors loading metrics
|
|
1321
|
+
logger.exception(f"Unexpected error loading metrics: {e}")
|
|
1251
1322
|
print(f"✗ Failed to load metrics: {e}")
|
|
1252
1323
|
sys.exit(1)
|
|
1253
1324
|
|
|
@@ -1264,7 +1335,13 @@ def cmd_inspect(args):
|
|
|
1264
1335
|
print("\n Users:")
|
|
1265
1336
|
for uid in users:
|
|
1266
1337
|
print(f" • {uid}")
|
|
1338
|
+
except (OSError, FileNotFoundError) as e:
|
|
1339
|
+
# State directory not found
|
|
1340
|
+
print(f"✗ State directory not found: {e}")
|
|
1341
|
+
sys.exit(1)
|
|
1267
1342
|
except Exception as e:
|
|
1343
|
+
# Unexpected errors loading state
|
|
1344
|
+
logger.exception(f"Unexpected error loading state: {e}")
|
|
1268
1345
|
print(f"✗ Failed to load state: {e}")
|
|
1269
1346
|
sys.exit(1)
|
|
1270
1347
|
|
|
@@ -1316,7 +1393,17 @@ def cmd_export(args):
|
|
|
1316
1393
|
print(f"✗ Source file not found: {db_path}")
|
|
1317
1394
|
print(" Tip: Patterns are saved automatically when using the framework")
|
|
1318
1395
|
sys.exit(1)
|
|
1396
|
+
except (OSError, PermissionError) as e:
|
|
1397
|
+
# Cannot write output file
|
|
1398
|
+
print(f"✗ Cannot write to file: {e}")
|
|
1399
|
+
sys.exit(1)
|
|
1400
|
+
except (ValueError, KeyError) as e:
|
|
1401
|
+
# Invalid pattern data
|
|
1402
|
+
print(f"✗ Invalid pattern data: {e}")
|
|
1403
|
+
sys.exit(1)
|
|
1319
1404
|
except Exception as e:
|
|
1405
|
+
# Unexpected errors during export
|
|
1406
|
+
logger.exception(f"Unexpected error exporting patterns: {e}")
|
|
1320
1407
|
print(f"✗ Export failed: {e}")
|
|
1321
1408
|
sys.exit(1)
|
|
1322
1409
|
|
|
@@ -1369,7 +1456,17 @@ def cmd_import(args):
|
|
|
1369
1456
|
except FileNotFoundError:
|
|
1370
1457
|
print(f"✗ Input file not found: {input_file}")
|
|
1371
1458
|
sys.exit(1)
|
|
1459
|
+
except (ValueError, KeyError) as e:
|
|
1460
|
+
# Invalid pattern data format
|
|
1461
|
+
print(f"✗ Invalid pattern data: {e}")
|
|
1462
|
+
sys.exit(1)
|
|
1463
|
+
except (OSError, PermissionError) as e:
|
|
1464
|
+
# Cannot read input or write to database
|
|
1465
|
+
print(f"✗ File access error: {e}")
|
|
1466
|
+
sys.exit(1)
|
|
1372
1467
|
except Exception as e:
|
|
1468
|
+
# Unexpected errors during import
|
|
1469
|
+
logger.exception(f"Unexpected error importing patterns: {e}")
|
|
1373
1470
|
print(f"✗ Import failed: {e}")
|
|
1374
1471
|
sys.exit(1)
|
|
1375
1472
|
|
|
@@ -1413,13 +1510,29 @@ def cmd_wizard(args):
|
|
|
1413
1510
|
print("\n3. Which LLM provider will you use?")
|
|
1414
1511
|
print(" [1] Anthropic Claude ⭐ Recommended")
|
|
1415
1512
|
print(" [2] OpenAI GPT-4")
|
|
1416
|
-
print(" [3]
|
|
1417
|
-
print(" [4]
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1513
|
+
print(" [3] Google Gemini (2M context)")
|
|
1514
|
+
print(" [4] Local (Ollama)")
|
|
1515
|
+
print(" [5] Hybrid (mix best models from each provider)")
|
|
1516
|
+
print(" [6] Skip (configure later)")
|
|
1517
|
+
|
|
1518
|
+
llm_choice = input("\nYour choice (1-6) [1]: ").strip() or "1"
|
|
1519
|
+
llm_map = {
|
|
1520
|
+
"1": "anthropic",
|
|
1521
|
+
"2": "openai",
|
|
1522
|
+
"3": "google",
|
|
1523
|
+
"4": "ollama",
|
|
1524
|
+
"5": "hybrid",
|
|
1525
|
+
"6": None,
|
|
1526
|
+
}
|
|
1421
1527
|
llm_provider = llm_map.get(llm_choice, "anthropic")
|
|
1422
1528
|
|
|
1529
|
+
# If hybrid selected, launch interactive tier selection
|
|
1530
|
+
if llm_provider == "hybrid":
|
|
1531
|
+
from empathy_os.models.provider_config import configure_hybrid_interactive
|
|
1532
|
+
|
|
1533
|
+
configure_hybrid_interactive()
|
|
1534
|
+
llm_provider = None # Already saved by hybrid config
|
|
1535
|
+
|
|
1423
1536
|
# Step 4: User ID
|
|
1424
1537
|
print("\n4. What user ID should we use?")
|
|
1425
1538
|
user_id = input("User ID [default_user]: ").strip() or "default_user"
|
|
@@ -1480,14 +1593,94 @@ llm_provider: "{llm_provider}"
|
|
|
1480
1593
|
print("\nNext steps:")
|
|
1481
1594
|
print(f" 1. Edit {output_file} to customize settings")
|
|
1482
1595
|
|
|
1483
|
-
if llm_provider in ["anthropic", "openai"]:
|
|
1484
|
-
|
|
1596
|
+
if llm_provider in ["anthropic", "openai", "google"]:
|
|
1597
|
+
env_var_map = {
|
|
1598
|
+
"anthropic": "ANTHROPIC_API_KEY",
|
|
1599
|
+
"openai": "OPENAI_API_KEY",
|
|
1600
|
+
"google": "GOOGLE_API_KEY",
|
|
1601
|
+
}
|
|
1602
|
+
env_var = env_var_map.get(llm_provider, "API_KEY")
|
|
1485
1603
|
print(f" 2. Set {env_var} environment variable")
|
|
1486
1604
|
|
|
1487
1605
|
print(" 3. Run: empathy-framework run --config empathy.config.yml")
|
|
1488
1606
|
print("\nHappy empathizing! 🧠✨\n")
|
|
1489
1607
|
|
|
1490
1608
|
|
|
1609
|
+
def cmd_provider_hybrid(args):
|
|
1610
|
+
"""Configure hybrid mode - pick best models for each tier."""
|
|
1611
|
+
from empathy_os.models.provider_config import configure_hybrid_interactive
|
|
1612
|
+
|
|
1613
|
+
configure_hybrid_interactive()
|
|
1614
|
+
|
|
1615
|
+
|
|
1616
|
+
def cmd_provider_show(args):
|
|
1617
|
+
"""Show current provider configuration."""
|
|
1618
|
+
from empathy_os.models.provider_config import ProviderConfig
|
|
1619
|
+
from empathy_os.workflows.config import WorkflowConfig
|
|
1620
|
+
|
|
1621
|
+
print("\n" + "=" * 60)
|
|
1622
|
+
print("Provider Configuration")
|
|
1623
|
+
print("=" * 60)
|
|
1624
|
+
|
|
1625
|
+
# Detect available providers
|
|
1626
|
+
config = ProviderConfig.auto_detect()
|
|
1627
|
+
print(
|
|
1628
|
+
f"\nDetected API keys for: {', '.join(config.available_providers) if config.available_providers else 'None'}",
|
|
1629
|
+
)
|
|
1630
|
+
|
|
1631
|
+
# Load workflow config
|
|
1632
|
+
wf_config = WorkflowConfig.load()
|
|
1633
|
+
print(f"\nDefault provider: {wf_config.default_provider}")
|
|
1634
|
+
|
|
1635
|
+
# Show effective models
|
|
1636
|
+
print("\nEffective model mapping:")
|
|
1637
|
+
if wf_config.custom_models and "hybrid" in wf_config.custom_models:
|
|
1638
|
+
hybrid = wf_config.custom_models["hybrid"]
|
|
1639
|
+
for tier in ["cheap", "capable", "premium"]:
|
|
1640
|
+
model = hybrid.get(tier, "not configured")
|
|
1641
|
+
print(f" {tier:8} → {model}")
|
|
1642
|
+
else:
|
|
1643
|
+
from empathy_os.models import MODEL_REGISTRY
|
|
1644
|
+
|
|
1645
|
+
provider = wf_config.default_provider
|
|
1646
|
+
if provider in MODEL_REGISTRY:
|
|
1647
|
+
for tier in ["cheap", "capable", "premium"]:
|
|
1648
|
+
model_info = MODEL_REGISTRY[provider].get(tier)
|
|
1649
|
+
if model_info:
|
|
1650
|
+
print(f" {tier:8} → {model_info.id} ({provider})")
|
|
1651
|
+
|
|
1652
|
+
print()
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
def cmd_provider_set(args):
|
|
1656
|
+
"""Set default provider."""
|
|
1657
|
+
from pathlib import Path
|
|
1658
|
+
|
|
1659
|
+
import yaml
|
|
1660
|
+
|
|
1661
|
+
provider = args.name
|
|
1662
|
+
workflows_path = Path(".empathy/workflows.yaml")
|
|
1663
|
+
|
|
1664
|
+
# Load existing config or create new
|
|
1665
|
+
if workflows_path.exists():
|
|
1666
|
+
with open(workflows_path) as f:
|
|
1667
|
+
config = yaml.safe_load(f) or {}
|
|
1668
|
+
else:
|
|
1669
|
+
config = {}
|
|
1670
|
+
workflows_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1671
|
+
|
|
1672
|
+
config["default_provider"] = provider
|
|
1673
|
+
|
|
1674
|
+
with open(workflows_path, "w") as f:
|
|
1675
|
+
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
1676
|
+
|
|
1677
|
+
print(f"✓ Default provider set to: {provider}")
|
|
1678
|
+
print(f" Saved to: {workflows_path}")
|
|
1679
|
+
|
|
1680
|
+
if provider == "hybrid":
|
|
1681
|
+
print("\n Tip: Run 'empathy provider hybrid' to customize tier models")
|
|
1682
|
+
|
|
1683
|
+
|
|
1491
1684
|
def cmd_sync_claude(args):
|
|
1492
1685
|
"""Sync patterns to Claude Code rules directory."""
|
|
1493
1686
|
import json as json_mod
|
|
@@ -1569,7 +1762,7 @@ def _generate_claude_rule(category: str, patterns: list) -> str:
|
|
|
1569
1762
|
"",
|
|
1570
1763
|
"When debugging similar issues, consider these historical fixes:",
|
|
1571
1764
|
"",
|
|
1572
|
-
]
|
|
1765
|
+
],
|
|
1573
1766
|
)
|
|
1574
1767
|
for p in patterns[:20]: # Limit to 20 most recent
|
|
1575
1768
|
bug_type = p.get("bug_type", "unknown")
|
|
@@ -1591,7 +1784,7 @@ def _generate_claude_rule(category: str, patterns: list) -> str:
|
|
|
1591
1784
|
"",
|
|
1592
1785
|
"Previously reviewed security items:",
|
|
1593
1786
|
"",
|
|
1594
|
-
]
|
|
1787
|
+
],
|
|
1595
1788
|
)
|
|
1596
1789
|
for p in patterns[:20]:
|
|
1597
1790
|
decision = p.get("decision", "unknown")
|
|
@@ -1608,7 +1801,7 @@ def _generate_claude_rule(category: str, patterns: list) -> str:
|
|
|
1608
1801
|
"",
|
|
1609
1802
|
"Known technical debt items:",
|
|
1610
1803
|
"",
|
|
1611
|
-
]
|
|
1804
|
+
],
|
|
1612
1805
|
)
|
|
1613
1806
|
for p in patterns[:20]:
|
|
1614
1807
|
lines.append(f"- {p.get('description', str(p))}")
|
|
@@ -1618,7 +1811,7 @@ def _generate_claude_rule(category: str, patterns: list) -> str:
|
|
|
1618
1811
|
[
|
|
1619
1812
|
f"## {category.title()} Items",
|
|
1620
1813
|
"",
|
|
1621
|
-
]
|
|
1814
|
+
],
|
|
1622
1815
|
)
|
|
1623
1816
|
for p in patterns[:20]:
|
|
1624
1817
|
lines.append(f"- {p.get('description', str(p)[:100])}")
|
|
@@ -1627,8 +1820,7 @@ def _generate_claude_rule(category: str, patterns: list) -> str:
|
|
|
1627
1820
|
|
|
1628
1821
|
|
|
1629
1822
|
def _extract_workflow_content(final_output):
|
|
1630
|
-
"""
|
|
1631
|
-
Extract readable content from workflow final_output.
|
|
1823
|
+
"""Extract readable content from workflow final_output.
|
|
1632
1824
|
|
|
1633
1825
|
Workflows return their results in various formats - this extracts
|
|
1634
1826
|
the actual content users want to see.
|
|
@@ -1643,7 +1835,9 @@ def _extract_workflow_content(final_output):
|
|
|
1643
1835
|
# If it's a dict, try to extract meaningful content
|
|
1644
1836
|
if isinstance(final_output, dict):
|
|
1645
1837
|
# Common keys that contain the main output
|
|
1838
|
+
# formatted_report is first - preferred for security-audit and other formatted outputs
|
|
1646
1839
|
content_keys = [
|
|
1840
|
+
"formatted_report", # Human-readable formatted output (security-audit, etc.)
|
|
1647
1841
|
"answer",
|
|
1648
1842
|
"synthesis",
|
|
1649
1843
|
"result",
|
|
@@ -1661,11 +1855,11 @@ def _extract_workflow_content(final_output):
|
|
|
1661
1855
|
"plan",
|
|
1662
1856
|
]
|
|
1663
1857
|
for key in content_keys:
|
|
1664
|
-
if
|
|
1858
|
+
if final_output.get(key):
|
|
1665
1859
|
val = final_output[key]
|
|
1666
1860
|
if isinstance(val, str):
|
|
1667
1861
|
return val
|
|
1668
|
-
|
|
1862
|
+
if isinstance(val, dict):
|
|
1669
1863
|
# Recursively extract
|
|
1670
1864
|
return _extract_workflow_content(val)
|
|
1671
1865
|
|
|
@@ -1761,8 +1955,14 @@ def cmd_workflow(args):
|
|
|
1761
1955
|
try:
|
|
1762
1956
|
workflow_cls = get_workflow(name)
|
|
1763
1957
|
|
|
1764
|
-
# Get provider
|
|
1765
|
-
|
|
1958
|
+
# Get provider from CLI arg, or fall back to config's default_provider
|
|
1959
|
+
if args.provider:
|
|
1960
|
+
provider = args.provider
|
|
1961
|
+
else:
|
|
1962
|
+
from empathy_os.workflows.config import WorkflowConfig
|
|
1963
|
+
|
|
1964
|
+
wf_config = WorkflowConfig.load()
|
|
1965
|
+
provider = wf_config.default_provider
|
|
1766
1966
|
workflow = workflow_cls(provider=provider)
|
|
1767
1967
|
|
|
1768
1968
|
# Parse input
|
|
@@ -1770,8 +1970,17 @@ def cmd_workflow(args):
|
|
|
1770
1970
|
if args.input:
|
|
1771
1971
|
input_data = json_mod.loads(args.input)
|
|
1772
1972
|
|
|
1773
|
-
|
|
1774
|
-
|
|
1973
|
+
# Add test-gen specific flags to input_data (only for test-gen workflow)
|
|
1974
|
+
if name == "test-gen":
|
|
1975
|
+
if getattr(args, "write_tests", False):
|
|
1976
|
+
input_data["write_tests"] = True
|
|
1977
|
+
if getattr(args, "output_dir", None):
|
|
1978
|
+
input_data["output_dir"] = args.output_dir
|
|
1979
|
+
|
|
1980
|
+
# Only print header when not in JSON mode
|
|
1981
|
+
if not args.json:
|
|
1982
|
+
print(f"\n Running workflow: {name} (provider: {provider})")
|
|
1983
|
+
print("=" * 50)
|
|
1775
1984
|
|
|
1776
1985
|
# Execute workflow
|
|
1777
1986
|
result = asyncio.run(workflow.execute(**input_data))
|
|
@@ -1779,6 +1988,11 @@ def cmd_workflow(args):
|
|
|
1779
1988
|
# Extract the actual content - handle different result types
|
|
1780
1989
|
if hasattr(result, "final_output"):
|
|
1781
1990
|
output_content = _extract_workflow_content(result.final_output)
|
|
1991
|
+
elif hasattr(result, "metadata") and isinstance(result.metadata, dict):
|
|
1992
|
+
# Check for formatted_report in metadata (e.g., HealthCheckResult)
|
|
1993
|
+
output_content = result.metadata.get("formatted_report")
|
|
1994
|
+
if not output_content and hasattr(result, "summary"):
|
|
1995
|
+
output_content = result.summary
|
|
1782
1996
|
elif hasattr(result, "summary"):
|
|
1783
1997
|
output_content = result.summary
|
|
1784
1998
|
else:
|
|
@@ -1789,37 +2003,81 @@ def cmd_workflow(args):
|
|
|
1789
2003
|
if duration_ms is None and hasattr(result, "duration_seconds"):
|
|
1790
2004
|
duration_ms = int(result.duration_seconds * 1000)
|
|
1791
2005
|
|
|
1792
|
-
# Get cost info if available
|
|
2006
|
+
# Get cost info if available (check cost_report first, then direct cost attribute)
|
|
1793
2007
|
cost_report = getattr(result, "cost_report", None)
|
|
1794
|
-
|
|
1795
|
-
|
|
2008
|
+
if cost_report and hasattr(cost_report, "total_cost"):
|
|
2009
|
+
total_cost = cost_report.total_cost
|
|
2010
|
+
savings = getattr(cost_report, "savings", 0.0)
|
|
2011
|
+
else:
|
|
2012
|
+
# Fall back to direct cost attribute (e.g., CodeReviewPipelineResult)
|
|
2013
|
+
total_cost = getattr(result, "cost", 0.0)
|
|
2014
|
+
savings = 0.0
|
|
1796
2015
|
|
|
1797
2016
|
if args.json:
|
|
2017
|
+
# Extract error from various result types
|
|
2018
|
+
error = getattr(result, "error", None)
|
|
2019
|
+
if not error and not result.success:
|
|
2020
|
+
blockers = getattr(result, "blockers", [])
|
|
2021
|
+
if blockers:
|
|
2022
|
+
error = "; ".join(blockers)
|
|
2023
|
+
else:
|
|
2024
|
+
metadata = getattr(result, "metadata", {})
|
|
2025
|
+
error = metadata.get("error") if isinstance(metadata, dict) else None
|
|
2026
|
+
|
|
1798
2027
|
# JSON output includes both content and metadata
|
|
2028
|
+
# Include final_output for programmatic access (VSCode panels, etc.)
|
|
2029
|
+
raw_final_output = getattr(result, "final_output", None)
|
|
2030
|
+
if raw_final_output and isinstance(raw_final_output, dict):
|
|
2031
|
+
# Make a copy to avoid modifying the original
|
|
2032
|
+
final_output_serializable = {}
|
|
2033
|
+
for k, v in raw_final_output.items():
|
|
2034
|
+
# Skip non-serializable items
|
|
2035
|
+
if isinstance(v, set):
|
|
2036
|
+
final_output_serializable[k] = list(v)
|
|
2037
|
+
elif v is None or isinstance(v, str | int | float | bool | list | dict):
|
|
2038
|
+
final_output_serializable[k] = v
|
|
2039
|
+
else:
|
|
2040
|
+
try:
|
|
2041
|
+
final_output_serializable[k] = str(v)
|
|
2042
|
+
except Exception as e: # noqa: BLE001
|
|
2043
|
+
# INTENTIONAL: Silently skip any non-serializable objects
|
|
2044
|
+
# This is a best-effort serialization for JSON output
|
|
2045
|
+
# We cannot predict all possible object types users might return
|
|
2046
|
+
logger.debug(f"Cannot serialize field {k}: {e}")
|
|
2047
|
+
pass
|
|
2048
|
+
else:
|
|
2049
|
+
final_output_serializable = None
|
|
2050
|
+
|
|
1799
2051
|
output = {
|
|
1800
2052
|
"success": result.success,
|
|
1801
2053
|
"output": output_content,
|
|
2054
|
+
"final_output": final_output_serializable,
|
|
1802
2055
|
"cost": total_cost,
|
|
1803
2056
|
"savings": savings,
|
|
1804
2057
|
"duration_ms": duration_ms or 0,
|
|
1805
|
-
"error":
|
|
2058
|
+
"error": error,
|
|
1806
2059
|
}
|
|
1807
2060
|
print(json_mod.dumps(output, indent=2))
|
|
2061
|
+
# Display the actual results - this is what users want to see
|
|
2062
|
+
elif result.success:
|
|
2063
|
+
if output_content:
|
|
2064
|
+
print(f"\n{output_content}\n")
|
|
2065
|
+
else:
|
|
2066
|
+
print("\n✓ Workflow completed successfully.\n")
|
|
1808
2067
|
else:
|
|
1809
|
-
#
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2068
|
+
# Extract error from various result types
|
|
2069
|
+
error_msg = getattr(result, "error", None)
|
|
2070
|
+
if not error_msg:
|
|
2071
|
+
# Check for blockers (CodeReviewPipelineResult)
|
|
2072
|
+
blockers = getattr(result, "blockers", [])
|
|
2073
|
+
if blockers:
|
|
2074
|
+
error_msg = "; ".join(blockers)
|
|
1813
2075
|
else:
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
print(f"Completed in {ms}ms | Cost: ${total_cost:.4f} (saved ${savings:.4f})")
|
|
1820
|
-
else:
|
|
1821
|
-
error_msg = getattr(result, "error", None) or "Unknown error"
|
|
1822
|
-
print(f"\n✗ Workflow failed: {error_msg}\n")
|
|
2076
|
+
# Check metadata for error
|
|
2077
|
+
metadata = getattr(result, "metadata", {})
|
|
2078
|
+
error_msg = metadata.get("error") if isinstance(metadata, dict) else None
|
|
2079
|
+
error_msg = error_msg or "Unknown error"
|
|
2080
|
+
print(f"\n✗ Workflow failed: {error_msg}\n")
|
|
1823
2081
|
|
|
1824
2082
|
except KeyError as e:
|
|
1825
2083
|
print(f"Error: {e}")
|
|
@@ -1898,7 +2156,7 @@ def cmd_frameworks(args):
|
|
|
1898
2156
|
json_mod.dumps(
|
|
1899
2157
|
{"use_case": recommend_use_case, "recommended": recommended.value, **info},
|
|
1900
2158
|
indent=2,
|
|
1901
|
-
)
|
|
2159
|
+
),
|
|
1902
2160
|
)
|
|
1903
2161
|
else:
|
|
1904
2162
|
print(f"\nRecommended framework for '{recommend_use_case}': {info['name']}")
|
|
@@ -1925,7 +2183,7 @@ def cmd_frameworks(args):
|
|
|
1925
2183
|
for f in frameworks
|
|
1926
2184
|
],
|
|
1927
2185
|
indent=2,
|
|
1928
|
-
)
|
|
2186
|
+
),
|
|
1929
2187
|
)
|
|
1930
2188
|
else:
|
|
1931
2189
|
print("\n" + "=" * 60)
|
|
@@ -1950,6 +2208,9 @@ def cmd_frameworks(args):
|
|
|
1950
2208
|
|
|
1951
2209
|
def main():
|
|
1952
2210
|
"""Main CLI entry point"""
|
|
2211
|
+
# Configure Windows-compatible asyncio event loop policy
|
|
2212
|
+
setup_asyncio_policy()
|
|
2213
|
+
|
|
1953
2214
|
parser = argparse.ArgumentParser(
|
|
1954
2215
|
prog="empathy",
|
|
1955
2216
|
description="Empathy - Build AI systems with 5 levels of empathy",
|
|
@@ -2002,32 +2263,45 @@ def main():
|
|
|
2002
2263
|
parser_patterns_export.add_argument("input", help="Input file path")
|
|
2003
2264
|
parser_patterns_export.add_argument("output", help="Output file path")
|
|
2004
2265
|
parser_patterns_export.add_argument(
|
|
2005
|
-
"--input-format",
|
|
2266
|
+
"--input-format",
|
|
2267
|
+
choices=["json", "sqlite"],
|
|
2268
|
+
default="json",
|
|
2006
2269
|
)
|
|
2007
2270
|
parser_patterns_export.add_argument(
|
|
2008
|
-
"--output-format",
|
|
2271
|
+
"--output-format",
|
|
2272
|
+
choices=["json", "sqlite"],
|
|
2273
|
+
default="json",
|
|
2009
2274
|
)
|
|
2010
2275
|
parser_patterns_export.set_defaults(func=cmd_patterns_export)
|
|
2011
2276
|
|
|
2012
2277
|
# Patterns resolve - mark investigating bugs as resolved
|
|
2013
2278
|
parser_patterns_resolve = patterns_subparsers.add_parser(
|
|
2014
|
-
"resolve",
|
|
2279
|
+
"resolve",
|
|
2280
|
+
help="Resolve investigating bug patterns",
|
|
2015
2281
|
)
|
|
2016
2282
|
parser_patterns_resolve.add_argument(
|
|
2017
|
-
"bug_id",
|
|
2283
|
+
"bug_id",
|
|
2284
|
+
nargs="?",
|
|
2285
|
+
help="Bug ID to resolve (omit to list investigating)",
|
|
2018
2286
|
)
|
|
2019
2287
|
parser_patterns_resolve.add_argument("--root-cause", help="Description of the root cause")
|
|
2020
2288
|
parser_patterns_resolve.add_argument("--fix", help="Description of the fix applied")
|
|
2021
2289
|
parser_patterns_resolve.add_argument("--fix-code", help="Code snippet of the fix")
|
|
2022
2290
|
parser_patterns_resolve.add_argument("--time", type=int, help="Resolution time in minutes")
|
|
2023
2291
|
parser_patterns_resolve.add_argument(
|
|
2024
|
-
"--resolved-by",
|
|
2292
|
+
"--resolved-by",
|
|
2293
|
+
default="@developer",
|
|
2294
|
+
help="Who resolved it",
|
|
2025
2295
|
)
|
|
2026
2296
|
parser_patterns_resolve.add_argument(
|
|
2027
|
-
"--patterns-dir",
|
|
2297
|
+
"--patterns-dir",
|
|
2298
|
+
default="./patterns",
|
|
2299
|
+
help="Path to patterns directory",
|
|
2028
2300
|
)
|
|
2029
2301
|
parser_patterns_resolve.add_argument(
|
|
2030
|
-
"--no-regenerate",
|
|
2302
|
+
"--no-regenerate",
|
|
2303
|
+
action="store_true",
|
|
2304
|
+
help="Skip regenerating summary",
|
|
2031
2305
|
)
|
|
2032
2306
|
parser_patterns_resolve.set_defaults(func=cmd_patterns_resolve)
|
|
2033
2307
|
|
|
@@ -2048,7 +2322,9 @@ def main():
|
|
|
2048
2322
|
# State list
|
|
2049
2323
|
parser_state_list = state_subparsers.add_parser("list", help="List saved states")
|
|
2050
2324
|
parser_state_list.add_argument(
|
|
2051
|
-
"--state-dir",
|
|
2325
|
+
"--state-dir",
|
|
2326
|
+
default="./empathy_state",
|
|
2327
|
+
help="State directory path",
|
|
2052
2328
|
)
|
|
2053
2329
|
parser_state_list.set_defaults(func=cmd_state_list)
|
|
2054
2330
|
|
|
@@ -2057,7 +2333,10 @@ def main():
|
|
|
2057
2333
|
parser_run.add_argument("--config", "-c", help="Configuration file path")
|
|
2058
2334
|
parser_run.add_argument("--user-id", help="User ID (default: cli_user)")
|
|
2059
2335
|
parser_run.add_argument(
|
|
2060
|
-
"--level",
|
|
2336
|
+
"--level",
|
|
2337
|
+
type=int,
|
|
2338
|
+
default=4,
|
|
2339
|
+
help="Target empathy level (1-5, default: 4)",
|
|
2061
2340
|
)
|
|
2062
2341
|
parser_run.set_defaults(func=cmd_run)
|
|
2063
2342
|
|
|
@@ -2071,21 +2350,27 @@ def main():
|
|
|
2071
2350
|
parser_inspect.add_argument("--user-id", help="User ID to filter by (optional)")
|
|
2072
2351
|
parser_inspect.add_argument("--db", help="Database path (default: .empathy/patterns.db)")
|
|
2073
2352
|
parser_inspect.add_argument(
|
|
2074
|
-
"--state-dir",
|
|
2353
|
+
"--state-dir",
|
|
2354
|
+
help="State directory path (default: .empathy/state)",
|
|
2075
2355
|
)
|
|
2076
2356
|
parser_inspect.set_defaults(func=cmd_inspect)
|
|
2077
2357
|
|
|
2078
2358
|
# Export command
|
|
2079
2359
|
parser_export = subparsers.add_parser(
|
|
2080
|
-
"export",
|
|
2360
|
+
"export",
|
|
2361
|
+
help="Export patterns to file for sharing/backup",
|
|
2081
2362
|
)
|
|
2082
2363
|
parser_export.add_argument("output", help="Output file path")
|
|
2083
2364
|
parser_export.add_argument(
|
|
2084
|
-
"--user-id",
|
|
2365
|
+
"--user-id",
|
|
2366
|
+
help="User ID to export (optional, exports all if not specified)",
|
|
2085
2367
|
)
|
|
2086
2368
|
parser_export.add_argument("--db", help="Database path (default: .empathy/patterns.db)")
|
|
2087
2369
|
parser_export.add_argument(
|
|
2088
|
-
"--format",
|
|
2370
|
+
"--format",
|
|
2371
|
+
default="json",
|
|
2372
|
+
choices=["json"],
|
|
2373
|
+
help="Export format (default: json)",
|
|
2089
2374
|
)
|
|
2090
2375
|
parser_export.set_defaults(func=cmd_export)
|
|
2091
2376
|
|
|
@@ -2097,20 +2382,59 @@ def main():
|
|
|
2097
2382
|
|
|
2098
2383
|
# Wizard command (Interactive setup)
|
|
2099
2384
|
parser_wizard = subparsers.add_parser(
|
|
2100
|
-
"wizard",
|
|
2385
|
+
"wizard",
|
|
2386
|
+
help="Interactive setup wizard for creating configuration",
|
|
2101
2387
|
)
|
|
2102
2388
|
parser_wizard.set_defaults(func=cmd_wizard)
|
|
2103
2389
|
|
|
2390
|
+
# Provider command (Model provider configuration)
|
|
2391
|
+
parser_provider = subparsers.add_parser(
|
|
2392
|
+
"provider",
|
|
2393
|
+
help="Configure model providers and hybrid mode",
|
|
2394
|
+
)
|
|
2395
|
+
provider_subparsers = parser_provider.add_subparsers(dest="provider_cmd")
|
|
2396
|
+
|
|
2397
|
+
# provider hybrid - Interactive hybrid configuration
|
|
2398
|
+
parser_provider_hybrid = provider_subparsers.add_parser(
|
|
2399
|
+
"hybrid",
|
|
2400
|
+
help="Configure hybrid mode - pick best models for each tier",
|
|
2401
|
+
)
|
|
2402
|
+
parser_provider_hybrid.set_defaults(func=cmd_provider_hybrid)
|
|
2403
|
+
|
|
2404
|
+
# provider show - Show current configuration
|
|
2405
|
+
parser_provider_show = provider_subparsers.add_parser(
|
|
2406
|
+
"show",
|
|
2407
|
+
help="Show current provider configuration",
|
|
2408
|
+
)
|
|
2409
|
+
parser_provider_show.set_defaults(func=cmd_provider_show)
|
|
2410
|
+
|
|
2411
|
+
# provider set - Quick set single provider
|
|
2412
|
+
parser_provider_set = provider_subparsers.add_parser(
|
|
2413
|
+
"set",
|
|
2414
|
+
help="Set default provider (anthropic, openai, google, ollama)",
|
|
2415
|
+
)
|
|
2416
|
+
parser_provider_set.add_argument(
|
|
2417
|
+
"name",
|
|
2418
|
+
choices=["anthropic", "openai", "google", "ollama", "hybrid"],
|
|
2419
|
+
help="Provider name",
|
|
2420
|
+
)
|
|
2421
|
+
parser_provider_set.set_defaults(func=cmd_provider_set)
|
|
2422
|
+
|
|
2104
2423
|
# Status command (Session status assistant)
|
|
2105
2424
|
parser_status = subparsers.add_parser(
|
|
2106
|
-
"status",
|
|
2425
|
+
"status",
|
|
2426
|
+
help="Session status - prioritized project status report",
|
|
2107
2427
|
)
|
|
2108
2428
|
parser_status.add_argument(
|
|
2109
|
-
"--patterns-dir",
|
|
2429
|
+
"--patterns-dir",
|
|
2430
|
+
default="./patterns",
|
|
2431
|
+
help="Path to patterns directory",
|
|
2110
2432
|
)
|
|
2111
2433
|
parser_status.add_argument("--project-root", default=".", help="Project root directory")
|
|
2112
2434
|
parser_status.add_argument(
|
|
2113
|
-
"--force",
|
|
2435
|
+
"--force",
|
|
2436
|
+
action="store_true",
|
|
2437
|
+
help="Force show status regardless of inactivity",
|
|
2114
2438
|
)
|
|
2115
2439
|
parser_status.add_argument("--full", action="store_true", help="Show all items (no limit)")
|
|
2116
2440
|
parser_status.add_argument("--json", action="store_true", help="Output as JSON")
|
|
@@ -2125,7 +2449,8 @@ def main():
|
|
|
2125
2449
|
|
|
2126
2450
|
# Review command (Pattern-based code review)
|
|
2127
2451
|
parser_review = subparsers.add_parser(
|
|
2128
|
-
"review",
|
|
2452
|
+
"review",
|
|
2453
|
+
help="Pattern-based code review against historical bugs",
|
|
2129
2454
|
)
|
|
2130
2455
|
parser_review.add_argument("files", nargs="*", help="Files to review (default: recent changes)")
|
|
2131
2456
|
parser_review.add_argument("--staged", action="store_true", help="Review staged changes only")
|
|
@@ -2141,10 +2466,13 @@ def main():
|
|
|
2141
2466
|
|
|
2142
2467
|
# Health command (Code Health Assistant)
|
|
2143
2468
|
parser_health = subparsers.add_parser(
|
|
2144
|
-
"health",
|
|
2469
|
+
"health",
|
|
2470
|
+
help="Code health assistant - run checks and auto-fix issues",
|
|
2145
2471
|
)
|
|
2146
2472
|
parser_health.add_argument(
|
|
2147
|
-
"--deep",
|
|
2473
|
+
"--deep",
|
|
2474
|
+
action="store_true",
|
|
2475
|
+
help="Run comprehensive checks (slower)",
|
|
2148
2476
|
)
|
|
2149
2477
|
parser_health.add_argument(
|
|
2150
2478
|
"--check",
|
|
@@ -2153,20 +2481,31 @@ def main():
|
|
|
2153
2481
|
)
|
|
2154
2482
|
parser_health.add_argument("--fix", action="store_true", help="Auto-fix issues where possible")
|
|
2155
2483
|
parser_health.add_argument(
|
|
2156
|
-
"--dry-run",
|
|
2484
|
+
"--dry-run",
|
|
2485
|
+
action="store_true",
|
|
2486
|
+
help="Show what would be fixed without applying",
|
|
2157
2487
|
)
|
|
2158
2488
|
parser_health.add_argument(
|
|
2159
|
-
"--interactive",
|
|
2489
|
+
"--interactive",
|
|
2490
|
+
action="store_true",
|
|
2491
|
+
help="Prompt before applying non-safe fixes",
|
|
2160
2492
|
)
|
|
2161
2493
|
parser_health.add_argument("--details", action="store_true", help="Show detailed issue list")
|
|
2162
2494
|
parser_health.add_argument(
|
|
2163
|
-
"--full",
|
|
2495
|
+
"--full",
|
|
2496
|
+
action="store_true",
|
|
2497
|
+
help="Show full report with all details",
|
|
2164
2498
|
)
|
|
2165
2499
|
parser_health.add_argument(
|
|
2166
|
-
"--trends",
|
|
2500
|
+
"--trends",
|
|
2501
|
+
type=int,
|
|
2502
|
+
metavar="DAYS",
|
|
2503
|
+
help="Show health trends over N days",
|
|
2167
2504
|
)
|
|
2168
2505
|
parser_health.add_argument(
|
|
2169
|
-
"--project-root",
|
|
2506
|
+
"--project-root",
|
|
2507
|
+
default=".",
|
|
2508
|
+
help="Project root directory (default: current)",
|
|
2170
2509
|
)
|
|
2171
2510
|
parser_health.add_argument("--json", action="store_true", help="Output as JSON")
|
|
2172
2511
|
parser_health.set_defaults(func=cmd_health)
|
|
@@ -2177,10 +2516,13 @@ def main():
|
|
|
2177
2516
|
|
|
2178
2517
|
# Morning command (start-of-day briefing)
|
|
2179
2518
|
parser_morning = subparsers.add_parser(
|
|
2180
|
-
"morning",
|
|
2519
|
+
"morning",
|
|
2520
|
+
help="Start-of-day briefing with patterns, debt, and focus areas",
|
|
2181
2521
|
)
|
|
2182
2522
|
parser_morning.add_argument(
|
|
2183
|
-
"--patterns-dir",
|
|
2523
|
+
"--patterns-dir",
|
|
2524
|
+
default="./patterns",
|
|
2525
|
+
help="Path to patterns directory",
|
|
2184
2526
|
)
|
|
2185
2527
|
parser_morning.add_argument("--project-root", default=".", help="Project root directory")
|
|
2186
2528
|
parser_morning.add_argument("--verbose", "-v", action="store_true", help="Show detailed output")
|
|
@@ -2189,48 +2531,77 @@ def main():
|
|
|
2189
2531
|
# Ship command (pre-commit validation)
|
|
2190
2532
|
parser_ship = subparsers.add_parser("ship", help="Pre-commit validation pipeline")
|
|
2191
2533
|
parser_ship.add_argument(
|
|
2192
|
-
"--patterns-dir",
|
|
2534
|
+
"--patterns-dir",
|
|
2535
|
+
default="./patterns",
|
|
2536
|
+
help="Path to patterns directory",
|
|
2193
2537
|
)
|
|
2194
2538
|
parser_ship.add_argument("--project-root", default=".", help="Project root directory")
|
|
2195
2539
|
parser_ship.add_argument(
|
|
2196
|
-
"--skip-sync",
|
|
2540
|
+
"--skip-sync",
|
|
2541
|
+
action="store_true",
|
|
2542
|
+
help="Skip syncing patterns to Claude",
|
|
2543
|
+
)
|
|
2544
|
+
parser_ship.add_argument(
|
|
2545
|
+
"--tests-only",
|
|
2546
|
+
action="store_true",
|
|
2547
|
+
help="Run tests only (skip lint/format checks)",
|
|
2548
|
+
)
|
|
2549
|
+
parser_ship.add_argument(
|
|
2550
|
+
"--security-only",
|
|
2551
|
+
action="store_true",
|
|
2552
|
+
help="Run security checks only",
|
|
2197
2553
|
)
|
|
2198
2554
|
parser_ship.add_argument("--verbose", "-v", action="store_true", help="Show detailed output")
|
|
2199
2555
|
parser_ship.set_defaults(func=cmd_ship)
|
|
2200
2556
|
|
|
2201
2557
|
# Fix-all command (auto-fix everything)
|
|
2202
2558
|
parser_fix_all = subparsers.add_parser(
|
|
2203
|
-
"fix-all",
|
|
2559
|
+
"fix-all",
|
|
2560
|
+
help="Auto-fix all fixable lint and format issues",
|
|
2204
2561
|
)
|
|
2205
2562
|
parser_fix_all.add_argument("--project-root", default=".", help="Project root directory")
|
|
2206
2563
|
parser_fix_all.add_argument(
|
|
2207
|
-
"--dry-run",
|
|
2564
|
+
"--dry-run",
|
|
2565
|
+
action="store_true",
|
|
2566
|
+
help="Show what would be fixed without applying",
|
|
2208
2567
|
)
|
|
2209
2568
|
parser_fix_all.add_argument("--verbose", "-v", action="store_true", help="Show detailed output")
|
|
2210
2569
|
parser_fix_all.set_defaults(func=cmd_fix_all)
|
|
2211
2570
|
|
|
2212
2571
|
# Learn command (pattern learning from git history)
|
|
2213
2572
|
parser_learn = subparsers.add_parser(
|
|
2214
|
-
"learn",
|
|
2573
|
+
"learn",
|
|
2574
|
+
help="Learn patterns from git history and bug fixes",
|
|
2215
2575
|
)
|
|
2216
2576
|
parser_learn.add_argument(
|
|
2217
|
-
"--patterns-dir",
|
|
2577
|
+
"--patterns-dir",
|
|
2578
|
+
default="./patterns",
|
|
2579
|
+
help="Path to patterns directory",
|
|
2218
2580
|
)
|
|
2219
2581
|
parser_learn.add_argument(
|
|
2220
|
-
"--analyze",
|
|
2582
|
+
"--analyze",
|
|
2583
|
+
type=int,
|
|
2584
|
+
metavar="N",
|
|
2585
|
+
help="Analyze last N commits (default: 10)",
|
|
2221
2586
|
)
|
|
2222
2587
|
parser_learn.add_argument(
|
|
2223
|
-
"--watch",
|
|
2588
|
+
"--watch",
|
|
2589
|
+
action="store_true",
|
|
2590
|
+
help="Watch for new commits (not yet implemented)",
|
|
2224
2591
|
)
|
|
2225
2592
|
parser_learn.add_argument("--verbose", "-v", action="store_true", help="Show detailed output")
|
|
2226
2593
|
parser_learn.set_defaults(func=cmd_learn)
|
|
2227
2594
|
|
|
2228
2595
|
# Costs command (cost tracking dashboard)
|
|
2229
2596
|
parser_costs = subparsers.add_parser(
|
|
2230
|
-
"costs",
|
|
2597
|
+
"costs",
|
|
2598
|
+
help="View API cost tracking and savings from model routing",
|
|
2231
2599
|
)
|
|
2232
2600
|
parser_costs.add_argument(
|
|
2233
|
-
"--days",
|
|
2601
|
+
"--days",
|
|
2602
|
+
type=int,
|
|
2603
|
+
default=7,
|
|
2604
|
+
help="Number of days to include (default: 7)",
|
|
2234
2605
|
)
|
|
2235
2606
|
parser_costs.add_argument("--empathy-dir", default=".empathy", help="Empathy data directory")
|
|
2236
2607
|
parser_costs.add_argument("--json", action="store_true", help="Output as JSON")
|
|
@@ -2252,16 +2623,25 @@ def main():
|
|
|
2252
2623
|
# Dashboard command (visual web interface)
|
|
2253
2624
|
parser_dashboard = subparsers.add_parser("dashboard", help="Launch visual dashboard in browser")
|
|
2254
2625
|
parser_dashboard.add_argument(
|
|
2255
|
-
"--port",
|
|
2626
|
+
"--port",
|
|
2627
|
+
type=int,
|
|
2628
|
+
default=8765,
|
|
2629
|
+
help="Port to run on (default: 8765)",
|
|
2256
2630
|
)
|
|
2257
2631
|
parser_dashboard.add_argument(
|
|
2258
|
-
"--patterns-dir",
|
|
2632
|
+
"--patterns-dir",
|
|
2633
|
+
default="./patterns",
|
|
2634
|
+
help="Path to patterns directory",
|
|
2259
2635
|
)
|
|
2260
2636
|
parser_dashboard.add_argument(
|
|
2261
|
-
"--empathy-dir",
|
|
2637
|
+
"--empathy-dir",
|
|
2638
|
+
default=".empathy",
|
|
2639
|
+
help="Empathy data directory",
|
|
2262
2640
|
)
|
|
2263
2641
|
parser_dashboard.add_argument(
|
|
2264
|
-
"--no-browser",
|
|
2642
|
+
"--no-browser",
|
|
2643
|
+
action="store_true",
|
|
2644
|
+
help="Don't open browser automatically",
|
|
2265
2645
|
)
|
|
2266
2646
|
parser_dashboard.set_defaults(func=cmd_dashboard)
|
|
2267
2647
|
|
|
@@ -2271,7 +2651,9 @@ def main():
|
|
|
2271
2651
|
help="List and manage agent frameworks (LangChain, LangGraph, AutoGen, Haystack)",
|
|
2272
2652
|
)
|
|
2273
2653
|
parser_frameworks.add_argument(
|
|
2274
|
-
"--all",
|
|
2654
|
+
"--all",
|
|
2655
|
+
action="store_true",
|
|
2656
|
+
help="Show all frameworks including uninstalled",
|
|
2275
2657
|
)
|
|
2276
2658
|
parser_frameworks.add_argument(
|
|
2277
2659
|
"--recommend",
|
|
@@ -2304,9 +2686,9 @@ def main():
|
|
|
2304
2686
|
parser_workflow.add_argument(
|
|
2305
2687
|
"--provider",
|
|
2306
2688
|
"-p",
|
|
2307
|
-
choices=["anthropic", "openai", "ollama", "hybrid"],
|
|
2689
|
+
choices=["anthropic", "openai", "google", "ollama", "hybrid"],
|
|
2308
2690
|
default=None, # None means use config
|
|
2309
|
-
help="Model provider: anthropic, openai, ollama, or hybrid (mix of best models)",
|
|
2691
|
+
help="Model provider: anthropic, openai, google, ollama, or hybrid (mix of best models)",
|
|
2310
2692
|
)
|
|
2311
2693
|
parser_workflow.add_argument(
|
|
2312
2694
|
"--force",
|
|
@@ -2314,14 +2696,27 @@ def main():
|
|
|
2314
2696
|
help="Force overwrite existing config file",
|
|
2315
2697
|
)
|
|
2316
2698
|
parser_workflow.add_argument("--json", action="store_true", help="Output as JSON")
|
|
2699
|
+
parser_workflow.add_argument(
|
|
2700
|
+
"--write-tests",
|
|
2701
|
+
action="store_true",
|
|
2702
|
+
help="(test-gen workflow) Write generated tests to disk",
|
|
2703
|
+
)
|
|
2704
|
+
parser_workflow.add_argument(
|
|
2705
|
+
"--output-dir",
|
|
2706
|
+
default="tests/generated",
|
|
2707
|
+
help="(test-gen workflow) Output directory for generated tests",
|
|
2708
|
+
)
|
|
2317
2709
|
parser_workflow.set_defaults(func=cmd_workflow)
|
|
2318
2710
|
|
|
2319
2711
|
# Sync-claude command (sync patterns to Claude Code)
|
|
2320
2712
|
parser_sync_claude = subparsers.add_parser(
|
|
2321
|
-
"sync-claude",
|
|
2713
|
+
"sync-claude",
|
|
2714
|
+
help="Sync learned patterns to Claude Code rules",
|
|
2322
2715
|
)
|
|
2323
2716
|
parser_sync_claude.add_argument(
|
|
2324
|
-
"--patterns-dir",
|
|
2717
|
+
"--patterns-dir",
|
|
2718
|
+
default="./patterns",
|
|
2719
|
+
help="Path to patterns directory",
|
|
2325
2720
|
)
|
|
2326
2721
|
parser_sync_claude.add_argument(
|
|
2327
2722
|
"--output-dir",
|
|
@@ -2342,13 +2737,16 @@ def main():
|
|
|
2342
2737
|
help="Category to show (getting-started, daily-workflow, code-quality, etc.)",
|
|
2343
2738
|
)
|
|
2344
2739
|
parser_cheatsheet.add_argument(
|
|
2345
|
-
"--compact",
|
|
2740
|
+
"--compact",
|
|
2741
|
+
action="store_true",
|
|
2742
|
+
help="Show commands only without descriptions",
|
|
2346
2743
|
)
|
|
2347
2744
|
parser_cheatsheet.set_defaults(func=cmd_cheatsheet)
|
|
2348
2745
|
|
|
2349
2746
|
# Onboard command (interactive tutorial)
|
|
2350
2747
|
parser_onboard = subparsers.add_parser(
|
|
2351
|
-
"onboard",
|
|
2748
|
+
"onboard",
|
|
2749
|
+
help="Interactive onboarding tutorial for new users",
|
|
2352
2750
|
)
|
|
2353
2751
|
parser_onboard.add_argument("--step", type=int, help="Jump to a specific step (1-5)")
|
|
2354
2752
|
parser_onboard.add_argument("--reset", action="store_true", help="Reset onboarding progress")
|
|
@@ -2356,7 +2754,8 @@ def main():
|
|
|
2356
2754
|
|
|
2357
2755
|
# Explain command (detailed command explanations)
|
|
2358
2756
|
parser_explain = subparsers.add_parser(
|
|
2359
|
-
"explain",
|
|
2757
|
+
"explain",
|
|
2758
|
+
help="Get detailed explanation of how a command works",
|
|
2360
2759
|
)
|
|
2361
2760
|
parser_explain.add_argument(
|
|
2362
2761
|
"command",
|
|
@@ -2367,10 +2766,14 @@ def main():
|
|
|
2367
2766
|
|
|
2368
2767
|
# Achievements command (progress tracking)
|
|
2369
2768
|
parser_achievements = subparsers.add_parser(
|
|
2370
|
-
"achievements",
|
|
2769
|
+
"achievements",
|
|
2770
|
+
help="View your usage statistics and achievements",
|
|
2371
2771
|
)
|
|
2372
2772
|
parser_achievements.set_defaults(func=cmd_achievements)
|
|
2373
2773
|
|
|
2774
|
+
# Wizard Factory commands (create wizards 12x faster)
|
|
2775
|
+
add_wizard_factory_commands(subparsers)
|
|
2776
|
+
|
|
2374
2777
|
# Parse arguments
|
|
2375
2778
|
args = parser.parse_args()
|
|
2376
2779
|
|
|
@@ -2382,13 +2785,16 @@ def main():
|
|
|
2382
2785
|
if args.command and args.command not in ("dashboard", "run"):
|
|
2383
2786
|
try:
|
|
2384
2787
|
show_tip_if_available(args.command)
|
|
2385
|
-
except Exception:
|
|
2386
|
-
|
|
2788
|
+
except Exception as e: # noqa: BLE001
|
|
2789
|
+
# INTENTIONAL: Discovery tips are optional UX enhancements
|
|
2790
|
+
# They should never cause command execution to fail
|
|
2791
|
+
# Cannot predict all possible errors from discovery system
|
|
2792
|
+
logger.debug(f"Discovery tip not available for {args.command}: {e}")
|
|
2793
|
+
pass
|
|
2387
2794
|
|
|
2388
2795
|
return result if result is not None else 0
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
return 0
|
|
2796
|
+
parser.print_help()
|
|
2797
|
+
return 0
|
|
2392
2798
|
|
|
2393
2799
|
|
|
2394
2800
|
if __name__ == "__main__":
|