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
empathy_os/cli_unified.py
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
"""Unified CLI for Empathy Framework
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A simplified, intelligent CLI using Socratic questioning.
|
|
4
4
|
|
|
5
5
|
Usage:
|
|
6
|
-
empathy
|
|
7
|
-
empathy
|
|
8
|
-
empathy
|
|
9
|
-
empathy
|
|
10
|
-
empathy
|
|
6
|
+
empathy do "review code in src/" # Intelligent - asks questions if needed
|
|
7
|
+
empathy r . # Quick: review
|
|
8
|
+
empathy s . # Quick: security
|
|
9
|
+
empathy t . # Quick: test
|
|
10
|
+
empathy scan . # Quick scan (no API)
|
|
11
|
+
empathy ship # Pre-commit check
|
|
11
12
|
|
|
12
13
|
Copyright 2025 Smart-AI-Memory
|
|
13
14
|
Licensed under Fair Source License 0.9
|
|
14
15
|
"""
|
|
15
16
|
|
|
17
|
+
import json
|
|
16
18
|
import subprocess
|
|
17
19
|
import sys
|
|
18
20
|
from importlib.metadata import version as get_version
|
|
@@ -22,10 +24,104 @@ import typer
|
|
|
22
24
|
from rich.console import Console
|
|
23
25
|
from rich.panel import Panel
|
|
24
26
|
|
|
25
|
-
#
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# CONSTANTS
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
CHEATSHEET_CONTENT = """\
|
|
32
|
+
[bold]Main Command[/bold]
|
|
33
|
+
empathy do "..." Intelligent task execution (asks questions if needed)
|
|
34
|
+
|
|
35
|
+
[bold]Quick Actions (short aliases)[/bold]
|
|
36
|
+
empathy r [path] Review code
|
|
37
|
+
empathy s [path] Security audit
|
|
38
|
+
empathy t [path] Generate tests
|
|
39
|
+
empathy d [path] Generate docs
|
|
40
|
+
|
|
41
|
+
[bold]Utilities[/bold]
|
|
42
|
+
empathy scan [path] Quick scan (no API needed)
|
|
43
|
+
empathy ship Pre-commit validation
|
|
44
|
+
empathy health Project health check
|
|
45
|
+
|
|
46
|
+
[bold]Reports[/bold]
|
|
47
|
+
empathy report costs API cost tracking
|
|
48
|
+
empathy report health Project health summary
|
|
49
|
+
empathy report patterns Learned patterns
|
|
50
|
+
|
|
51
|
+
[bold]Memory[/bold]
|
|
52
|
+
empathy memory Memory system status
|
|
53
|
+
empathy memory start Start Redis"""
|
|
54
|
+
|
|
55
|
+
TIER_CONFIG_PATH = Path(".empathy") / "tier_config.json"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# =============================================================================
|
|
59
|
+
# HELPER FUNCTIONS
|
|
60
|
+
# =============================================================================
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _load_tier_config() -> dict:
|
|
64
|
+
"""Load tier configuration from .empathy/tier_config.json."""
|
|
65
|
+
if TIER_CONFIG_PATH.exists():
|
|
66
|
+
try:
|
|
67
|
+
return json.loads(TIER_CONFIG_PATH.read_text())
|
|
68
|
+
except json.JSONDecodeError:
|
|
69
|
+
return {}
|
|
70
|
+
return {}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _save_tier_config(config: dict) -> None:
|
|
74
|
+
"""Save tier configuration to .empathy/tier_config.json."""
|
|
75
|
+
TIER_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
TIER_CONFIG_PATH.write_text(json.dumps(config, indent=2))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _auto_sync_patterns() -> None:
|
|
80
|
+
"""Automatically sync patterns to Claude Code after workflow completion."""
|
|
81
|
+
try:
|
|
82
|
+
result = subprocess.run(
|
|
83
|
+
["empathy-sync-claude", "--source", "patterns"],
|
|
84
|
+
capture_output=True,
|
|
85
|
+
text=True,
|
|
86
|
+
timeout=30,
|
|
87
|
+
check=False,
|
|
88
|
+
)
|
|
89
|
+
if result.returncode == 0:
|
|
90
|
+
console.print("\n[dim]✓ Patterns synced to Claude Code[/dim]")
|
|
91
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, Exception):
|
|
92
|
+
pass # Silent fail
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _run_workflow(name: str, path: Path, json_output: bool = False):
|
|
96
|
+
"""Helper to run a workflow via the legacy CLI."""
|
|
97
|
+
workflow_input = f'{{"path": "{path}"}}'
|
|
98
|
+
|
|
99
|
+
cmd = [
|
|
100
|
+
sys.executable,
|
|
101
|
+
"-m",
|
|
102
|
+
"empathy_os.cli",
|
|
103
|
+
"workflow",
|
|
104
|
+
"run",
|
|
105
|
+
name,
|
|
106
|
+
"--input",
|
|
107
|
+
workflow_input,
|
|
108
|
+
]
|
|
109
|
+
if json_output:
|
|
110
|
+
cmd.append("--json")
|
|
111
|
+
|
|
112
|
+
result = subprocess.run(cmd, check=False)
|
|
113
|
+
|
|
114
|
+
if result.returncode == 0 and not json_output:
|
|
115
|
+
_auto_sync_patterns()
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# APP SETUP
|
|
120
|
+
# =============================================================================
|
|
121
|
+
|
|
26
122
|
app = typer.Typer(
|
|
27
123
|
name="empathy",
|
|
28
|
-
help="Empathy Framework -
|
|
124
|
+
help="Empathy Framework - Intelligent AI-Developer Collaboration",
|
|
29
125
|
no_args_is_help=True,
|
|
30
126
|
rich_markup_mode="rich",
|
|
31
127
|
)
|
|
@@ -59,244 +155,236 @@ def callback(
|
|
|
59
155
|
help="Show version and exit",
|
|
60
156
|
),
|
|
61
157
|
):
|
|
62
|
-
"""Empathy Framework -
|
|
63
|
-
|
|
64
|
-
The AI collaboration framework that predicts problems before they happen.
|
|
158
|
+
"""Empathy Framework - Intelligent AI-Developer Collaboration
|
|
65
159
|
|
|
66
160
|
[bold]Quick Start:[/bold]
|
|
67
|
-
empathy
|
|
68
|
-
empathy
|
|
69
|
-
empathy
|
|
70
|
-
|
|
71
|
-
[bold]Memory:[/bold]
|
|
72
|
-
empathy memory status Check memory system status
|
|
73
|
-
empathy memory start Start Redis server
|
|
161
|
+
empathy do "review the code" Ask AI to do something
|
|
162
|
+
empathy r . Quick code review
|
|
163
|
+
empathy scan . Quick security scan
|
|
74
164
|
|
|
75
|
-
[bold]
|
|
76
|
-
|
|
77
|
-
empathy provider --set hybrid Configure provider
|
|
78
|
-
|
|
79
|
-
[bold]Inspection:[/bold]
|
|
80
|
-
empathy scan . Scan codebase for issues
|
|
81
|
-
empathy inspect . Deep inspection with SARIF output
|
|
165
|
+
[bold]Shortcuts:[/bold]
|
|
166
|
+
r = review, s = security, t = test, d = docs
|
|
82
167
|
"""
|
|
83
168
|
|
|
84
169
|
|
|
85
170
|
# =============================================================================
|
|
86
|
-
#
|
|
171
|
+
# MAIN COMMAND: do
|
|
87
172
|
# =============================================================================
|
|
88
173
|
|
|
89
|
-
memory_app = typer.Typer(help="Memory system control panel")
|
|
90
|
-
app.add_typer(memory_app, name="memory")
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@memory_app.command("status")
|
|
94
|
-
def memory_status():
|
|
95
|
-
"""Check memory system status (Redis, patterns, stats)."""
|
|
96
|
-
# Delegate to the existing CLI
|
|
97
|
-
subprocess.run([sys.executable, "-m", "empathy_os.memory.control_panel", "status"], check=False)
|
|
98
|
-
|
|
99
174
|
|
|
100
|
-
@
|
|
101
|
-
def
|
|
102
|
-
"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"""
|
|
109
|
-
subprocess.run([sys.executable, "-m", "empathy_os.memory.control_panel", "stop"], check=False)
|
|
175
|
+
@app.command("do")
|
|
176
|
+
def do_command(
|
|
177
|
+
goal: str = typer.Argument(..., help="What you want to accomplish"),
|
|
178
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Path to analyze"),
|
|
179
|
+
interactive: bool = typer.Option(
|
|
180
|
+
True, "--interactive/--no-interactive", "-i", help="Ask clarifying questions"
|
|
181
|
+
),
|
|
182
|
+
):
|
|
183
|
+
"""Intelligent task execution using Socratic questioning.
|
|
110
184
|
|
|
185
|
+
The AI will understand your goal and ask clarifying questions if needed.
|
|
186
|
+
Uses domain templates for common tasks like code review, security, testing.
|
|
111
187
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
188
|
+
Examples:
|
|
189
|
+
empathy do "review the authentication code"
|
|
190
|
+
empathy do "find security vulnerabilities" --path ./src
|
|
191
|
+
empathy do "generate tests for the API" --no-interactive
|
|
192
|
+
"""
|
|
193
|
+
console.print(f"\n[bold]Goal:[/bold] {goal}")
|
|
194
|
+
console.print(f"[dim]Path: {path}[/dim]\n")
|
|
116
195
|
|
|
196
|
+
# Use Socratic system for intelligent task execution
|
|
197
|
+
try:
|
|
198
|
+
from empathy_os.socratic import SocraticWorkflowBuilder
|
|
199
|
+
from empathy_os.socratic.cli import console as socratic_console
|
|
200
|
+
from empathy_os.socratic.cli import render_form_interactive
|
|
201
|
+
from empathy_os.socratic.storage import get_default_storage
|
|
202
|
+
|
|
203
|
+
builder = SocraticWorkflowBuilder()
|
|
204
|
+
storage = get_default_storage()
|
|
205
|
+
|
|
206
|
+
# Start session with the goal
|
|
207
|
+
session = builder.start_session()
|
|
208
|
+
session = builder.set_goal(session, f"{goal} (path: {path})")
|
|
209
|
+
storage.save_session(session)
|
|
210
|
+
|
|
211
|
+
# Show domain detection
|
|
212
|
+
if session.goal_analysis:
|
|
213
|
+
console.print(f"[cyan]Detected domain:[/cyan] {session.goal_analysis.domain}")
|
|
214
|
+
console.print(f"[cyan]Confidence:[/cyan] {session.goal_analysis.confidence:.0%}")
|
|
215
|
+
|
|
216
|
+
if session.goal_analysis.ambiguities and interactive:
|
|
217
|
+
console.print("\n[yellow]Clarifications needed:[/yellow]")
|
|
218
|
+
for amb in session.goal_analysis.ambiguities:
|
|
219
|
+
console.print(f" • {amb}")
|
|
220
|
+
|
|
221
|
+
# Interactive questioning if needed
|
|
222
|
+
if interactive:
|
|
223
|
+
while not builder.is_ready_to_generate(session):
|
|
224
|
+
form = builder.get_next_questions(session)
|
|
225
|
+
if not form:
|
|
226
|
+
break
|
|
227
|
+
|
|
228
|
+
answers = render_form_interactive(form, socratic_console)
|
|
229
|
+
session = builder.submit_answers(session, answers)
|
|
230
|
+
storage.save_session(session)
|
|
231
|
+
|
|
232
|
+
# Generate and execute workflow
|
|
233
|
+
if builder.is_ready_to_generate(session):
|
|
234
|
+
console.print("\n[bold]Generating workflow...[/bold]")
|
|
235
|
+
workflow = builder.generate_workflow(session)
|
|
236
|
+
storage.save_session(session)
|
|
117
237
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
238
|
+
console.print(
|
|
239
|
+
f"\n[green]✓ Generated workflow with {len(workflow.agents)} agents[/green]"
|
|
240
|
+
)
|
|
241
|
+
console.print(workflow.describe())
|
|
242
|
+
|
|
243
|
+
# Execute the workflow
|
|
244
|
+
if session.blueprint:
|
|
245
|
+
storage.save_blueprint(session.blueprint)
|
|
246
|
+
console.print(f"\n[dim]Blueprint saved: {session.blueprint.id[:8]}...[/dim]")
|
|
247
|
+
|
|
248
|
+
_auto_sync_patterns()
|
|
249
|
+
|
|
250
|
+
except ImportError as e:
|
|
251
|
+
console.print(f"[yellow]Socratic system not fully available: {e}[/yellow]")
|
|
252
|
+
console.print("[dim]Falling back to keyword matching...[/dim]\n")
|
|
253
|
+
|
|
254
|
+
# Fallback: keyword-based workflow selection
|
|
255
|
+
goal_lower = goal.lower()
|
|
256
|
+
if any(w in goal_lower for w in ["review", "check", "analyze"]):
|
|
257
|
+
_run_workflow("code-review", path)
|
|
258
|
+
elif any(w in goal_lower for w in ["security", "vulnerab", "owasp"]):
|
|
259
|
+
_run_workflow("security-audit", path)
|
|
260
|
+
elif any(w in goal_lower for w in ["test", "coverage"]):
|
|
261
|
+
_run_workflow("test-gen", path)
|
|
262
|
+
elif any(w in goal_lower for w in ["doc", "document"]):
|
|
263
|
+
_run_workflow("doc-gen", path)
|
|
264
|
+
else:
|
|
265
|
+
_run_workflow("code-review", path)
|
|
124
266
|
|
|
125
267
|
|
|
126
268
|
# =============================================================================
|
|
127
|
-
#
|
|
269
|
+
# SHORT ALIASES
|
|
128
270
|
# =============================================================================
|
|
129
271
|
|
|
130
|
-
provider_app = typer.Typer(help="Multi-model provider configuration")
|
|
131
|
-
app.add_typer(provider_app, name="provider")
|
|
132
|
-
|
|
133
272
|
|
|
134
|
-
@
|
|
135
|
-
def
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
interactive: bool = False,
|
|
139
|
-
format_out: str = "table",
|
|
273
|
+
@app.command("r")
|
|
274
|
+
def review_short(
|
|
275
|
+
path: Path = typer.Argument(Path("."), help="Path to review"),
|
|
276
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
140
277
|
):
|
|
141
|
-
"""
|
|
142
|
-
if ctx.invoked_subcommand is not None:
|
|
143
|
-
return
|
|
144
|
-
|
|
145
|
-
args = [sys.executable, "-m", "empathy_os.models.cli", "provider"]
|
|
146
|
-
if set_provider:
|
|
147
|
-
args.extend(["--set", set_provider])
|
|
148
|
-
if interactive:
|
|
149
|
-
args.append("--interactive")
|
|
150
|
-
if format_out != "table":
|
|
151
|
-
args.extend(["-f", format_out])
|
|
278
|
+
"""[bold]Review[/bold] - Quick code review.
|
|
152
279
|
|
|
153
|
-
|
|
280
|
+
Alias for: empathy do "review code"
|
|
281
|
+
"""
|
|
282
|
+
_run_workflow("code-review", path, json_output)
|
|
154
283
|
|
|
155
284
|
|
|
156
|
-
@
|
|
157
|
-
def
|
|
158
|
-
|
|
285
|
+
@app.command("s")
|
|
286
|
+
def security_short(
|
|
287
|
+
path: Path = typer.Argument(Path("."), help="Path to scan"),
|
|
288
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
159
289
|
):
|
|
160
|
-
"""
|
|
161
|
-
args = [sys.executable, "-m", "empathy_os.models.cli", "registry"]
|
|
162
|
-
if provider_filter:
|
|
163
|
-
args.extend(["--provider", provider_filter])
|
|
164
|
-
subprocess.run(args, check=False)
|
|
165
|
-
|
|
290
|
+
"""[bold]Security[/bold] - Quick security audit.
|
|
166
291
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
output_tokens: int = 2000,
|
|
171
|
-
):
|
|
172
|
-
"""Estimate costs for token usage."""
|
|
173
|
-
subprocess.run(
|
|
174
|
-
[
|
|
175
|
-
sys.executable,
|
|
176
|
-
"-m",
|
|
177
|
-
"empathy_os.models.cli",
|
|
178
|
-
"costs",
|
|
179
|
-
"--input-tokens",
|
|
180
|
-
str(input_tokens),
|
|
181
|
-
"--output-tokens",
|
|
182
|
-
str(output_tokens),
|
|
183
|
-
],
|
|
184
|
-
check=False,
|
|
185
|
-
)
|
|
292
|
+
Alias for: empathy do "security audit"
|
|
293
|
+
"""
|
|
294
|
+
_run_workflow("security-audit", path, json_output)
|
|
186
295
|
|
|
187
296
|
|
|
188
|
-
@
|
|
189
|
-
def
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
providers: bool = False,
|
|
297
|
+
@app.command("t")
|
|
298
|
+
def test_short(
|
|
299
|
+
path: Path = typer.Argument(Path("."), help="Path to analyze"),
|
|
300
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
193
301
|
):
|
|
194
|
-
"""
|
|
195
|
-
args = [sys.executable, "-m", "empathy_os.models.cli", "telemetry"]
|
|
196
|
-
if summary:
|
|
197
|
-
args.append("--summary")
|
|
198
|
-
if costs:
|
|
199
|
-
args.append("--costs")
|
|
200
|
-
if providers:
|
|
201
|
-
args.append("--providers")
|
|
202
|
-
subprocess.run(args, check=False)
|
|
203
|
-
|
|
302
|
+
"""[bold]Test[/bold] - Generate tests.
|
|
204
303
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
304
|
+
Alias for: empathy do "generate tests"
|
|
305
|
+
"""
|
|
306
|
+
_run_workflow("test-gen", path, json_output)
|
|
208
307
|
|
|
209
308
|
|
|
210
|
-
@app.command("
|
|
211
|
-
def
|
|
212
|
-
path: Path = Path("."),
|
|
213
|
-
|
|
214
|
-
fix: bool = False,
|
|
215
|
-
staged: bool = False,
|
|
309
|
+
@app.command("d")
|
|
310
|
+
def docs_short(
|
|
311
|
+
path: Path = typer.Argument(Path("."), help="Path to document"),
|
|
312
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
216
313
|
):
|
|
217
|
-
"""
|
|
218
|
-
args = ["empathy-scan", str(path)]
|
|
219
|
-
if format_out != "text":
|
|
220
|
-
args.extend(["--format", format_out])
|
|
221
|
-
if fix:
|
|
222
|
-
args.append("--fix")
|
|
223
|
-
if staged:
|
|
224
|
-
args.append("--staged")
|
|
314
|
+
"""[bold]Docs[/bold] - Generate documentation.
|
|
225
315
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
console.print("Install with: pip install empathy-framework[software]")
|
|
316
|
+
Alias for: empathy do "generate docs"
|
|
317
|
+
"""
|
|
318
|
+
_run_workflow("doc-gen", path, json_output)
|
|
230
319
|
|
|
231
320
|
|
|
232
321
|
# =============================================================================
|
|
233
|
-
#
|
|
322
|
+
# UTILITY COMMANDS
|
|
234
323
|
# =============================================================================
|
|
235
324
|
|
|
236
325
|
|
|
237
|
-
@app.command("
|
|
238
|
-
def
|
|
239
|
-
|
|
240
|
-
|
|
326
|
+
@app.command("scan")
|
|
327
|
+
def scan_command(
|
|
328
|
+
scan_type: str = typer.Argument("all", help="Scan type: security, performance, or all"),
|
|
329
|
+
path: Path = typer.Argument(Path("."), help="Path to scan"),
|
|
241
330
|
):
|
|
242
|
-
"""
|
|
243
|
-
args = ["empathy-inspect", str(path)]
|
|
244
|
-
if format_out != "text":
|
|
245
|
-
args.extend(["--format", format_out])
|
|
246
|
-
|
|
247
|
-
result = subprocess.run(args, check=False, capture_output=False)
|
|
248
|
-
if result.returncode != 0:
|
|
249
|
-
console.print("[yellow]Note: empathy-inspect may not be installed[/yellow]")
|
|
250
|
-
console.print("Install with: pip install empathy-framework[software]")
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
# =============================================================================
|
|
254
|
-
# SYNC-CLAUDE COMMAND
|
|
255
|
-
# =============================================================================
|
|
331
|
+
"""Quick security/performance scan (no API needed).
|
|
256
332
|
|
|
333
|
+
Examples:
|
|
334
|
+
empathy scan all .
|
|
335
|
+
empathy scan security ./src
|
|
336
|
+
"""
|
|
337
|
+
if scan_type not in ("security", "performance", "all"):
|
|
338
|
+
console.print(f"[red]Invalid scan type: {scan_type}[/red]")
|
|
339
|
+
console.print("Valid types: security, performance, all")
|
|
340
|
+
raise typer.Exit(code=1)
|
|
257
341
|
|
|
258
|
-
|
|
259
|
-
def sync_claude(
|
|
260
|
-
source: str = "patterns",
|
|
261
|
-
):
|
|
262
|
-
"""Sync patterns to Claude Code memory."""
|
|
263
|
-
subprocess.run(["empathy-sync-claude", "--source", source], check=False)
|
|
342
|
+
console.print(f"[bold blue]Scanning {path} ({scan_type})...[/bold blue]\n")
|
|
264
343
|
|
|
344
|
+
if scan_type in ("all", "security"):
|
|
345
|
+
# Run ruff for linting
|
|
346
|
+
console.print("[bold]Running ruff (linting)...[/bold]")
|
|
347
|
+
subprocess.run(["ruff", "check", str(path)], check=False)
|
|
265
348
|
|
|
266
|
-
#
|
|
267
|
-
|
|
268
|
-
|
|
349
|
+
# Run bandit for security
|
|
350
|
+
console.print("\n[bold]Running bandit (security)...[/bold]")
|
|
351
|
+
result = subprocess.run(["bandit", "-r", str(path), "-q"], check=False, capture_output=True)
|
|
352
|
+
if result.returncode == 0:
|
|
353
|
+
console.print("[green]No security issues found[/green]")
|
|
354
|
+
elif result.stdout:
|
|
355
|
+
console.print(result.stdout.decode())
|
|
269
356
|
|
|
357
|
+
if scan_type in ("all", "performance"):
|
|
358
|
+
console.print("\n[bold]Checking for performance patterns...[/bold]")
|
|
359
|
+
# Basic performance check - look for common issues
|
|
360
|
+
subprocess.run(["ruff", "check", str(path), "--select", "PERF"], check=False)
|
|
270
361
|
|
|
271
|
-
|
|
272
|
-
def morning():
|
|
273
|
-
"""Start-of-day briefing with patterns, git context, and priorities."""
|
|
274
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "morning"], check=False)
|
|
362
|
+
console.print("\n[bold green]Scan complete![/bold green]")
|
|
275
363
|
|
|
276
364
|
|
|
277
365
|
@app.command("ship")
|
|
278
|
-
def
|
|
279
|
-
|
|
280
|
-
security_only: bool = False,
|
|
281
|
-
skip_sync: bool = False,
|
|
366
|
+
def ship_command(
|
|
367
|
+
skip_sync: bool = typer.Option(False, "--skip-sync", help="Skip pattern sync"),
|
|
282
368
|
):
|
|
283
|
-
"""Pre-commit validation (lint, format, tests, security).
|
|
369
|
+
"""Pre-commit validation (lint, format, tests, security).
|
|
370
|
+
|
|
371
|
+
Run this before committing to ensure code quality.
|
|
372
|
+
"""
|
|
284
373
|
args = [sys.executable, "-m", "empathy_os.cli", "ship"]
|
|
285
|
-
if tests_only:
|
|
286
|
-
args.append("--tests-only")
|
|
287
|
-
if security_only:
|
|
288
|
-
args.append("--security-only")
|
|
289
374
|
if skip_sync:
|
|
290
375
|
args.append("--skip-sync")
|
|
291
376
|
subprocess.run(args, check=False)
|
|
292
377
|
|
|
293
378
|
|
|
294
379
|
@app.command("health")
|
|
295
|
-
def
|
|
296
|
-
deep: bool = False,
|
|
297
|
-
fix: bool = False,
|
|
380
|
+
def health_command(
|
|
381
|
+
deep: bool = typer.Option(False, "--deep", help="Comprehensive check"),
|
|
382
|
+
fix: bool = typer.Option(False, "--fix", help="Auto-fix issues"),
|
|
298
383
|
):
|
|
299
|
-
"""Quick health check
|
|
384
|
+
"""Quick project health check.
|
|
385
|
+
|
|
386
|
+
Shows lint issues, test status, and overall health score.
|
|
387
|
+
"""
|
|
300
388
|
args = [sys.executable, "-m", "empathy_os.cli", "health"]
|
|
301
389
|
if deep:
|
|
302
390
|
args.append("--deep")
|
|
@@ -305,1107 +393,380 @@ def health(
|
|
|
305
393
|
subprocess.run(args, check=False)
|
|
306
394
|
|
|
307
395
|
|
|
308
|
-
@app.command("fix-all")
|
|
309
|
-
def fix_all():
|
|
310
|
-
"""Fix all lint and format issues."""
|
|
311
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "fix-all"], check=False)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
@app.command("learn")
|
|
315
|
-
def learn(
|
|
316
|
-
analyze: int = 20,
|
|
317
|
-
):
|
|
318
|
-
"""Learn patterns from commit history."""
|
|
319
|
-
subprocess.run(
|
|
320
|
-
[sys.executable, "-m", "empathy_os.cli", "learn", "--analyze", str(analyze)], check=False
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
@app.command("run")
|
|
325
|
-
def run_repl():
|
|
326
|
-
"""Start interactive REPL mode."""
|
|
327
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "run"], check=False)
|
|
328
|
-
|
|
329
|
-
|
|
330
396
|
# =============================================================================
|
|
331
|
-
#
|
|
397
|
+
# REPORT SUBCOMMAND GROUP
|
|
332
398
|
# =============================================================================
|
|
333
399
|
|
|
334
|
-
|
|
335
|
-
app.add_typer(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
@wizard_app.command("list")
|
|
339
|
-
def wizard_list():
|
|
340
|
-
"""List all available wizards."""
|
|
341
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "frameworks"], check=False)
|
|
400
|
+
report_app = typer.Typer(help="View reports and dashboards")
|
|
401
|
+
app.add_typer(report_app, name="report")
|
|
342
402
|
|
|
343
403
|
|
|
344
|
-
@
|
|
345
|
-
def
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
):
|
|
349
|
-
"""Run a specific wizard on your codebase."""
|
|
350
|
-
console.print(f"[yellow]Running wizard:[/yellow] {name} on {path}")
|
|
351
|
-
# Delegate to empathy-scan with wizard filter
|
|
352
|
-
subprocess.run(["empathy-scan", str(path), "--wizards", name], check=False)
|
|
404
|
+
@report_app.command("costs")
|
|
405
|
+
def report_costs():
|
|
406
|
+
"""View API cost tracking."""
|
|
407
|
+
subprocess.run([sys.executable, "-m", "empathy_os.cli", "costs"], check=False)
|
|
353
408
|
|
|
354
409
|
|
|
355
|
-
@
|
|
356
|
-
def
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
..., "--domain", "-d", help="Domain (healthcare, finance, software)"
|
|
360
|
-
),
|
|
361
|
-
wizard_type: str = typer.Option(
|
|
362
|
-
"domain", "--type", "-t", help="Wizard type (domain, coach, ai)"
|
|
363
|
-
),
|
|
364
|
-
methodology: str = typer.Option(
|
|
365
|
-
"pattern", "--methodology", "-m", help="Methodology (pattern, tdd)"
|
|
366
|
-
),
|
|
367
|
-
patterns: str | None = typer.Option(
|
|
368
|
-
None, "--patterns", "-p", help="Comma-separated pattern IDs"
|
|
369
|
-
),
|
|
370
|
-
interactive: bool = typer.Option(
|
|
371
|
-
False, "--interactive", "-i", help="Interactive pattern selection"
|
|
372
|
-
),
|
|
373
|
-
):
|
|
374
|
-
"""Create a new wizard using Wizard Factory (12x faster)."""
|
|
375
|
-
cmd = [
|
|
376
|
-
sys.executable,
|
|
377
|
-
"-m",
|
|
378
|
-
"scaffolding",
|
|
379
|
-
"create",
|
|
380
|
-
name,
|
|
381
|
-
"--domain",
|
|
382
|
-
domain,
|
|
383
|
-
"--type",
|
|
384
|
-
wizard_type,
|
|
385
|
-
"--methodology",
|
|
386
|
-
methodology,
|
|
387
|
-
]
|
|
388
|
-
if patterns:
|
|
389
|
-
cmd.extend(["--patterns", patterns])
|
|
390
|
-
if interactive:
|
|
391
|
-
cmd.append("--interactive")
|
|
392
|
-
subprocess.run(cmd, check=False)
|
|
410
|
+
@report_app.command("health")
|
|
411
|
+
def report_health():
|
|
412
|
+
"""View project health summary."""
|
|
413
|
+
subprocess.run([sys.executable, "-m", "empathy_os.cli", "status"], check=False)
|
|
393
414
|
|
|
394
415
|
|
|
395
|
-
@
|
|
396
|
-
def
|
|
397
|
-
"""
|
|
398
|
-
subprocess.run(
|
|
416
|
+
@report_app.command("patterns")
|
|
417
|
+
def report_patterns():
|
|
418
|
+
"""View learned patterns."""
|
|
419
|
+
subprocess.run(
|
|
420
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "patterns"],
|
|
421
|
+
check=False,
|
|
422
|
+
)
|
|
399
423
|
|
|
400
424
|
|
|
401
|
-
@
|
|
402
|
-
def
|
|
403
|
-
|
|
404
|
-
patterns: str = typer.Option(..., "--patterns", "-p", help="Comma-separated pattern IDs"),
|
|
405
|
-
output: Path | None = typer.Option(None, "--output", "-o", help="Output directory"),
|
|
425
|
+
@report_app.command("telemetry")
|
|
426
|
+
def report_telemetry(
|
|
427
|
+
limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
|
|
406
428
|
):
|
|
407
|
-
"""
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
@wizard_app.command("analyze")
|
|
415
|
-
def wizard_analyze(
|
|
416
|
-
wizard_id: str = typer.Argument(..., help="Wizard ID"),
|
|
417
|
-
patterns: str = typer.Option(..., "--patterns", "-p", help="Wizard ID"),
|
|
418
|
-
json_output: bool = typer.Option(False, "--json", help="Output JSON format"),
|
|
419
|
-
):
|
|
420
|
-
"""Analyze wizard risk and get coverage recommendations."""
|
|
421
|
-
cmd = [sys.executable, "-m", "test_generator", "analyze", wizard_id, "--patterns", patterns]
|
|
422
|
-
if json_output:
|
|
423
|
-
cmd.append("--json")
|
|
424
|
-
subprocess.run(cmd, check=False)
|
|
429
|
+
"""View LLM usage telemetry."""
|
|
430
|
+
subprocess.run(
|
|
431
|
+
[sys.executable, "-m", "empathy_os.cli", "telemetry", "show", "--limit", str(limit)],
|
|
432
|
+
check=False,
|
|
433
|
+
)
|
|
425
434
|
|
|
426
435
|
|
|
427
436
|
# =============================================================================
|
|
428
|
-
#
|
|
437
|
+
# MEMORY SUBCOMMAND GROUP
|
|
429
438
|
# =============================================================================
|
|
430
439
|
|
|
431
|
-
|
|
432
|
-
app.add_typer(
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
@workflow_app.command("list")
|
|
436
|
-
def workflow_list():
|
|
437
|
-
"""List available multi-model workflows."""
|
|
438
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "workflow", "list"], check=False)
|
|
440
|
+
memory_app = typer.Typer(help="Memory system control panel")
|
|
441
|
+
app.add_typer(memory_app, name="memory")
|
|
439
442
|
|
|
440
443
|
|
|
441
|
-
@
|
|
442
|
-
def
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
):
|
|
450
|
-
"""Run a multi-model workflow.
|
|
444
|
+
@memory_app.callback(invoke_without_command=True)
|
|
445
|
+
def memory_default(ctx: typer.Context):
|
|
446
|
+
"""Memory system control panel."""
|
|
447
|
+
if ctx.invoked_subcommand is None:
|
|
448
|
+
subprocess.run(
|
|
449
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "status"],
|
|
450
|
+
check=False,
|
|
451
|
+
)
|
|
451
452
|
|
|
452
|
-
Examples:
|
|
453
|
-
empathy workflow run code-review --path ./src
|
|
454
|
-
empathy workflow run test-gen --input '{"path": ".", "file_types": [".py"]}'
|
|
455
|
-
"""
|
|
456
|
-
# Handle typer.Option defaults when called directly (not via CLI)
|
|
457
|
-
# When called directly, typer.Option() objects may be passed instead of resolved values
|
|
458
|
-
actual_path = path if isinstance(path, Path) else Path(".")
|
|
459
|
-
actual_input_json = input_json if isinstance(input_json, str) else None
|
|
460
|
-
actual_json_output = json_output if isinstance(json_output, bool) else False
|
|
461
|
-
|
|
462
|
-
# Determine input JSON - explicit --input takes precedence over --path
|
|
463
|
-
if actual_input_json:
|
|
464
|
-
workflow_input = actual_input_json
|
|
465
|
-
else:
|
|
466
|
-
workflow_input = f'{{"path": "{actual_path}"}}'
|
|
467
453
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
"
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
"--input",
|
|
476
|
-
workflow_input,
|
|
477
|
-
]
|
|
454
|
+
@memory_app.command("status")
|
|
455
|
+
def memory_status():
|
|
456
|
+
"""Check memory system status."""
|
|
457
|
+
subprocess.run(
|
|
458
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "status"],
|
|
459
|
+
check=False,
|
|
460
|
+
)
|
|
478
461
|
|
|
479
|
-
if use_recommended_tier:
|
|
480
|
-
cmd.append("--use-recommended-tier")
|
|
481
462
|
|
|
482
|
-
|
|
483
|
-
|
|
463
|
+
@memory_app.command("start")
|
|
464
|
+
def memory_start():
|
|
465
|
+
"""Start Redis server for short-term memory."""
|
|
466
|
+
subprocess.run(
|
|
467
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "start"],
|
|
468
|
+
check=False,
|
|
469
|
+
)
|
|
484
470
|
|
|
485
|
-
if actual_json_output:
|
|
486
|
-
cmd.append("--json")
|
|
487
471
|
|
|
488
|
-
|
|
472
|
+
@memory_app.command("stop")
|
|
473
|
+
def memory_stop():
|
|
474
|
+
"""Stop Redis server."""
|
|
475
|
+
subprocess.run(
|
|
476
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "stop"],
|
|
477
|
+
check=False,
|
|
478
|
+
)
|
|
489
479
|
|
|
490
480
|
|
|
491
|
-
@
|
|
492
|
-
def
|
|
493
|
-
|
|
494
|
-
description: str = typer.Option(None, "--description", "-d", help="Workflow description"),
|
|
495
|
-
patterns: str = typer.Option(None, "--patterns", "-p", help="Comma-separated pattern IDs"),
|
|
496
|
-
stages: str = typer.Option(None, "--stages", "-s", help="Comma-separated stage names"),
|
|
497
|
-
tier_map: str = typer.Option(
|
|
498
|
-
None, "--tier-map", "-t", help="Tier map (e.g., analyze:CHEAP,process:CAPABLE)"
|
|
499
|
-
),
|
|
500
|
-
output: Path = typer.Option(None, "--output", "-o", help="Output directory"),
|
|
501
|
-
):
|
|
502
|
-
"""Create a new workflow using Workflow Factory (12x faster)."""
|
|
503
|
-
cmd = [sys.executable, "-m", "workflow_scaffolding", "create", name]
|
|
504
|
-
if description:
|
|
505
|
-
cmd.extend(["--description", description])
|
|
506
|
-
if patterns:
|
|
507
|
-
cmd.extend(["--patterns", patterns])
|
|
508
|
-
if stages:
|
|
509
|
-
cmd.extend(["--stages", stages])
|
|
510
|
-
if tier_map:
|
|
511
|
-
cmd.extend(["--tier-map", tier_map])
|
|
512
|
-
if output:
|
|
513
|
-
cmd.extend(["--output", str(output)])
|
|
514
|
-
subprocess.run(cmd, check=False)
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
@workflow_app.command("list-patterns")
|
|
518
|
-
def workflow_list_patterns():
|
|
519
|
-
"""List available workflow patterns."""
|
|
520
|
-
subprocess.run([sys.executable, "-m", "workflow_scaffolding", "list-patterns"], check=False)
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
@workflow_app.command("recommend")
|
|
524
|
-
def workflow_recommend(
|
|
525
|
-
workflow_type: str = typer.Argument(
|
|
526
|
-
..., help="Workflow type (code-analysis, simple, multi-agent, etc.)"
|
|
527
|
-
),
|
|
528
|
-
):
|
|
529
|
-
"""Recommend patterns for a workflow type."""
|
|
481
|
+
@memory_app.command("patterns")
|
|
482
|
+
def memory_patterns():
|
|
483
|
+
"""List stored patterns."""
|
|
530
484
|
subprocess.run(
|
|
531
|
-
[sys.executable, "-m", "
|
|
485
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "patterns"],
|
|
486
|
+
check=False,
|
|
532
487
|
)
|
|
533
488
|
|
|
534
489
|
|
|
535
490
|
# =============================================================================
|
|
536
|
-
#
|
|
491
|
+
# UTILITIES SUBCOMMAND GROUP
|
|
537
492
|
# =============================================================================
|
|
538
493
|
|
|
539
|
-
|
|
540
|
-
app.add_typer(
|
|
494
|
+
utilities_app = typer.Typer(help="Utility tools - init, cheatsheet, dashboard, sync")
|
|
495
|
+
app.add_typer(utilities_app, name="utilities")
|
|
496
|
+
app.add_typer(utilities_app, name="utility", hidden=True) # Alias for common typo
|
|
541
497
|
|
|
542
498
|
|
|
543
|
-
@
|
|
544
|
-
def
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
daily: Quick parallel check (3 agents: Security, Coverage, Quality)
|
|
553
|
-
weekly: Comprehensive parallel (5 agents: adds Performance, Docs)
|
|
554
|
-
release: Deep refinement (6 agents: adds Architecture)
|
|
555
|
-
|
|
556
|
-
The results are automatically saved to .empathy/health.json which can be
|
|
557
|
-
viewed in the Empathy VS Code extension's health dashboard.
|
|
558
|
-
"""
|
|
559
|
-
import asyncio
|
|
499
|
+
@utilities_app.command("cheatsheet")
|
|
500
|
+
def utilities_cheatsheet():
|
|
501
|
+
"""Show quick reference for all commands."""
|
|
502
|
+
console.print(
|
|
503
|
+
Panel.fit(
|
|
504
|
+
CHEATSHEET_CONTENT,
|
|
505
|
+
title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
|
|
506
|
+
),
|
|
507
|
+
)
|
|
560
508
|
|
|
561
|
-
from empathy_os.workflows.orchestrated_health_check import OrchestratedHealthCheckWorkflow
|
|
562
509
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
510
|
+
@utilities_app.command("init")
|
|
511
|
+
def utilities_init():
|
|
512
|
+
"""Create a new configuration file."""
|
|
513
|
+
subprocess.run([sys.executable, "-m", "empathy_os.cli", "init"], check=False)
|
|
566
514
|
|
|
567
|
-
if json_output:
|
|
568
|
-
import json
|
|
569
515
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
console.print("=" * 60)
|
|
575
|
-
|
|
576
|
-
# Health score with color coding
|
|
577
|
-
score_color = (
|
|
578
|
-
"green"
|
|
579
|
-
if report.overall_health_score >= 80
|
|
580
|
-
else "yellow" if report.overall_health_score >= 60 else "red"
|
|
581
|
-
)
|
|
582
|
-
console.print(
|
|
583
|
-
f"\n[bold {score_color}]Health Score: {report.overall_health_score}/100 (Grade: {report.grade})[/bold {score_color}]"
|
|
584
|
-
)
|
|
585
|
-
console.print(f"[dim]Trend: {report.trend}[/dim]")
|
|
586
|
-
console.print(f"[dim]Duration: {report.execution_time:.2f}s[/dim]")
|
|
587
|
-
|
|
588
|
-
# Issues
|
|
589
|
-
if report.issues:
|
|
590
|
-
console.print(f"\n[bold red]⚠️ Issues Found ({len(report.issues)}):[/bold red]")
|
|
591
|
-
for issue in report.issues[:5]:
|
|
592
|
-
console.print(f" • {issue}")
|
|
593
|
-
|
|
594
|
-
# Recommendations
|
|
595
|
-
if report.recommendations:
|
|
596
|
-
console.print("\n[bold yellow]💡 Next Steps:[/bold yellow]")
|
|
597
|
-
for rec in report.recommendations[:10]: # Show more recommendations
|
|
598
|
-
console.print(f" {rec}")
|
|
599
|
-
|
|
600
|
-
console.print("\n" + "=" * 60)
|
|
601
|
-
|
|
602
|
-
# Show VS Code dashboard info
|
|
603
|
-
health_file = Path(project_root) / ".empathy" / "health.json"
|
|
604
|
-
console.print(f"\n📁 Health data saved to: [cyan]{health_file}[/cyan]")
|
|
605
|
-
|
|
606
|
-
# Try to open VS Code health panel
|
|
607
|
-
console.print("\n🔄 Opening Health Panel in VS Code...")
|
|
608
|
-
try:
|
|
609
|
-
import subprocess
|
|
610
|
-
|
|
611
|
-
# Use VS Code CLI to trigger the health panel (run in background)
|
|
612
|
-
subprocess.Popen(
|
|
613
|
-
["code", "--command", "empathy.openHealthPanel"],
|
|
614
|
-
stdout=subprocess.DEVNULL,
|
|
615
|
-
stderr=subprocess.DEVNULL,
|
|
616
|
-
)
|
|
617
|
-
console.print(
|
|
618
|
-
" [dim]If VS Code is already open, the Health Panel will appear automatically.[/dim]"
|
|
619
|
-
)
|
|
620
|
-
console.print(
|
|
621
|
-
" [dim]If not, open VS Code and the panel will show updated data.[/dim]"
|
|
622
|
-
)
|
|
623
|
-
except FileNotFoundError:
|
|
624
|
-
console.print("\n💡 [yellow]To view in VS Code:[/yellow]")
|
|
625
|
-
console.print(" 1. Open this project in VS Code")
|
|
626
|
-
console.print(" 2. Install the Empathy VS Code extension")
|
|
627
|
-
console.print(" 3. Run: code --command empathy.openHealthPanel")
|
|
628
|
-
console.print(" [dim]Or the panel will auto-refresh if already open[/dim]")
|
|
629
|
-
except Exception: # noqa: BLE001
|
|
630
|
-
# INTENTIONAL: Best-effort VS Code integration, don't fail if it doesn't work
|
|
631
|
-
console.print(
|
|
632
|
-
"\n💡 [dim]View in VS Code Health Panel (auto-refreshes every 30s)[/dim]"
|
|
633
|
-
)
|
|
634
|
-
|
|
635
|
-
return report
|
|
636
|
-
|
|
637
|
-
try:
|
|
638
|
-
asyncio.run(run_health_check())
|
|
639
|
-
except Exception as e:
|
|
640
|
-
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
641
|
-
raise typer.Exit(code=1)
|
|
516
|
+
@utilities_app.command("dashboard")
|
|
517
|
+
def utilities_dashboard():
|
|
518
|
+
"""Launch visual dashboard."""
|
|
519
|
+
subprocess.run([sys.executable, "-m", "empathy_os.cli", "dashboard"], check=False)
|
|
642
520
|
|
|
643
521
|
|
|
644
|
-
@
|
|
645
|
-
def
|
|
646
|
-
|
|
647
|
-
min_coverage: float = typer.Option(80.0, "--min-coverage", help="Minimum test coverage %"),
|
|
648
|
-
min_quality: float = typer.Option(7.0, "--min-quality", help="Minimum quality score (0-10)"),
|
|
649
|
-
max_critical: int = typer.Option(0, "--max-critical", help="Max critical issues allowed"),
|
|
650
|
-
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
522
|
+
@utilities_app.command("sync-claude")
|
|
523
|
+
def utilities_sync_claude(
|
|
524
|
+
source: str = typer.Option("patterns", "--source", "-s", help="Source to sync"),
|
|
651
525
|
):
|
|
652
|
-
"""
|
|
653
|
-
|
|
654
|
-
Runs 4 agents in parallel:
|
|
655
|
-
- Security Auditor (vulnerability scan)
|
|
656
|
-
- Test Coverage Analyzer (gap analysis)
|
|
657
|
-
- Code Quality Reviewer (best practices)
|
|
658
|
-
- Documentation Writer (completeness check)
|
|
659
|
-
"""
|
|
660
|
-
import asyncio
|
|
661
|
-
|
|
662
|
-
from empathy_os.workflows.orchestrated_release_prep import OrchestratedReleasePrepWorkflow
|
|
663
|
-
|
|
664
|
-
async def run_release_prep():
|
|
665
|
-
workflow = OrchestratedReleasePrepWorkflow(
|
|
666
|
-
quality_gates={
|
|
667
|
-
"min_coverage": min_coverage,
|
|
668
|
-
"min_quality_score": min_quality,
|
|
669
|
-
"max_critical_issues": max_critical,
|
|
670
|
-
}
|
|
671
|
-
)
|
|
672
|
-
report = await workflow.execute(path=str(project_root))
|
|
673
|
-
|
|
674
|
-
if json_output:
|
|
675
|
-
import json
|
|
676
|
-
|
|
677
|
-
console.print(json.dumps(report.to_dict(), indent=2))
|
|
678
|
-
else:
|
|
679
|
-
console.print("\n[bold cyan]📋 RELEASE PREPARATION REPORT[/bold cyan]")
|
|
680
|
-
console.print("=" * 60)
|
|
681
|
-
|
|
682
|
-
approval_color = "green" if report.approved else "red"
|
|
683
|
-
approval_emoji = "✅" if report.approved else "❌"
|
|
684
|
-
console.print(
|
|
685
|
-
f"\n[bold {approval_color}]{approval_emoji} {'APPROVED' if report.approved else 'NOT APPROVED'}[/bold {approval_color}]"
|
|
686
|
-
)
|
|
687
|
-
console.print(f"[dim]Confidence: {report.confidence}[/dim]")
|
|
688
|
-
console.print(f"[dim]Duration: {report.total_duration:.2f}s[/dim]")
|
|
689
|
-
|
|
690
|
-
# Quality gates
|
|
691
|
-
console.print("\n[bold]Quality Gates:[/bold]")
|
|
692
|
-
for gate in report.quality_gates:
|
|
693
|
-
gate_emoji = "✅" if gate.passed else "❌"
|
|
694
|
-
console.print(
|
|
695
|
-
f" {gate_emoji} {gate.name}: {gate.actual:.1f} (threshold: {gate.threshold:.1f})"
|
|
696
|
-
)
|
|
697
|
-
|
|
698
|
-
# Blockers
|
|
699
|
-
if report.blockers:
|
|
700
|
-
console.print("\n[bold red]🚫 Blockers:[/bold red]")
|
|
701
|
-
for blocker in report.blockers:
|
|
702
|
-
console.print(f" • {blocker}")
|
|
526
|
+
"""Sync patterns to Claude Code memory."""
|
|
527
|
+
subprocess.run(["empathy-sync-claude", "--source", source], check=False)
|
|
703
528
|
|
|
704
|
-
# Warnings
|
|
705
|
-
if report.warnings:
|
|
706
|
-
console.print("\n[bold yellow]⚠️ Warnings:[/bold yellow]")
|
|
707
|
-
for warning in report.warnings:
|
|
708
|
-
console.print(f" • {warning}")
|
|
709
529
|
|
|
710
|
-
|
|
530
|
+
@utilities_app.command("costs")
|
|
531
|
+
def utilities_costs():
|
|
532
|
+
"""View API cost tracking."""
|
|
533
|
+
subprocess.run([sys.executable, "-m", "empathy_os.cli", "costs"], check=False)
|
|
711
534
|
|
|
712
|
-
return report
|
|
713
535
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
raise typer.Exit(code=1)
|
|
536
|
+
@utilities_app.command("status")
|
|
537
|
+
def utilities_status():
|
|
538
|
+
"""What needs attention now."""
|
|
539
|
+
subprocess.run([sys.executable, "-m", "empathy_os.cli", "status"], check=False)
|
|
719
540
|
|
|
720
541
|
|
|
721
|
-
@
|
|
722
|
-
def
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
542
|
+
@utilities_app.command("scan")
|
|
543
|
+
def utilities_scan(
|
|
544
|
+
path: Path = typer.Argument(Path("."), help="Path to scan"),
|
|
545
|
+
scan_type: str = typer.Option("all", "--type", "-t", help="Scan type: security, performance, or all"),
|
|
726
546
|
):
|
|
727
|
-
"""
|
|
547
|
+
"""Scan codebase for issues.
|
|
728
548
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
3. Test Validator → Verify coverage
|
|
549
|
+
Examples:
|
|
550
|
+
empathy utility scan .
|
|
551
|
+
empathy utility scan ./src --type security
|
|
733
552
|
"""
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
from empathy_os.workflows.test_coverage_boost import TestCoverageBoostWorkflow
|
|
553
|
+
# Delegate to main scan command
|
|
554
|
+
scan_command(scan_type, path)
|
|
737
555
|
|
|
738
|
-
async def run_test_coverage():
|
|
739
|
-
workflow = TestCoverageBoostWorkflow(target_coverage=target)
|
|
740
|
-
report = await workflow.execute(project_root=str(project_root))
|
|
741
|
-
|
|
742
|
-
if json_output:
|
|
743
|
-
import json
|
|
744
|
-
|
|
745
|
-
console.print(json.dumps(report.to_dict(), indent=2))
|
|
746
|
-
else:
|
|
747
|
-
console.print("\n[bold cyan]🧪 TEST COVERAGE BOOST REPORT[/bold cyan]")
|
|
748
|
-
console.print("=" * 60)
|
|
749
556
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
f"\n[bold {success_color}]{success_emoji} {'SUCCESS' if report.success else 'FAILED'}[/bold {success_color}]"
|
|
754
|
-
)
|
|
755
|
-
console.print(f"[dim]Initial: {report.initial_coverage:.1f}%[/dim]")
|
|
756
|
-
console.print(f"[dim]Final: {report.final_coverage:.1f}%[/dim]")
|
|
757
|
-
console.print(f"[dim]Improvement: +{report.improvement:.1f}%[/dim]")
|
|
758
|
-
console.print(f"[dim]Duration: {report.total_duration:.2f}s[/dim]")
|
|
759
|
-
|
|
760
|
-
# Stage results
|
|
761
|
-
console.print("\n[bold]Stage Results:[/bold]")
|
|
762
|
-
for i, stage in enumerate(report.stage_results, 1):
|
|
763
|
-
stage_emoji = "✅" if stage["success"] else "❌"
|
|
764
|
-
console.print(f" {stage_emoji} Stage {i}: {stage.get('description', 'N/A')}")
|
|
765
|
-
|
|
766
|
-
console.print("\n" + "=" * 60)
|
|
557
|
+
# =============================================================================
|
|
558
|
+
# CHEATSHEET (top-level alias for convenience)
|
|
559
|
+
# =============================================================================
|
|
767
560
|
|
|
768
|
-
return report
|
|
769
561
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
562
|
+
@app.command("cheatsheet")
|
|
563
|
+
def cheatsheet():
|
|
564
|
+
"""Show quick reference for all commands."""
|
|
565
|
+
console.print(
|
|
566
|
+
Panel.fit(
|
|
567
|
+
CHEATSHEET_CONTENT,
|
|
568
|
+
title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
|
|
569
|
+
),
|
|
570
|
+
)
|
|
775
571
|
|
|
776
572
|
|
|
777
573
|
# =============================================================================
|
|
778
|
-
#
|
|
574
|
+
# ADDITIONAL COMMAND APPS (exported for cli/__init__.py)
|
|
575
|
+
# These provide structure for commands that will be migrated from legacy CLI
|
|
779
576
|
# =============================================================================
|
|
780
577
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
@telemetry_app.command("show")
|
|
786
|
-
def telemetry_show(
|
|
787
|
-
limit: int = typer.Option(20, "--limit", "-l", help="Number of entries to show"),
|
|
788
|
-
days: int | None = typer.Option(None, "--days", "-d", help="Only show last N days"),
|
|
789
|
-
):
|
|
790
|
-
"""Show recent LLM calls and usage stats."""
|
|
791
|
-
args = [sys.executable, "-m", "empathy_os.cli", "telemetry", "show", "--limit", str(limit)]
|
|
792
|
-
if days:
|
|
793
|
-
args.extend(["--days", str(days)])
|
|
794
|
-
subprocess.run(args, check=False)
|
|
578
|
+
# Workflow commands - run multi-model AI workflows
|
|
579
|
+
workflow_app = typer.Typer(help="Run multi-model AI workflows")
|
|
795
580
|
|
|
796
581
|
|
|
797
|
-
@
|
|
798
|
-
def
|
|
799
|
-
|
|
800
|
-
):
|
|
801
|
-
"""Calculate cost savings vs baseline (all PREMIUM)."""
|
|
582
|
+
@workflow_app.command("list")
|
|
583
|
+
def workflow_list():
|
|
584
|
+
"""List available workflows."""
|
|
802
585
|
subprocess.run(
|
|
803
|
-
[sys.executable, "-m", "empathy_os.cli", "
|
|
586
|
+
[sys.executable, "-m", "empathy_os.cli", "workflow", "list"],
|
|
804
587
|
check=False,
|
|
805
588
|
)
|
|
806
589
|
|
|
807
590
|
|
|
808
|
-
@
|
|
809
|
-
def
|
|
810
|
-
|
|
811
|
-
|
|
591
|
+
@workflow_app.command("run")
|
|
592
|
+
def workflow_run(
|
|
593
|
+
name: str = typer.Argument(..., help="Workflow name"),
|
|
594
|
+
input_json: str = typer.Option("{}", "--input", "-i", help="Input JSON"),
|
|
595
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="JSON output"),
|
|
812
596
|
):
|
|
813
|
-
"""
|
|
597
|
+
"""Run a workflow by name."""
|
|
598
|
+
args = [sys.executable, "-m", "empathy_os.cli", "workflow", "run", name, "--input", input_json]
|
|
599
|
+
if json_output:
|
|
600
|
+
args.append("--json")
|
|
601
|
+
subprocess.run(args, check=False)
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
@workflow_app.command("describe")
|
|
605
|
+
def workflow_describe(name: str = typer.Argument(..., help="Workflow name")):
|
|
606
|
+
"""Describe a workflow."""
|
|
814
607
|
subprocess.run(
|
|
815
|
-
[
|
|
816
|
-
sys.executable,
|
|
817
|
-
"-m",
|
|
818
|
-
"empathy_os.cli",
|
|
819
|
-
"telemetry",
|
|
820
|
-
"compare",
|
|
821
|
-
"--period1",
|
|
822
|
-
str(period1),
|
|
823
|
-
"--period2",
|
|
824
|
-
str(period2),
|
|
825
|
-
],
|
|
608
|
+
[sys.executable, "-m", "empathy_os.cli", "workflow", "describe", name],
|
|
826
609
|
check=False,
|
|
827
610
|
)
|
|
828
611
|
|
|
829
612
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
format_type: str = typer.Option("json", "--format", "-f", help="Export format (json, csv)"),
|
|
833
|
-
output: Path | None = typer.Option(None, "--output", "-o", help="Output file path"),
|
|
834
|
-
days: int | None = typer.Option(None, "--days", "-d", help="Only export last N days"),
|
|
835
|
-
):
|
|
836
|
-
"""Export telemetry data to JSON or CSV."""
|
|
837
|
-
args = [sys.executable, "-m", "empathy_os.cli", "telemetry", "export", "--format", format_type]
|
|
838
|
-
if output:
|
|
839
|
-
args.extend(["--output", str(output)])
|
|
840
|
-
if days:
|
|
841
|
-
args.extend(["--days", str(days)])
|
|
842
|
-
subprocess.run(args, check=False)
|
|
613
|
+
# Orchestrate commands - advanced orchestration features
|
|
614
|
+
orchestrate_app = typer.Typer(help="Advanced workflow orchestration")
|
|
843
615
|
|
|
844
616
|
|
|
845
|
-
@
|
|
846
|
-
def
|
|
847
|
-
|
|
617
|
+
@orchestrate_app.command("run")
|
|
618
|
+
def orchestrate_run(
|
|
619
|
+
task: str = typer.Argument(..., help="Task description"),
|
|
620
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Path to analyze"),
|
|
848
621
|
):
|
|
849
|
-
"""
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
622
|
+
"""Run orchestrated task."""
|
|
623
|
+
task_json = json.dumps({"task": task, "path": str(path)})
|
|
624
|
+
subprocess.run(
|
|
625
|
+
[sys.executable, "-m", "empathy_os.cli", "orchestrate", "--input", task_json],
|
|
626
|
+
check=False,
|
|
627
|
+
)
|
|
855
628
|
|
|
856
|
-
# =============================================================================
|
|
857
|
-
# SERVICE SUBCOMMAND GROUP (Cross-Session Communication)
|
|
858
|
-
# =============================================================================
|
|
859
629
|
|
|
860
|
-
|
|
861
|
-
|
|
630
|
+
# Telemetry commands - LLM usage tracking
|
|
631
|
+
telemetry_app = typer.Typer(help="LLM usage telemetry and cost tracking")
|
|
862
632
|
|
|
863
633
|
|
|
864
|
-
@
|
|
865
|
-
def
|
|
866
|
-
|
|
634
|
+
@telemetry_app.command("show")
|
|
635
|
+
def telemetry_show(
|
|
636
|
+
limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
|
|
867
637
|
):
|
|
868
|
-
"""
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
638
|
+
"""Show telemetry data."""
|
|
639
|
+
subprocess.run(
|
|
640
|
+
[sys.executable, "-m", "empathy_os.cli", "telemetry", "show", "--limit", str(limit)],
|
|
641
|
+
check=False,
|
|
642
|
+
)
|
|
872
643
|
|
|
873
|
-
Requires Redis to be running (empathy memory start).
|
|
874
|
-
"""
|
|
875
|
-
from empathy_os.redis_config import get_redis_memory
|
|
876
644
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
service = BackgroundService(memory, auto_start_on_connect=daemon)
|
|
889
|
-
|
|
890
|
-
if service.start():
|
|
891
|
-
console.print("[bold green]✅ Cross-session service started[/bold green]")
|
|
892
|
-
status = service.get_status()
|
|
893
|
-
console.print(f"[dim]Agent ID: {status['agent_id']}[/dim]")
|
|
894
|
-
console.print(f"[dim]Active sessions: {status['active_sessions']}[/dim]")
|
|
895
|
-
|
|
896
|
-
if daemon:
|
|
897
|
-
console.print("[dim]Running in daemon mode (press Ctrl+C to stop)[/dim]")
|
|
898
|
-
try:
|
|
899
|
-
import time
|
|
900
|
-
while service.is_running:
|
|
901
|
-
time.sleep(1)
|
|
902
|
-
except KeyboardInterrupt:
|
|
903
|
-
service.stop()
|
|
904
|
-
console.print("\n[dim]Service stopped[/dim]")
|
|
905
|
-
else:
|
|
906
|
-
console.print("[yellow]⚠️ Service already running (or couldn't acquire lock)[/yellow]")
|
|
907
|
-
console.print("[dim]Use 'empathy service status' to check[/dim]")
|
|
908
|
-
|
|
909
|
-
except Exception as e:
|
|
910
|
-
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
911
|
-
raise typer.Exit(code=1)
|
|
645
|
+
@telemetry_app.command("export")
|
|
646
|
+
def telemetry_export(
|
|
647
|
+
output: Path = typer.Argument(..., help="Output file path"),
|
|
648
|
+
format_type: str = typer.Option("json", "--format", "-f", help="Output format: json, csv"),
|
|
649
|
+
):
|
|
650
|
+
"""Export telemetry data."""
|
|
651
|
+
subprocess.run(
|
|
652
|
+
[sys.executable, "-m", "empathy_os.cli", "telemetry", "export", str(output), "--format", format_type],
|
|
653
|
+
check=False,
|
|
654
|
+
)
|
|
912
655
|
|
|
913
656
|
|
|
914
|
-
@
|
|
915
|
-
def
|
|
916
|
-
"""
|
|
917
|
-
|
|
657
|
+
@telemetry_app.command("reset")
|
|
658
|
+
def telemetry_reset():
|
|
659
|
+
"""Reset telemetry data."""
|
|
660
|
+
subprocess.run(
|
|
661
|
+
[sys.executable, "-m", "empathy_os.cli", "telemetry", "reset"],
|
|
662
|
+
check=False,
|
|
663
|
+
)
|
|
918
664
|
|
|
919
|
-
try:
|
|
920
|
-
memory = get_redis_memory()
|
|
921
|
-
|
|
922
|
-
if memory.use_mock:
|
|
923
|
-
console.print("[yellow]No service to stop (mock mode)[/yellow]")
|
|
924
|
-
return
|
|
925
|
-
|
|
926
|
-
# Check if service is running and signal it to stop
|
|
927
|
-
client = memory._client
|
|
928
|
-
if client:
|
|
929
|
-
from empathy_os.memory.cross_session import KEY_SERVICE_LOCK
|
|
930
|
-
|
|
931
|
-
lock_holder = client.get(KEY_SERVICE_LOCK)
|
|
932
|
-
if lock_holder:
|
|
933
|
-
client.delete(KEY_SERVICE_LOCK)
|
|
934
|
-
console.print("[green]✅ Service stop signal sent[/green]")
|
|
935
|
-
else:
|
|
936
|
-
console.print("[dim]No service currently running[/dim]")
|
|
937
|
-
else:
|
|
938
|
-
console.print("[yellow]Redis not connected[/yellow]")
|
|
939
665
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
raise typer.Exit(code=1)
|
|
666
|
+
# Service commands - background services
|
|
667
|
+
service_app = typer.Typer(help="Background services management")
|
|
943
668
|
|
|
944
669
|
|
|
945
670
|
@service_app.command("status")
|
|
946
|
-
def service_status(
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
671
|
+
def service_status():
|
|
672
|
+
"""Check service status."""
|
|
673
|
+
# Check Redis status via memory control panel
|
|
674
|
+
subprocess.run(
|
|
675
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "status"],
|
|
676
|
+
check=False,
|
|
677
|
+
)
|
|
951
678
|
|
|
952
|
-
from empathy_os.redis_config import get_redis_memory
|
|
953
679
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
"message": "Cross-session requires Redis",
|
|
962
|
-
}
|
|
963
|
-
if json_output:
|
|
964
|
-
console.print(json_mod.dumps(status, indent=2))
|
|
965
|
-
else:
|
|
966
|
-
console.print("[yellow]⚠️ Mock mode - cross-session not available[/yellow]")
|
|
967
|
-
console.print("[dim]Start Redis: empathy memory start[/dim]")
|
|
968
|
-
return
|
|
969
|
-
|
|
970
|
-
from empathy_os.memory.cross_session import (
|
|
971
|
-
KEY_ACTIVE_AGENTS,
|
|
972
|
-
KEY_SERVICE_HEARTBEAT,
|
|
973
|
-
KEY_SERVICE_LOCK,
|
|
974
|
-
SessionInfo,
|
|
680
|
+
@service_app.command("start")
|
|
681
|
+
def service_start(service_name: str = typer.Argument("all", help="Service to start")):
|
|
682
|
+
"""Start background services."""
|
|
683
|
+
if service_name in ("all", "redis"):
|
|
684
|
+
subprocess.run(
|
|
685
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "start"],
|
|
686
|
+
check=False,
|
|
975
687
|
)
|
|
976
688
|
|
|
977
|
-
client = memory._client
|
|
978
|
-
if not client:
|
|
979
|
-
console.print("[red]Redis not connected[/red]")
|
|
980
|
-
raise typer.Exit(code=1)
|
|
981
|
-
|
|
982
|
-
# Check service status
|
|
983
|
-
service_lock = client.get(KEY_SERVICE_LOCK)
|
|
984
|
-
service_heartbeat = client.get(KEY_SERVICE_HEARTBEAT)
|
|
985
|
-
|
|
986
|
-
# Get active sessions
|
|
987
|
-
all_agents = client.hgetall(KEY_ACTIVE_AGENTS)
|
|
988
|
-
sessions = []
|
|
989
|
-
for agent_id, data in all_agents.items():
|
|
990
|
-
try:
|
|
991
|
-
if isinstance(agent_id, bytes):
|
|
992
|
-
agent_id = agent_id.decode()
|
|
993
|
-
if isinstance(data, bytes):
|
|
994
|
-
data = data.decode()
|
|
995
|
-
info = SessionInfo.from_dict(json_mod.loads(data))
|
|
996
|
-
if not info.is_stale:
|
|
997
|
-
sessions.append(info.to_dict())
|
|
998
|
-
except (json_mod.JSONDecodeError, KeyError, ValueError):
|
|
999
|
-
pass
|
|
1000
|
-
|
|
1001
|
-
status = {
|
|
1002
|
-
"mode": "redis",
|
|
1003
|
-
"cross_session_available": True,
|
|
1004
|
-
"service_running": bool(service_lock),
|
|
1005
|
-
"service_pid": service_lock.decode() if isinstance(service_lock, bytes) else service_lock,
|
|
1006
|
-
"last_heartbeat": service_heartbeat.decode() if isinstance(service_heartbeat, bytes) else service_heartbeat,
|
|
1007
|
-
"active_sessions": len(sessions),
|
|
1008
|
-
"sessions": sessions,
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
if json_output:
|
|
1012
|
-
console.print(json_mod.dumps(status, indent=2))
|
|
1013
|
-
else:
|
|
1014
|
-
console.print()
|
|
1015
|
-
console.print("[bold cyan]CROSS-SESSION SERVICE STATUS[/bold cyan]")
|
|
1016
|
-
console.print("=" * 50)
|
|
1017
|
-
console.print()
|
|
1018
|
-
|
|
1019
|
-
if status["service_running"]:
|
|
1020
|
-
console.print("[green]● Service Running[/green]")
|
|
1021
|
-
console.print(f"[dim] PID: {status['service_pid']}[/dim]")
|
|
1022
|
-
if status["last_heartbeat"]:
|
|
1023
|
-
console.print(f"[dim] Last heartbeat: {status['last_heartbeat']}[/dim]")
|
|
1024
|
-
else:
|
|
1025
|
-
console.print("[yellow]○ Service Not Running[/yellow]")
|
|
1026
|
-
console.print("[dim] Start with: empathy service start[/dim]")
|
|
1027
|
-
|
|
1028
|
-
console.print()
|
|
1029
|
-
console.print(f"[bold]Active Sessions:[/bold] {status['active_sessions']}")
|
|
1030
|
-
|
|
1031
|
-
if sessions:
|
|
1032
|
-
console.print()
|
|
1033
|
-
for session in sessions:
|
|
1034
|
-
session_type = session.get("session_type", "unknown")
|
|
1035
|
-
agent_id = session.get("agent_id", "unknown")
|
|
1036
|
-
tier = session.get("access_tier", "unknown")
|
|
1037
|
-
emoji = "🤖" if session_type == "claude" else "⚙️" if session_type == "service" else "👷"
|
|
1038
|
-
console.print(f" {emoji} {agent_id}")
|
|
1039
|
-
console.print(f" [dim]Type: {session_type} | Tier: {tier}[/dim]")
|
|
1040
|
-
|
|
1041
|
-
console.print()
|
|
1042
|
-
console.print("=" * 50)
|
|
1043
|
-
|
|
1044
|
-
except Exception as e:
|
|
1045
|
-
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
1046
|
-
raise typer.Exit(code=1)
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
@service_app.command("sessions")
|
|
1050
|
-
def service_sessions():
|
|
1051
|
-
"""List all active cross-session agents."""
|
|
1052
|
-
import json as json_mod
|
|
1053
|
-
|
|
1054
|
-
from empathy_os.redis_config import get_redis_memory
|
|
1055
|
-
|
|
1056
|
-
try:
|
|
1057
|
-
memory = get_redis_memory()
|
|
1058
|
-
|
|
1059
|
-
if memory.use_mock:
|
|
1060
|
-
console.print("[yellow]No sessions (mock mode)[/yellow]")
|
|
1061
|
-
return
|
|
1062
|
-
|
|
1063
|
-
from empathy_os.memory.cross_session import KEY_ACTIVE_AGENTS, SessionInfo
|
|
1064
|
-
|
|
1065
|
-
client = memory._client
|
|
1066
|
-
if not client:
|
|
1067
|
-
console.print("[red]Redis not connected[/red]")
|
|
1068
|
-
return
|
|
1069
|
-
|
|
1070
|
-
all_agents = client.hgetall(KEY_ACTIVE_AGENTS)
|
|
1071
|
-
|
|
1072
|
-
if not all_agents:
|
|
1073
|
-
console.print("[dim]No active sessions[/dim]")
|
|
1074
|
-
return
|
|
1075
|
-
|
|
1076
|
-
console.print()
|
|
1077
|
-
console.print("[bold]Active Cross-Session Agents[/bold]")
|
|
1078
|
-
console.print("-" * 60)
|
|
1079
|
-
|
|
1080
|
-
for agent_id, data in all_agents.items():
|
|
1081
|
-
try:
|
|
1082
|
-
if isinstance(agent_id, bytes):
|
|
1083
|
-
agent_id = agent_id.decode()
|
|
1084
|
-
if isinstance(data, bytes):
|
|
1085
|
-
data = data.decode()
|
|
1086
|
-
|
|
1087
|
-
info = SessionInfo.from_dict(json_mod.loads(data))
|
|
1088
|
-
|
|
1089
|
-
if info.is_stale:
|
|
1090
|
-
status_str = "[red]STALE[/red]"
|
|
1091
|
-
else:
|
|
1092
|
-
status_str = "[green]ACTIVE[/green]"
|
|
1093
|
-
|
|
1094
|
-
console.print(f"\n{agent_id}")
|
|
1095
|
-
console.print(f" Status: {status_str}")
|
|
1096
|
-
console.print(f" Type: {info.session_type.value}")
|
|
1097
|
-
console.print(f" Tier: {info.access_tier.name}")
|
|
1098
|
-
console.print(f" Started: {info.started_at.isoformat()}")
|
|
1099
|
-
console.print(f" Last heartbeat: {info.last_heartbeat.isoformat()}")
|
|
1100
|
-
if info.capabilities:
|
|
1101
|
-
console.print(f" Capabilities: {', '.join(info.capabilities)}")
|
|
1102
|
-
|
|
1103
|
-
except (json_mod.JSONDecodeError, KeyError, ValueError) as e:
|
|
1104
|
-
console.print(f"\n{agent_id}: [red]Invalid data[/red] - {e}")
|
|
1105
|
-
|
|
1106
|
-
console.print()
|
|
1107
|
-
|
|
1108
|
-
except Exception as e:
|
|
1109
|
-
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
1110
|
-
raise typer.Exit(code=1)
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
# =============================================================================
|
|
1114
|
-
# META-WORKFLOW SUBCOMMAND GROUP
|
|
1115
|
-
# =============================================================================
|
|
1116
|
-
|
|
1117
|
-
try:
|
|
1118
|
-
from empathy_os.meta_workflows.cli_meta_workflows import meta_workflow_app
|
|
1119
|
-
app.add_typer(meta_workflow_app, name="meta-workflow")
|
|
1120
|
-
except ImportError as e:
|
|
1121
|
-
# Meta-workflow system is optional/experimental
|
|
1122
|
-
import logging
|
|
1123
|
-
logging.getLogger(__name__).debug(f"Meta-workflow CLI not available: {e}")
|
|
1124
689
|
|
|
690
|
+
@service_app.command("stop")
|
|
691
|
+
def service_stop(service_name: str = typer.Argument("all", help="Service to stop")):
|
|
692
|
+
"""Stop background services."""
|
|
693
|
+
if service_name in ("all", "redis"):
|
|
694
|
+
subprocess.run(
|
|
695
|
+
[sys.executable, "-m", "empathy_os.memory.control_panel", "stop"],
|
|
696
|
+
check=False,
|
|
697
|
+
)
|
|
1125
698
|
|
|
1126
|
-
# =============================================================================
|
|
1127
|
-
# PROGRESSIVE WORKFLOW SUBCOMMAND GROUP
|
|
1128
|
-
# =============================================================================
|
|
1129
699
|
|
|
1130
|
-
|
|
1131
|
-
|
|
700
|
+
# Progressive commands - progressive test generation
|
|
701
|
+
progressive_app = typer.Typer(help="Progressive test generation")
|
|
1132
702
|
|
|
1133
703
|
|
|
1134
704
|
@progressive_app.command("list")
|
|
1135
|
-
def progressive_list(
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
"
|
|
1139
|
-
|
|
1140
|
-
)
|
|
1141
|
-
):
|
|
1142
|
-
"""List all saved progressive workflow results."""
|
|
1143
|
-
from argparse import Namespace
|
|
1144
|
-
|
|
1145
|
-
from empathy_os.workflows.progressive.cli import cmd_list_results
|
|
1146
|
-
|
|
1147
|
-
args = Namespace(storage_path=storage_path)
|
|
1148
|
-
cmd_list_results(args)
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
@progressive_app.command("show")
|
|
1152
|
-
def progressive_show(
|
|
1153
|
-
task_id: str = typer.Argument(..., help="Task ID to display"),
|
|
1154
|
-
storage_path: str = typer.Option(
|
|
1155
|
-
None,
|
|
1156
|
-
"--storage-path",
|
|
1157
|
-
help="Path to progressive workflow storage (default: .empathy/progressive_runs)",
|
|
1158
|
-
),
|
|
1159
|
-
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
|
|
1160
|
-
):
|
|
1161
|
-
"""Show detailed report for a specific task."""
|
|
1162
|
-
from argparse import Namespace
|
|
705
|
+
def progressive_list():
|
|
706
|
+
"""List progressive test results."""
|
|
707
|
+
subprocess.run(
|
|
708
|
+
[sys.executable, "-m", "empathy_os.cli", "progressive", "list"],
|
|
709
|
+
check=False,
|
|
710
|
+
)
|
|
1163
711
|
|
|
1164
|
-
from empathy_os.workflows.progressive.cli import cmd_show_report
|
|
1165
712
|
|
|
1166
|
-
|
|
1167
|
-
|
|
713
|
+
@progressive_app.command("report")
|
|
714
|
+
def progressive_report(session_id: str = typer.Argument(..., help="Session ID")):
|
|
715
|
+
"""Show progressive test report."""
|
|
716
|
+
subprocess.run(
|
|
717
|
+
[sys.executable, "-m", "empathy_os.cli", "progressive", "report", session_id],
|
|
718
|
+
check=False,
|
|
719
|
+
)
|
|
1168
720
|
|
|
1169
721
|
|
|
1170
722
|
@progressive_app.command("analytics")
|
|
1171
|
-
def progressive_analytics(
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
"
|
|
1175
|
-
|
|
1176
|
-
),
|
|
1177
|
-
json_output: bool = typer.Option(False, "--json", help="Output in JSON format"),
|
|
1178
|
-
):
|
|
1179
|
-
"""Show cost optimization analytics."""
|
|
1180
|
-
from argparse import Namespace
|
|
1181
|
-
|
|
1182
|
-
from empathy_os.workflows.progressive.cli import cmd_analytics
|
|
1183
|
-
|
|
1184
|
-
args = Namespace(storage_path=storage_path, json=json_output)
|
|
1185
|
-
cmd_analytics(args)
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
@progressive_app.command("cleanup")
|
|
1189
|
-
def progressive_cleanup(
|
|
1190
|
-
storage_path: str = typer.Option(
|
|
1191
|
-
None,
|
|
1192
|
-
"--storage-path",
|
|
1193
|
-
help="Path to progressive workflow storage (default: .empathy/progressive_runs)",
|
|
1194
|
-
),
|
|
1195
|
-
retention_days: int = typer.Option(
|
|
1196
|
-
30, "--retention-days", help="Number of days to retain results (default: 30)"
|
|
1197
|
-
),
|
|
1198
|
-
dry_run: bool = typer.Option(
|
|
1199
|
-
False,
|
|
1200
|
-
"--dry-run",
|
|
1201
|
-
help="Show what would be deleted without actually deleting",
|
|
1202
|
-
),
|
|
1203
|
-
):
|
|
1204
|
-
"""Clean up old progressive workflow results."""
|
|
1205
|
-
from argparse import Namespace
|
|
1206
|
-
|
|
1207
|
-
from empathy_os.workflows.progressive.cli import cmd_cleanup
|
|
1208
|
-
|
|
1209
|
-
args = Namespace(
|
|
1210
|
-
storage_path=storage_path, retention_days=retention_days, dry_run=dry_run
|
|
723
|
+
def progressive_analytics():
|
|
724
|
+
"""Show progressive test analytics."""
|
|
725
|
+
subprocess.run(
|
|
726
|
+
[sys.executable, "-m", "empathy_os.cli", "progressive", "analytics"],
|
|
727
|
+
check=False,
|
|
1211
728
|
)
|
|
1212
|
-
cmd_cleanup(args)
|
|
1213
729
|
|
|
1214
730
|
|
|
1215
|
-
#
|
|
1216
|
-
|
|
1217
|
-
# =============================================================================
|
|
1218
|
-
|
|
1219
|
-
tier_app = typer.Typer(help="Intelligent tier recommendations for cascading workflows")
|
|
1220
|
-
app.add_typer(tier_app, name="tier")
|
|
731
|
+
# Tier commands - model tier management
|
|
732
|
+
tier_app = typer.Typer(help="Model tier configuration")
|
|
1221
733
|
|
|
1222
734
|
|
|
1223
735
|
@tier_app.command("recommend")
|
|
1224
736
|
def tier_recommend(
|
|
1225
|
-
|
|
1226
|
-
files: str = typer.Option(None, "--files", "-f", help="Comma-separated list of affected files"),
|
|
1227
|
-
complexity: int = typer.Option(None, "--complexity", "-c", help="Manual complexity hint 1-10"),
|
|
737
|
+
task: str = typer.Argument("code-review", help="Task type"),
|
|
1228
738
|
):
|
|
1229
|
-
"""Get
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
# Get recommendation
|
|
1235
|
-
result = recommender.recommend(
|
|
1236
|
-
bug_description=description,
|
|
1237
|
-
files_affected=files.split(",") if files else None,
|
|
1238
|
-
complexity_hint=complexity,
|
|
739
|
+
"""Get tier recommendation for a task."""
|
|
740
|
+
subprocess.run(
|
|
741
|
+
[sys.executable, "-m", "empathy_os.cli", "tier", "recommend", task],
|
|
742
|
+
check=False,
|
|
1239
743
|
)
|
|
1240
744
|
|
|
1241
|
-
# Display results
|
|
1242
|
-
console.print()
|
|
1243
|
-
console.print("=" * 60)
|
|
1244
|
-
console.print(" [bold]TIER RECOMMENDATION[/bold]")
|
|
1245
|
-
console.print("=" * 60)
|
|
1246
|
-
console.print()
|
|
1247
|
-
console.print(f" [dim]Bug/Task:[/dim] {description}")
|
|
1248
|
-
console.print()
|
|
1249
|
-
console.print(f" 📍 [bold]Recommended Tier:[/bold] {result.tier}")
|
|
1250
|
-
console.print(f" 🎯 [bold]Confidence:[/bold] {result.confidence * 100:.1f}%")
|
|
1251
|
-
console.print(f" 💰 [bold]Expected Cost:[/bold] ${result.expected_cost:.3f}")
|
|
1252
|
-
console.print(f" 🔄 [bold]Expected Attempts:[/bold] {result.expected_attempts:.1f}")
|
|
1253
|
-
console.print()
|
|
1254
|
-
console.print(" 📊 [bold]Reasoning:[/bold]")
|
|
1255
|
-
console.print(f" {result.reasoning}")
|
|
1256
|
-
console.print()
|
|
1257
|
-
|
|
1258
|
-
if result.fallback_used:
|
|
1259
|
-
console.print(" ⚠️ [yellow]No historical data - using conservative default[/yellow]")
|
|
1260
|
-
console.print()
|
|
1261
|
-
console.print(" 💡 [dim]Tip: As more patterns are collected, recommendations[/dim]")
|
|
1262
|
-
console.print(" [dim]will become more accurate and personalized.[/dim]")
|
|
1263
|
-
else:
|
|
1264
|
-
console.print(f" ✅ Based on {result.similar_patterns_count} similar patterns")
|
|
1265
|
-
|
|
1266
|
-
console.print()
|
|
1267
|
-
console.print("=" * 60)
|
|
1268
|
-
console.print()
|
|
1269
|
-
|
|
1270
745
|
|
|
1271
746
|
@tier_app.command("stats")
|
|
1272
747
|
def tier_stats():
|
|
1273
|
-
"""Show tier
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
stats = recommender.get_stats()
|
|
1278
|
-
|
|
1279
|
-
if stats.get("total_patterns") == 0:
|
|
1280
|
-
console.print()
|
|
1281
|
-
console.print(" [yellow]No patterns loaded yet.[/yellow]")
|
|
1282
|
-
console.print()
|
|
1283
|
-
console.print(" 💡 [dim]Patterns are collected automatically as you use")
|
|
1284
|
-
console.print(" cascading workflows. Run a few workflows first.[/dim]")
|
|
1285
|
-
console.print()
|
|
1286
|
-
return
|
|
1287
|
-
|
|
1288
|
-
# Display statistics
|
|
1289
|
-
console.print()
|
|
1290
|
-
console.print("=" * 60)
|
|
1291
|
-
console.print(" [bold]TIER PATTERN LEARNING STATS[/bold]")
|
|
1292
|
-
console.print("=" * 60)
|
|
1293
|
-
console.print()
|
|
1294
|
-
console.print(f" [bold]Total Patterns:[/bold] {stats['total_patterns']}")
|
|
1295
|
-
console.print(f" [bold]Avg Savings:[/bold] {stats['avg_savings_percent']}%")
|
|
1296
|
-
console.print()
|
|
1297
|
-
console.print(" [bold]TIER DISTRIBUTION[/bold]")
|
|
1298
|
-
console.print(" " + "-" * 40)
|
|
1299
|
-
|
|
1300
|
-
tier_dist = stats["patterns_by_tier"]
|
|
1301
|
-
total = stats["total_patterns"]
|
|
1302
|
-
max_bar_width = 20
|
|
1303
|
-
|
|
1304
|
-
for tier in ["CHEAP", "CAPABLE", "PREMIUM"]:
|
|
1305
|
-
count = tier_dist.get(tier, 0)
|
|
1306
|
-
percent = (count / total * 100) if total > 0 else 0
|
|
1307
|
-
bar_width = int(percent / 100 * max_bar_width)
|
|
1308
|
-
bar = "█" * bar_width
|
|
1309
|
-
console.print(f" {tier:<12} {count:>2} ({percent:>5.1f}%) {bar}")
|
|
1310
|
-
|
|
1311
|
-
console.print()
|
|
1312
|
-
console.print(" [bold]BUG TYPE DISTRIBUTION[/bold]")
|
|
1313
|
-
console.print(" " + "-" * 40)
|
|
1314
|
-
|
|
1315
|
-
for bug_type, count in sorted(
|
|
1316
|
-
stats["bug_type_distribution"].items(), key=lambda x: x[1], reverse=True
|
|
1317
|
-
):
|
|
1318
|
-
percent = (count / total * 100) if total > 0 else 0
|
|
1319
|
-
console.print(f" {bug_type:<20} {count:>2} ({percent:>5.1f}%)")
|
|
1320
|
-
|
|
1321
|
-
console.print()
|
|
1322
|
-
console.print("=" * 60)
|
|
1323
|
-
console.print()
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
# =============================================================================
|
|
1327
|
-
# UTILITY COMMANDS
|
|
1328
|
-
# =============================================================================
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
@app.command("cheatsheet")
|
|
1332
|
-
def cheatsheet():
|
|
1333
|
-
"""Show quick reference for all commands."""
|
|
1334
|
-
console.print(
|
|
1335
|
-
Panel.fit(
|
|
1336
|
-
"""[bold]Getting Started[/bold]
|
|
1337
|
-
empathy morning Start-of-day briefing
|
|
1338
|
-
empathy health Quick health check
|
|
1339
|
-
empathy ship Pre-commit validation
|
|
1340
|
-
empathy run Interactive REPL
|
|
1341
|
-
|
|
1342
|
-
[bold]Memory System[/bold]
|
|
1343
|
-
empathy memory status Check Redis & patterns
|
|
1344
|
-
empathy memory start Start Redis server
|
|
1345
|
-
empathy memory patterns List stored patterns
|
|
1346
|
-
|
|
1347
|
-
[bold]Cross-Session Service[/bold]
|
|
1348
|
-
empathy service start Start coordination service
|
|
1349
|
-
empathy service status Show service & sessions
|
|
1350
|
-
empathy service sessions List active agents
|
|
1351
|
-
|
|
1352
|
-
[bold]Provider Config[/bold]
|
|
1353
|
-
empathy provider Show current config
|
|
1354
|
-
empathy provider --set hybrid Use best-of-breed
|
|
1355
|
-
empathy provider registry List all models
|
|
1356
|
-
|
|
1357
|
-
[bold]Code Inspection[/bold]
|
|
1358
|
-
empathy scan . Scan for issues
|
|
1359
|
-
empathy inspect . Deep analysis (SARIF)
|
|
1360
|
-
empathy fix-all Auto-fix everything
|
|
1361
|
-
|
|
1362
|
-
[bold]Pattern Learning[/bold]
|
|
1363
|
-
empathy learn --analyze 20 Learn from commits
|
|
1364
|
-
empathy sync-claude Sync to Claude Code
|
|
1365
|
-
|
|
1366
|
-
[bold]Workflows[/bold]
|
|
1367
|
-
empathy workflow list Show available workflows
|
|
1368
|
-
empathy workflow run <name> Execute a workflow
|
|
1369
|
-
empathy workflow create <name> -p <patterns> Create workflow (12x faster)
|
|
1370
|
-
empathy workflow list-patterns List available patterns
|
|
1371
|
-
|
|
1372
|
-
[bold]Wizards[/bold]
|
|
1373
|
-
empathy wizard list Show available wizards
|
|
1374
|
-
empathy wizard run <name> Execute a wizard
|
|
1375
|
-
empathy wizard create <name> -d <domain> Create wizard (12x faster)
|
|
1376
|
-
empathy wizard list-patterns List available patterns
|
|
1377
|
-
|
|
1378
|
-
[bold]Usage Telemetry[/bold]
|
|
1379
|
-
empathy telemetry show View recent LLM calls & costs
|
|
1380
|
-
empathy telemetry savings Calculate cost savings (tier routing)
|
|
1381
|
-
empathy telemetry export Export usage data (JSON/CSV)""",
|
|
1382
|
-
title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
|
|
1383
|
-
),
|
|
748
|
+
"""Show tier usage statistics."""
|
|
749
|
+
subprocess.run(
|
|
750
|
+
[sys.executable, "-m", "empathy_os.cli", "tier", "stats"],
|
|
751
|
+
check=False,
|
|
1384
752
|
)
|
|
1385
753
|
|
|
1386
754
|
|
|
1387
|
-
@
|
|
1388
|
-
def
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
@app.command("init")
|
|
1400
|
-
def init():
|
|
1401
|
-
"""Create a new configuration file."""
|
|
1402
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "init"], check=False)
|
|
755
|
+
@tier_app.command("set")
|
|
756
|
+
def tier_set(
|
|
757
|
+
task: str = typer.Argument(..., help="Task type"),
|
|
758
|
+
tier_name: str = typer.Argument(..., help="Tier name: cheap, balanced, premium"),
|
|
759
|
+
):
|
|
760
|
+
"""Set tier for a task type."""
|
|
761
|
+
config = _load_tier_config()
|
|
762
|
+
config[task] = tier_name
|
|
763
|
+
_save_tier_config(config)
|
|
764
|
+
console.print(f"[green]Set {task} to use {tier_name} tier[/green]")
|
|
1403
765
|
|
|
1404
766
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
subprocess.run([sys.executable, "-m", "empathy_os.cli", "status"], check=False)
|
|
767
|
+
# =============================================================================
|
|
768
|
+
# ENTRY POINT
|
|
769
|
+
# =============================================================================
|
|
1409
770
|
|
|
1410
771
|
|
|
1411
772
|
def main():
|