empathy-framework 4.6.6__py3-none-any.whl → 4.7.0__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.
Files changed (247) hide show
  1. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/METADATA +7 -6
  2. empathy_framework-4.7.0.dist-info/RECORD +354 -0
  3. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/top_level.txt +0 -2
  4. empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
  5. empathy_llm_toolkit/agent_factory/__init__.py +6 -6
  6. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
  7. empathy_llm_toolkit/agents_md/__init__.py +22 -0
  8. empathy_llm_toolkit/agents_md/loader.py +218 -0
  9. empathy_llm_toolkit/agents_md/parser.py +271 -0
  10. empathy_llm_toolkit/agents_md/registry.py +307 -0
  11. empathy_llm_toolkit/commands/__init__.py +51 -0
  12. empathy_llm_toolkit/commands/context.py +375 -0
  13. empathy_llm_toolkit/commands/loader.py +301 -0
  14. empathy_llm_toolkit/commands/models.py +231 -0
  15. empathy_llm_toolkit/commands/parser.py +371 -0
  16. empathy_llm_toolkit/commands/registry.py +429 -0
  17. empathy_llm_toolkit/config/__init__.py +8 -8
  18. empathy_llm_toolkit/config/unified.py +3 -7
  19. empathy_llm_toolkit/context/__init__.py +22 -0
  20. empathy_llm_toolkit/context/compaction.py +455 -0
  21. empathy_llm_toolkit/context/manager.py +434 -0
  22. empathy_llm_toolkit/hooks/__init__.py +24 -0
  23. empathy_llm_toolkit/hooks/config.py +306 -0
  24. empathy_llm_toolkit/hooks/executor.py +289 -0
  25. empathy_llm_toolkit/hooks/registry.py +302 -0
  26. empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
  27. empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
  28. empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
  29. empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
  30. empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
  31. empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
  32. empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
  33. empathy_llm_toolkit/learning/__init__.py +30 -0
  34. empathy_llm_toolkit/learning/evaluator.py +438 -0
  35. empathy_llm_toolkit/learning/extractor.py +514 -0
  36. empathy_llm_toolkit/learning/storage.py +560 -0
  37. empathy_llm_toolkit/providers.py +4 -11
  38. empathy_llm_toolkit/security/__init__.py +17 -17
  39. empathy_llm_toolkit/utils/tokens.py +2 -5
  40. empathy_os/__init__.py +202 -70
  41. empathy_os/cache_monitor.py +5 -3
  42. empathy_os/cli/__init__.py +11 -55
  43. empathy_os/cli/__main__.py +29 -15
  44. empathy_os/cli/commands/inspection.py +21 -12
  45. empathy_os/cli/commands/memory.py +4 -12
  46. empathy_os/cli/commands/profiling.py +198 -0
  47. empathy_os/cli/commands/utilities.py +27 -7
  48. empathy_os/cli.py +28 -57
  49. empathy_os/cli_unified.py +525 -1164
  50. empathy_os/cost_tracker.py +9 -3
  51. empathy_os/dashboard/server.py +200 -2
  52. empathy_os/hot_reload/__init__.py +7 -7
  53. empathy_os/hot_reload/config.py +6 -7
  54. empathy_os/hot_reload/integration.py +35 -35
  55. empathy_os/hot_reload/reloader.py +57 -57
  56. empathy_os/hot_reload/watcher.py +28 -28
  57. empathy_os/hot_reload/websocket.py +2 -2
  58. empathy_os/memory/__init__.py +11 -4
  59. empathy_os/memory/claude_memory.py +1 -1
  60. empathy_os/memory/cross_session.py +8 -12
  61. empathy_os/memory/edges.py +6 -6
  62. empathy_os/memory/file_session.py +770 -0
  63. empathy_os/memory/graph.py +30 -30
  64. empathy_os/memory/nodes.py +6 -6
  65. empathy_os/memory/short_term.py +15 -9
  66. empathy_os/memory/unified.py +606 -140
  67. empathy_os/meta_workflows/agent_creator.py +3 -9
  68. empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
  69. empathy_os/meta_workflows/form_engine.py +6 -18
  70. empathy_os/meta_workflows/intent_detector.py +64 -24
  71. empathy_os/meta_workflows/models.py +3 -1
  72. empathy_os/meta_workflows/pattern_learner.py +13 -31
  73. empathy_os/meta_workflows/plan_generator.py +55 -47
  74. empathy_os/meta_workflows/session_context.py +2 -3
  75. empathy_os/meta_workflows/workflow.py +20 -51
  76. empathy_os/models/cli.py +2 -2
  77. empathy_os/models/tasks.py +1 -2
  78. empathy_os/models/telemetry.py +4 -1
  79. empathy_os/models/token_estimator.py +3 -1
  80. empathy_os/monitoring/alerts.py +938 -9
  81. empathy_os/monitoring/alerts_cli.py +346 -183
  82. empathy_os/orchestration/execution_strategies.py +12 -29
  83. empathy_os/orchestration/pattern_learner.py +20 -26
  84. empathy_os/orchestration/real_tools.py +6 -15
  85. empathy_os/platform_utils.py +2 -1
  86. empathy_os/plugins/__init__.py +2 -2
  87. empathy_os/plugins/base.py +64 -64
  88. empathy_os/plugins/registry.py +32 -32
  89. empathy_os/project_index/index.py +49 -15
  90. empathy_os/project_index/models.py +1 -2
  91. empathy_os/project_index/reports.py +1 -1
  92. empathy_os/project_index/scanner.py +1 -0
  93. empathy_os/redis_memory.py +10 -7
  94. empathy_os/resilience/__init__.py +1 -1
  95. empathy_os/resilience/health.py +10 -10
  96. empathy_os/routing/__init__.py +7 -7
  97. empathy_os/routing/chain_executor.py +37 -37
  98. empathy_os/routing/classifier.py +36 -36
  99. empathy_os/routing/smart_router.py +40 -40
  100. empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
  101. empathy_os/scaffolding/__init__.py +8 -8
  102. empathy_os/scaffolding/__main__.py +1 -1
  103. empathy_os/scaffolding/cli.py +28 -28
  104. empathy_os/socratic/__init__.py +3 -19
  105. empathy_os/socratic/ab_testing.py +25 -36
  106. empathy_os/socratic/blueprint.py +38 -38
  107. empathy_os/socratic/cli.py +34 -20
  108. empathy_os/socratic/collaboration.py +30 -28
  109. empathy_os/socratic/domain_templates.py +9 -1
  110. empathy_os/socratic/embeddings.py +17 -13
  111. empathy_os/socratic/engine.py +135 -70
  112. empathy_os/socratic/explainer.py +70 -60
  113. empathy_os/socratic/feedback.py +24 -19
  114. empathy_os/socratic/forms.py +15 -10
  115. empathy_os/socratic/generator.py +51 -35
  116. empathy_os/socratic/llm_analyzer.py +25 -23
  117. empathy_os/socratic/mcp_server.py +99 -159
  118. empathy_os/socratic/session.py +19 -13
  119. empathy_os/socratic/storage.py +98 -67
  120. empathy_os/socratic/success.py +38 -27
  121. empathy_os/socratic/visual_editor.py +51 -39
  122. empathy_os/socratic/web_ui.py +99 -66
  123. empathy_os/telemetry/cli.py +3 -1
  124. empathy_os/telemetry/usage_tracker.py +1 -3
  125. empathy_os/test_generator/__init__.py +3 -3
  126. empathy_os/test_generator/cli.py +28 -28
  127. empathy_os/test_generator/generator.py +64 -66
  128. empathy_os/test_generator/risk_analyzer.py +11 -11
  129. empathy_os/vscode_bridge.py +173 -0
  130. empathy_os/workflows/__init__.py +212 -120
  131. empathy_os/workflows/batch_processing.py +8 -24
  132. empathy_os/workflows/bug_predict.py +1 -1
  133. empathy_os/workflows/code_review.py +20 -5
  134. empathy_os/workflows/code_review_pipeline.py +13 -8
  135. empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
  136. empathy_os/workflows/manage_documentation.py +1 -0
  137. empathy_os/workflows/orchestrated_health_check.py +6 -11
  138. empathy_os/workflows/orchestrated_release_prep.py +3 -3
  139. empathy_os/workflows/pr_review.py +18 -10
  140. empathy_os/workflows/progressive/__init__.py +2 -12
  141. empathy_os/workflows/progressive/cli.py +14 -37
  142. empathy_os/workflows/progressive/core.py +12 -12
  143. empathy_os/workflows/progressive/orchestrator.py +166 -144
  144. empathy_os/workflows/progressive/reports.py +22 -31
  145. empathy_os/workflows/progressive/telemetry.py +8 -14
  146. empathy_os/workflows/progressive/test_gen.py +29 -48
  147. empathy_os/workflows/progressive/workflow.py +31 -70
  148. empathy_os/workflows/release_prep.py +21 -6
  149. empathy_os/workflows/release_prep_crew.py +1 -0
  150. empathy_os/workflows/secure_release.py +13 -6
  151. empathy_os/workflows/security_audit.py +8 -3
  152. empathy_os/workflows/test_coverage_boost_crew.py +3 -2
  153. empathy_os/workflows/test_maintenance_crew.py +1 -0
  154. empathy_os/workflows/test_runner.py +16 -12
  155. empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
  156. empathy_software_plugin/cli.py +0 -122
  157. coach_wizards/__init__.py +0 -45
  158. coach_wizards/accessibility_wizard.py +0 -91
  159. coach_wizards/api_wizard.py +0 -91
  160. coach_wizards/base_wizard.py +0 -209
  161. coach_wizards/cicd_wizard.py +0 -91
  162. coach_wizards/code_reviewer_README.md +0 -60
  163. coach_wizards/code_reviewer_wizard.py +0 -180
  164. coach_wizards/compliance_wizard.py +0 -91
  165. coach_wizards/database_wizard.py +0 -91
  166. coach_wizards/debugging_wizard.py +0 -91
  167. coach_wizards/documentation_wizard.py +0 -91
  168. coach_wizards/generate_wizards.py +0 -347
  169. coach_wizards/localization_wizard.py +0 -173
  170. coach_wizards/migration_wizard.py +0 -91
  171. coach_wizards/monitoring_wizard.py +0 -91
  172. coach_wizards/observability_wizard.py +0 -91
  173. coach_wizards/performance_wizard.py +0 -91
  174. coach_wizards/prompt_engineering_wizard.py +0 -661
  175. coach_wizards/refactoring_wizard.py +0 -91
  176. coach_wizards/scaling_wizard.py +0 -90
  177. coach_wizards/security_wizard.py +0 -92
  178. coach_wizards/testing_wizard.py +0 -91
  179. empathy_framework-4.6.6.dist-info/RECORD +0 -410
  180. empathy_llm_toolkit/wizards/__init__.py +0 -43
  181. empathy_llm_toolkit/wizards/base_wizard.py +0 -364
  182. empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
  183. empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
  184. empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
  185. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
  186. empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
  187. empathy_os/wizard_factory_cli.py +0 -170
  188. empathy_software_plugin/wizards/__init__.py +0 -42
  189. empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
  190. empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
  191. empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
  192. empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
  193. empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
  194. empathy_software_plugin/wizards/base_wizard.py +0 -288
  195. empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
  196. empathy_software_plugin/wizards/code_review_wizard.py +0 -604
  197. empathy_software_plugin/wizards/debugging/__init__.py +0 -50
  198. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
  199. empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
  200. empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
  201. empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
  202. empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
  203. empathy_software_plugin/wizards/debugging/verification.py +0 -369
  204. empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
  205. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
  206. empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
  207. empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
  208. empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
  209. empathy_software_plugin/wizards/performance/__init__.py +0 -9
  210. empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
  211. empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
  212. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
  213. empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
  214. empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
  215. empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
  216. empathy_software_plugin/wizards/security/__init__.py +0 -32
  217. empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
  218. empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
  219. empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
  220. empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
  221. empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
  222. empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
  223. empathy_software_plugin/wizards/testing/__init__.py +0 -27
  224. empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
  225. empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
  226. empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
  227. empathy_software_plugin/wizards/testing_wizard.py +0 -274
  228. wizards/__init__.py +0 -82
  229. wizards/admission_assessment_wizard.py +0 -644
  230. wizards/care_plan.py +0 -321
  231. wizards/clinical_assessment.py +0 -769
  232. wizards/discharge_planning.py +0 -77
  233. wizards/discharge_summary_wizard.py +0 -468
  234. wizards/dosage_calculation.py +0 -497
  235. wizards/incident_report_wizard.py +0 -454
  236. wizards/medication_reconciliation.py +0 -85
  237. wizards/nursing_assessment.py +0 -171
  238. wizards/patient_education.py +0 -654
  239. wizards/quality_improvement.py +0 -705
  240. wizards/sbar_report.py +0 -324
  241. wizards/sbar_wizard.py +0 -608
  242. wizards/shift_handoff_wizard.py +0 -535
  243. wizards/soap_note_wizard.py +0 -679
  244. wizards/treatment_plan.py +0 -15
  245. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/WHEEL +0 -0
  246. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/entry_points.txt +0 -0
  247. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.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 single entry point for all Empathy Framework commands using Typer.
3
+ A simplified, intelligent CLI using Socratic questioning.
4
4
 
5
5
  Usage:
6
- empathy --help # Show all commands
7
- empathy memory status # Memory control panel
8
- empathy provider # Show provider config
9
- empathy scan . # Scan codebase
10
- empathy morning # Start-of-day briefing
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
- # Create the main Typer app
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 - Predictive AI-Developer Collaboration",
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 - Predictive AI-Developer Collaboration
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 morning Start-of-day briefing
68
- empathy health Quick health check
69
- empathy ship Pre-commit validation
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]Provider:[/bold]
76
- empathy provider Show current provider config
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
- # MEMORY SUBCOMMAND GROUP
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
- @memory_app.command("start")
101
- def memory_start():
102
- """Start Redis server for short-term memory."""
103
- subprocess.run([sys.executable, "-m", "empathy_os.memory.control_panel", "start"], check=False)
104
-
105
-
106
- @memory_app.command("stop")
107
- def memory_stop():
108
- """Stop Redis server."""
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
- @memory_app.command("stats")
113
- def memory_stats():
114
- """Show memory statistics."""
115
- subprocess.run([sys.executable, "-m", "empathy_os.memory.control_panel", "stats"], check=False)
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
- @memory_app.command("patterns")
119
- def memory_patterns():
120
- """List stored patterns."""
121
- subprocess.run(
122
- [sys.executable, "-m", "empathy_os.memory.control_panel", "patterns", "--list"], check=False
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
- # PROVIDER SUBCOMMAND GROUP
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
- @provider_app.callback(invoke_without_command=True)
135
- def provider_show(
136
- ctx: typer.Context,
137
- set_provider: str | None = None,
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
- """Show or configure provider settings."""
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
- subprocess.run(args, check=False)
280
+ Alias for: empathy do "review code"
281
+ """
282
+ _run_workflow("code-review", path, json_output)
154
283
 
155
284
 
156
- @provider_app.command("registry")
157
- def provider_registry(
158
- provider_filter: str | None = None,
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
- """Show all available models in the registry."""
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
- @provider_app.command("costs")
168
- def provider_costs(
169
- input_tokens: int = 10000,
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
- @provider_app.command("telemetry")
189
- def provider_telemetry(
190
- summary: bool = False,
191
- costs: bool = False,
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
- """View telemetry and analytics."""
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
- # SCAN COMMAND
207
- # =============================================================================
304
+ Alias for: empathy do "generate tests"
305
+ """
306
+ _run_workflow("test-gen", path, json_output)
208
307
 
209
308
 
210
- @app.command("scan")
211
- def scan(
212
- path: Path = Path("."),
213
- format_out: str = "text",
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
- """Scan codebase for issues."""
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
- result = subprocess.run(args, check=False, capture_output=False)
227
- if result.returncode != 0:
228
- console.print("[yellow]Note: empathy-scan may not be installed[/yellow]")
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
- # INSPECT COMMAND
322
+ # UTILITY COMMANDS
234
323
  # =============================================================================
235
324
 
236
325
 
237
- @app.command("inspect")
238
- def inspect_cmd(
239
- path: Path = Path("."),
240
- format_out: str = "text",
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
- """Deep inspection with code analysis."""
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
- @app.command("sync-claude")
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
- # WORKFLOW COMMANDS (delegate to legacy CLI)
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
- @app.command("morning")
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 ship(
279
- tests_only: bool = False,
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 health(
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 (lint, types, tests)."""
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
- # WIZARD COMMANDS
397
+ # REPORT SUBCOMMAND GROUP
332
398
  # =============================================================================
333
399
 
334
- wizard_app = typer.Typer(help="AI Development Wizards")
335
- app.add_typer(wizard_app, name="wizard")
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
- @wizard_app.command("run")
345
- def wizard_run(
346
- name: str = typer.Argument(..., help="Wizard name to run"),
347
- path: Path = Path("."),
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
- @wizard_app.command("create")
356
- def wizard_create(
357
- name: str = typer.Argument(..., help="Wizard name (snake_case)"),
358
- domain: str = typer.Option(
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
- @wizard_app.command("list-patterns")
396
- def wizard_list_patterns():
397
- """List all available wizard patterns."""
398
- subprocess.run([sys.executable, "-m", "scaffolding", "list-patterns"], check=False)
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
- @wizard_app.command("generate-tests")
402
- def wizard_generate_tests(
403
- wizard_id: str = typer.Argument(..., help="Wizard ID"),
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
- """Generate tests for a wizard."""
408
- cmd = [sys.executable, "-m", "test_generator", "generate", wizard_id, "--patterns", patterns]
409
- if output:
410
- cmd.extend(["--output", str(output)])
411
- subprocess.run(cmd, check=False)
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
- # WORKFLOW SUBCOMMAND GROUP
437
+ # MEMORY SUBCOMMAND GROUP
429
438
  # =============================================================================
430
439
 
431
- workflow_app = typer.Typer(help="Multi-model workflows")
432
- app.add_typer(workflow_app, name="workflow")
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
- @workflow_app.command("run")
442
- def workflow_run(
443
- name: str = typer.Argument(..., help="Workflow name"),
444
- path: Path = typer.Option(Path("."), "--path", "-p", help="Target path for workflow"),
445
- input_json: str = typer.Option(None, "--input", "-i", help="JSON input for workflow (overrides --path)"),
446
- use_recommended_tier: bool = False,
447
- health_score_threshold: int = 95,
448
- json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
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
- cmd = [
469
- sys.executable,
470
- "-m",
471
- "empathy_os.cli",
472
- "workflow",
473
- "run",
474
- name,
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
- if health_score_threshold != 95:
483
- cmd.extend(["--health-score-threshold", str(health_score_threshold)])
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
- subprocess.run(cmd, check=False)
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
- @workflow_app.command("create")
492
- def workflow_create(
493
- name: str = typer.Argument(..., help="Workflow name (kebab-case, e.g., bug-scanner)"),
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", "workflow_scaffolding", "recommend", workflow_type], check=False
485
+ [sys.executable, "-m", "empathy_os.memory.control_panel", "patterns"],
486
+ check=False,
532
487
  )
533
488
 
534
489
 
535
490
  # =============================================================================
536
- # ORCHESTRATE SUBCOMMAND GROUP (Meta-Orchestration v4.0)
491
+ # UTILITIES SUBCOMMAND GROUP
537
492
  # =============================================================================
538
493
 
539
- orchestrate_app = typer.Typer(help="Meta-orchestration workflows (v4.0)")
540
- app.add_typer(orchestrate_app, name="orchestrate")
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
- @orchestrate_app.command("health-check")
544
- def orchestrate_health_check(
545
- mode: str = typer.Option("daily", "--mode", "-m", help="Check mode: daily, weekly, release"),
546
- project_root: Path = typer.Option(Path("."), "--project-root", "-p", help="Project root path"),
547
- json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
548
- ):
549
- """Run orchestrated health check with adaptive agent teams.
550
-
551
- Modes:
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
- async def run_health_check():
564
- workflow = OrchestratedHealthCheckWorkflow(mode=mode)
565
- report = await workflow.execute(project_root=str(project_root))
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
- console.print(json.dumps(report.to_dict(), indent=2))
571
- else:
572
- # Beautiful console output
573
- console.print("\n[bold cyan]🏥 HEALTH CHECK REPORT[/bold cyan]")
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
- @orchestrate_app.command("release-prep")
645
- def orchestrate_release_prep(
646
- project_root: Path = typer.Option(Path("."), "--project-root", "-p", help="Project root path"),
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
- """Run orchestrated release preparation with parallel validation.
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
- console.print("\n" + "=" * 60)
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
- try:
715
- asyncio.run(run_release_prep())
716
- except Exception as e:
717
- console.print(f"[bold red]Error:[/bold red] {e}")
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
- @orchestrate_app.command("test-coverage")
722
- def orchestrate_test_coverage(
723
- project_root: Path = typer.Option(Path("."), "--project-root", "-p", help="Project root path"),
724
- target: float = typer.Option(90.0, "--target", "-t", help="Target coverage percentage"),
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
- """Run orchestrated test coverage boost with sequential stages.
547
+ """Scan codebase for issues.
728
548
 
729
- Runs 3 stages sequentially:
730
- 1. Coverage Analyzer → Identify gaps
731
- 2. Test Generator Create tests
732
- 3. Test Validator → Verify coverage
549
+ Examples:
550
+ empathy utility scan .
551
+ empathy utility scan ./src --type security
733
552
  """
734
- import asyncio
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
- success_color = "green" if report.success else "red"
751
- success_emoji = "✅" if report.success else "❌"
752
- console.print(
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
- try:
771
- asyncio.run(run_test_coverage())
772
- except Exception as e:
773
- console.print(f"[bold red]Error:[/bold red] {e}")
774
- raise typer.Exit(code=1)
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
- # TELEMETRY SUBCOMMAND GROUP
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
- telemetry_app = typer.Typer(help="View and manage local usage telemetry")
782
- app.add_typer(telemetry_app, name="telemetry")
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
- @telemetry_app.command("savings")
798
- def telemetry_savings(
799
- days: int = typer.Option(30, "--days", "-d", help="Number of days to analyze"),
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", "telemetry", "savings", "--days", str(days)],
586
+ [sys.executable, "-m", "empathy_os.cli", "workflow", "list"],
804
587
  check=False,
805
588
  )
806
589
 
807
590
 
808
- @telemetry_app.command("compare")
809
- def telemetry_compare(
810
- period1: int = typer.Option(7, "--period1", "-p1", help="First period in days"),
811
- period2: int = typer.Option(30, "--period2", "-p2", help="Second period in days"),
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
- """Compare usage across two time periods."""
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
- @telemetry_app.command("export")
831
- def telemetry_export(
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
- @telemetry_app.command("reset")
846
- def telemetry_reset(
847
- confirm: bool = typer.Option(False, "--confirm", help="Confirm deletion"),
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
- """Clear all telemetry data (use with caution)."""
850
- args = [sys.executable, "-m", "empathy_os.cli", "telemetry", "reset"]
851
- if confirm:
852
- args.append("--confirm")
853
- subprocess.run(args, check=False)
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
- service_app = typer.Typer(help="Cross-session coordination service")
861
- app.add_typer(service_app, name="service")
630
+ # Telemetry commands - LLM usage tracking
631
+ telemetry_app = typer.Typer(help="LLM usage telemetry and cost tracking")
862
632
 
863
633
 
864
- @service_app.command("start")
865
- def service_start(
866
- daemon: bool = typer.Option(False, "--daemon", "-d", help="Run as daemon (auto-start on connect)"),
634
+ @telemetry_app.command("show")
635
+ def telemetry_show(
636
+ limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
867
637
  ):
868
- """Start the cross-session coordination service.
869
-
870
- The service enables communication between multiple Claude Code sessions
871
- via Redis-backed short-term memory.
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
- try:
878
- memory = get_redis_memory()
879
-
880
- if memory.use_mock:
881
- console.print("[yellow]⚠️ Cross-session service requires Redis.[/yellow]")
882
- console.print("[dim]Start Redis with: empathy memory start[/dim]")
883
- console.print("[dim]Or set REDIS_HOST/REDIS_PORT environment variables[/dim]")
884
- raise typer.Exit(code=1)
885
-
886
- from empathy_os.memory.cross_session import BackgroundService
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
- @service_app.command("stop")
915
- def service_stop():
916
- """Stop the cross-session coordination service."""
917
- from empathy_os.redis_config import get_redis_memory
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
- except Exception as e:
941
- console.print(f"[bold red]Error:[/bold red] {e}")
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
- json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
948
- ):
949
- """Show cross-session service status and active sessions."""
950
- import json as json_mod
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
- try:
955
- memory = get_redis_memory()
956
-
957
- if memory.use_mock:
958
- status = {
959
- "mode": "mock",
960
- "cross_session_available": False,
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
- progressive_app = typer.Typer(help="Progressive tier escalation workflows")
1131
- app.add_typer(progressive_app, name="progressive")
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
- storage_path: str = typer.Option(
1137
- None,
1138
- "--storage-path",
1139
- help="Path to progressive workflow storage (default: .empathy/progressive_runs)",
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
- args = Namespace(task_id=task_id, storage_path=storage_path, json=json_output)
1167
- cmd_show_report(args)
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
- storage_path: str = typer.Option(
1173
- None,
1174
- "--storage-path",
1175
- help="Path to progressive workflow storage (default: .empathy/progressive_runs)",
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
- # TIER RECOMMENDATION SUBCOMMAND GROUP
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
- description: str = typer.Argument(..., help="Description of the bug or task"),
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 intelligent tier recommendation for a bug/task."""
1230
- from empathy_os.tier_recommender import TierRecommender
1231
-
1232
- recommender = TierRecommender()
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 pattern learning statistics."""
1274
- from empathy_os.tier_recommender import TierRecommender
1275
-
1276
- recommender = TierRecommender()
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
- @app.command("dashboard")
1388
- def dashboard():
1389
- """Launch visual dashboard."""
1390
- subprocess.run([sys.executable, "-m", "empathy_os.cli", "dashboard"], check=False)
1391
-
1392
-
1393
- @app.command("costs")
1394
- def costs():
1395
- """View API cost tracking."""
1396
- subprocess.run([sys.executable, "-m", "empathy_os.cli", "costs"], check=False)
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
- @app.command("status")
1406
- def status():
1407
- """What needs attention now."""
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():