attune-ai 2.0.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.
- attune/__init__.py +358 -0
- attune/adaptive/__init__.py +13 -0
- attune/adaptive/task_complexity.py +127 -0
- attune/agent_monitoring.py +414 -0
- attune/cache/__init__.py +117 -0
- attune/cache/base.py +166 -0
- attune/cache/dependency_manager.py +256 -0
- attune/cache/hash_only.py +251 -0
- attune/cache/hybrid.py +457 -0
- attune/cache/storage.py +285 -0
- attune/cache_monitor.py +356 -0
- attune/cache_stats.py +298 -0
- attune/cli/__init__.py +152 -0
- attune/cli/__main__.py +12 -0
- attune/cli/commands/__init__.py +1 -0
- attune/cli/commands/batch.py +264 -0
- attune/cli/commands/cache.py +248 -0
- attune/cli/commands/help.py +331 -0
- attune/cli/commands/info.py +140 -0
- attune/cli/commands/inspect.py +436 -0
- attune/cli/commands/inspection.py +57 -0
- attune/cli/commands/memory.py +48 -0
- attune/cli/commands/metrics.py +92 -0
- attune/cli/commands/orchestrate.py +184 -0
- attune/cli/commands/patterns.py +207 -0
- attune/cli/commands/profiling.py +202 -0
- attune/cli/commands/provider.py +98 -0
- attune/cli/commands/routing.py +285 -0
- attune/cli/commands/setup.py +96 -0
- attune/cli/commands/status.py +235 -0
- attune/cli/commands/sync.py +166 -0
- attune/cli/commands/tier.py +121 -0
- attune/cli/commands/utilities.py +114 -0
- attune/cli/commands/workflow.py +579 -0
- attune/cli/core.py +32 -0
- attune/cli/parsers/__init__.py +68 -0
- attune/cli/parsers/batch.py +118 -0
- attune/cli/parsers/cache.py +65 -0
- attune/cli/parsers/help.py +41 -0
- attune/cli/parsers/info.py +26 -0
- attune/cli/parsers/inspect.py +66 -0
- attune/cli/parsers/metrics.py +42 -0
- attune/cli/parsers/orchestrate.py +61 -0
- attune/cli/parsers/patterns.py +54 -0
- attune/cli/parsers/provider.py +40 -0
- attune/cli/parsers/routing.py +110 -0
- attune/cli/parsers/setup.py +42 -0
- attune/cli/parsers/status.py +47 -0
- attune/cli/parsers/sync.py +31 -0
- attune/cli/parsers/tier.py +33 -0
- attune/cli/parsers/workflow.py +77 -0
- attune/cli/utils/__init__.py +1 -0
- attune/cli/utils/data.py +242 -0
- attune/cli/utils/helpers.py +68 -0
- attune/cli_legacy.py +3957 -0
- attune/cli_minimal.py +1159 -0
- attune/cli_router.py +437 -0
- attune/cli_unified.py +814 -0
- attune/config/__init__.py +66 -0
- attune/config/xml_config.py +286 -0
- attune/config.py +545 -0
- attune/coordination.py +870 -0
- attune/core.py +1511 -0
- attune/core_modules/__init__.py +15 -0
- attune/cost_tracker.py +626 -0
- attune/dashboard/__init__.py +41 -0
- attune/dashboard/app.py +512 -0
- attune/dashboard/simple_server.py +435 -0
- attune/dashboard/standalone_server.py +547 -0
- attune/discovery.py +306 -0
- attune/emergence.py +306 -0
- attune/exceptions.py +123 -0
- attune/feedback_loops.py +373 -0
- attune/hot_reload/README.md +473 -0
- attune/hot_reload/__init__.py +62 -0
- attune/hot_reload/config.py +83 -0
- attune/hot_reload/integration.py +229 -0
- attune/hot_reload/reloader.py +298 -0
- attune/hot_reload/watcher.py +183 -0
- attune/hot_reload/websocket.py +177 -0
- attune/levels.py +577 -0
- attune/leverage_points.py +441 -0
- attune/logging_config.py +261 -0
- attune/mcp/__init__.py +10 -0
- attune/mcp/server.py +506 -0
- attune/memory/__init__.py +237 -0
- attune/memory/claude_memory.py +469 -0
- attune/memory/config.py +224 -0
- attune/memory/control_panel.py +1290 -0
- attune/memory/control_panel_support.py +145 -0
- attune/memory/cross_session.py +845 -0
- attune/memory/edges.py +179 -0
- attune/memory/encryption.py +159 -0
- attune/memory/file_session.py +770 -0
- attune/memory/graph.py +570 -0
- attune/memory/long_term.py +913 -0
- attune/memory/long_term_types.py +99 -0
- attune/memory/mixins/__init__.py +25 -0
- attune/memory/mixins/backend_init_mixin.py +249 -0
- attune/memory/mixins/capabilities_mixin.py +208 -0
- attune/memory/mixins/handoff_mixin.py +208 -0
- attune/memory/mixins/lifecycle_mixin.py +49 -0
- attune/memory/mixins/long_term_mixin.py +352 -0
- attune/memory/mixins/promotion_mixin.py +109 -0
- attune/memory/mixins/short_term_mixin.py +182 -0
- attune/memory/nodes.py +179 -0
- attune/memory/redis_bootstrap.py +540 -0
- attune/memory/security/__init__.py +31 -0
- attune/memory/security/audit_logger.py +932 -0
- attune/memory/security/pii_scrubber.py +640 -0
- attune/memory/security/secrets_detector.py +678 -0
- attune/memory/short_term.py +2192 -0
- attune/memory/simple_storage.py +302 -0
- attune/memory/storage/__init__.py +15 -0
- attune/memory/storage_backend.py +167 -0
- attune/memory/summary_index.py +583 -0
- attune/memory/types.py +446 -0
- attune/memory/unified.py +182 -0
- attune/meta_workflows/__init__.py +74 -0
- attune/meta_workflows/agent_creator.py +248 -0
- attune/meta_workflows/builtin_templates.py +567 -0
- attune/meta_workflows/cli_commands/__init__.py +56 -0
- attune/meta_workflows/cli_commands/agent_commands.py +321 -0
- attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
- attune/meta_workflows/cli_commands/config_commands.py +232 -0
- attune/meta_workflows/cli_commands/memory_commands.py +182 -0
- attune/meta_workflows/cli_commands/template_commands.py +354 -0
- attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
- attune/meta_workflows/cli_meta_workflows.py +59 -0
- attune/meta_workflows/form_engine.py +292 -0
- attune/meta_workflows/intent_detector.py +409 -0
- attune/meta_workflows/models.py +569 -0
- attune/meta_workflows/pattern_learner.py +738 -0
- attune/meta_workflows/plan_generator.py +384 -0
- attune/meta_workflows/session_context.py +397 -0
- attune/meta_workflows/template_registry.py +229 -0
- attune/meta_workflows/workflow.py +984 -0
- attune/metrics/__init__.py +12 -0
- attune/metrics/collector.py +31 -0
- attune/metrics/prompt_metrics.py +194 -0
- attune/models/__init__.py +172 -0
- attune/models/__main__.py +13 -0
- attune/models/adaptive_routing.py +437 -0
- attune/models/auth_cli.py +444 -0
- attune/models/auth_strategy.py +450 -0
- attune/models/cli.py +655 -0
- attune/models/empathy_executor.py +354 -0
- attune/models/executor.py +257 -0
- attune/models/fallback.py +762 -0
- attune/models/provider_config.py +282 -0
- attune/models/registry.py +472 -0
- attune/models/tasks.py +359 -0
- attune/models/telemetry/__init__.py +71 -0
- attune/models/telemetry/analytics.py +594 -0
- attune/models/telemetry/backend.py +196 -0
- attune/models/telemetry/data_models.py +431 -0
- attune/models/telemetry/storage.py +489 -0
- attune/models/token_estimator.py +420 -0
- attune/models/validation.py +280 -0
- attune/monitoring/__init__.py +52 -0
- attune/monitoring/alerts.py +946 -0
- attune/monitoring/alerts_cli.py +448 -0
- attune/monitoring/multi_backend.py +271 -0
- attune/monitoring/otel_backend.py +362 -0
- attune/optimization/__init__.py +19 -0
- attune/optimization/context_optimizer.py +272 -0
- attune/orchestration/__init__.py +67 -0
- attune/orchestration/agent_templates.py +707 -0
- attune/orchestration/config_store.py +499 -0
- attune/orchestration/execution_strategies.py +2111 -0
- attune/orchestration/meta_orchestrator.py +1168 -0
- attune/orchestration/pattern_learner.py +696 -0
- attune/orchestration/real_tools.py +931 -0
- attune/pattern_cache.py +187 -0
- attune/pattern_library.py +542 -0
- attune/patterns/debugging/all_patterns.json +81 -0
- attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
- attune/patterns/refactoring_memory.json +89 -0
- attune/persistence.py +564 -0
- attune/platform_utils.py +265 -0
- attune/plugins/__init__.py +28 -0
- attune/plugins/base.py +361 -0
- attune/plugins/registry.py +268 -0
- attune/project_index/__init__.py +32 -0
- attune/project_index/cli.py +335 -0
- attune/project_index/index.py +667 -0
- attune/project_index/models.py +504 -0
- attune/project_index/reports.py +474 -0
- attune/project_index/scanner.py +777 -0
- attune/project_index/scanner_parallel.py +291 -0
- attune/prompts/__init__.py +61 -0
- attune/prompts/config.py +77 -0
- attune/prompts/context.py +177 -0
- attune/prompts/parser.py +285 -0
- attune/prompts/registry.py +313 -0
- attune/prompts/templates.py +208 -0
- attune/redis_config.py +302 -0
- attune/redis_memory.py +799 -0
- attune/resilience/__init__.py +56 -0
- attune/resilience/circuit_breaker.py +256 -0
- attune/resilience/fallback.py +179 -0
- attune/resilience/health.py +300 -0
- attune/resilience/retry.py +209 -0
- attune/resilience/timeout.py +135 -0
- attune/routing/__init__.py +43 -0
- attune/routing/chain_executor.py +433 -0
- attune/routing/classifier.py +217 -0
- attune/routing/smart_router.py +234 -0
- attune/routing/workflow_registry.py +343 -0
- attune/scaffolding/README.md +589 -0
- attune/scaffolding/__init__.py +35 -0
- attune/scaffolding/__main__.py +14 -0
- attune/scaffolding/cli.py +240 -0
- attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
- attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
- attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
- attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
- attune/socratic/__init__.py +256 -0
- attune/socratic/ab_testing.py +958 -0
- attune/socratic/blueprint.py +533 -0
- attune/socratic/cli.py +703 -0
- attune/socratic/collaboration.py +1114 -0
- attune/socratic/domain_templates.py +924 -0
- attune/socratic/embeddings.py +738 -0
- attune/socratic/engine.py +794 -0
- attune/socratic/explainer.py +682 -0
- attune/socratic/feedback.py +772 -0
- attune/socratic/forms.py +629 -0
- attune/socratic/generator.py +732 -0
- attune/socratic/llm_analyzer.py +637 -0
- attune/socratic/mcp_server.py +702 -0
- attune/socratic/session.py +312 -0
- attune/socratic/storage.py +667 -0
- attune/socratic/success.py +730 -0
- attune/socratic/visual_editor.py +860 -0
- attune/socratic/web_ui.py +958 -0
- attune/telemetry/__init__.py +39 -0
- attune/telemetry/agent_coordination.py +475 -0
- attune/telemetry/agent_tracking.py +367 -0
- attune/telemetry/approval_gates.py +545 -0
- attune/telemetry/cli.py +1231 -0
- attune/telemetry/commands/__init__.py +14 -0
- attune/telemetry/commands/dashboard_commands.py +696 -0
- attune/telemetry/event_streaming.py +409 -0
- attune/telemetry/feedback_loop.py +567 -0
- attune/telemetry/usage_tracker.py +591 -0
- attune/templates.py +754 -0
- attune/test_generator/__init__.py +38 -0
- attune/test_generator/__main__.py +14 -0
- attune/test_generator/cli.py +234 -0
- attune/test_generator/generator.py +355 -0
- attune/test_generator/risk_analyzer.py +216 -0
- attune/test_generator/templates/unit_test.py.jinja2 +272 -0
- attune/tier_recommender.py +384 -0
- attune/tools.py +183 -0
- attune/trust/__init__.py +28 -0
- attune/trust/circuit_breaker.py +579 -0
- attune/trust_building.py +527 -0
- attune/validation/__init__.py +19 -0
- attune/validation/xml_validator.py +281 -0
- attune/vscode_bridge.py +173 -0
- attune/workflow_commands.py +780 -0
- attune/workflow_patterns/__init__.py +33 -0
- attune/workflow_patterns/behavior.py +249 -0
- attune/workflow_patterns/core.py +76 -0
- attune/workflow_patterns/output.py +99 -0
- attune/workflow_patterns/registry.py +255 -0
- attune/workflow_patterns/structural.py +288 -0
- attune/workflows/__init__.py +539 -0
- attune/workflows/autonomous_test_gen.py +1268 -0
- attune/workflows/base.py +2667 -0
- attune/workflows/batch_processing.py +342 -0
- attune/workflows/bug_predict.py +1084 -0
- attune/workflows/builder.py +273 -0
- attune/workflows/caching.py +253 -0
- attune/workflows/code_review.py +1048 -0
- attune/workflows/code_review_adapters.py +312 -0
- attune/workflows/code_review_pipeline.py +722 -0
- attune/workflows/config.py +645 -0
- attune/workflows/dependency_check.py +644 -0
- attune/workflows/document_gen/__init__.py +25 -0
- attune/workflows/document_gen/config.py +30 -0
- attune/workflows/document_gen/report_formatter.py +162 -0
- attune/workflows/document_gen/workflow.py +1426 -0
- attune/workflows/document_manager.py +216 -0
- attune/workflows/document_manager_README.md +134 -0
- attune/workflows/documentation_orchestrator.py +1205 -0
- attune/workflows/history.py +510 -0
- attune/workflows/keyboard_shortcuts/__init__.py +39 -0
- attune/workflows/keyboard_shortcuts/generators.py +391 -0
- attune/workflows/keyboard_shortcuts/parsers.py +416 -0
- attune/workflows/keyboard_shortcuts/prompts.py +295 -0
- attune/workflows/keyboard_shortcuts/schema.py +193 -0
- attune/workflows/keyboard_shortcuts/workflow.py +509 -0
- attune/workflows/llm_base.py +363 -0
- attune/workflows/manage_docs.py +87 -0
- attune/workflows/manage_docs_README.md +134 -0
- attune/workflows/manage_documentation.py +821 -0
- attune/workflows/new_sample_workflow1.py +149 -0
- attune/workflows/new_sample_workflow1_README.md +150 -0
- attune/workflows/orchestrated_health_check.py +849 -0
- attune/workflows/orchestrated_release_prep.py +600 -0
- attune/workflows/output.py +413 -0
- attune/workflows/perf_audit.py +863 -0
- attune/workflows/pr_review.py +762 -0
- attune/workflows/progress.py +785 -0
- attune/workflows/progress_server.py +322 -0
- attune/workflows/progressive/README 2.md +454 -0
- attune/workflows/progressive/README.md +454 -0
- attune/workflows/progressive/__init__.py +82 -0
- attune/workflows/progressive/cli.py +219 -0
- attune/workflows/progressive/core.py +488 -0
- attune/workflows/progressive/orchestrator.py +723 -0
- attune/workflows/progressive/reports.py +520 -0
- attune/workflows/progressive/telemetry.py +274 -0
- attune/workflows/progressive/test_gen.py +495 -0
- attune/workflows/progressive/workflow.py +589 -0
- attune/workflows/refactor_plan.py +694 -0
- attune/workflows/release_prep.py +895 -0
- attune/workflows/release_prep_crew.py +969 -0
- attune/workflows/research_synthesis.py +404 -0
- attune/workflows/routing.py +168 -0
- attune/workflows/secure_release.py +593 -0
- attune/workflows/security_adapters.py +297 -0
- attune/workflows/security_audit.py +1329 -0
- attune/workflows/security_audit_phase3.py +355 -0
- attune/workflows/seo_optimization.py +633 -0
- attune/workflows/step_config.py +234 -0
- attune/workflows/telemetry_mixin.py +269 -0
- attune/workflows/test5.py +125 -0
- attune/workflows/test5_README.md +158 -0
- attune/workflows/test_coverage_boost_crew.py +849 -0
- attune/workflows/test_gen/__init__.py +52 -0
- attune/workflows/test_gen/ast_analyzer.py +249 -0
- attune/workflows/test_gen/config.py +88 -0
- attune/workflows/test_gen/data_models.py +38 -0
- attune/workflows/test_gen/report_formatter.py +289 -0
- attune/workflows/test_gen/test_templates.py +381 -0
- attune/workflows/test_gen/workflow.py +655 -0
- attune/workflows/test_gen.py +54 -0
- attune/workflows/test_gen_behavioral.py +477 -0
- attune/workflows/test_gen_parallel.py +341 -0
- attune/workflows/test_lifecycle.py +526 -0
- attune/workflows/test_maintenance.py +627 -0
- attune/workflows/test_maintenance_cli.py +590 -0
- attune/workflows/test_maintenance_crew.py +840 -0
- attune/workflows/test_runner.py +622 -0
- attune/workflows/tier_tracking.py +531 -0
- attune/workflows/xml_enhanced_crew.py +285 -0
- attune_ai-2.0.0.dist-info/METADATA +1026 -0
- attune_ai-2.0.0.dist-info/RECORD +457 -0
- attune_ai-2.0.0.dist-info/WHEEL +5 -0
- attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
- attune_ai-2.0.0.dist-info/top_level.txt +5 -0
- attune_healthcare/__init__.py +13 -0
- attune_healthcare/monitors/__init__.py +9 -0
- attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
- attune_healthcare/monitors/monitoring/__init__.py +44 -0
- attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
- attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
- attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
- attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
- attune_llm/README.md +553 -0
- attune_llm/__init__.py +28 -0
- attune_llm/agent_factory/__init__.py +53 -0
- attune_llm/agent_factory/adapters/__init__.py +85 -0
- attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
- attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
- attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
- attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
- attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
- attune_llm/agent_factory/adapters/native.py +228 -0
- attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
- attune_llm/agent_factory/base.py +305 -0
- attune_llm/agent_factory/crews/__init__.py +67 -0
- attune_llm/agent_factory/crews/code_review.py +1113 -0
- attune_llm/agent_factory/crews/health_check.py +1262 -0
- attune_llm/agent_factory/crews/refactoring.py +1128 -0
- attune_llm/agent_factory/crews/security_audit.py +1018 -0
- attune_llm/agent_factory/decorators.py +287 -0
- attune_llm/agent_factory/factory.py +558 -0
- attune_llm/agent_factory/framework.py +193 -0
- attune_llm/agent_factory/memory_integration.py +328 -0
- attune_llm/agent_factory/resilient.py +320 -0
- attune_llm/agents_md/__init__.py +22 -0
- attune_llm/agents_md/loader.py +218 -0
- attune_llm/agents_md/parser.py +271 -0
- attune_llm/agents_md/registry.py +307 -0
- attune_llm/claude_memory.py +466 -0
- attune_llm/cli/__init__.py +8 -0
- attune_llm/cli/sync_claude.py +487 -0
- attune_llm/code_health.py +1313 -0
- attune_llm/commands/__init__.py +51 -0
- attune_llm/commands/context.py +375 -0
- attune_llm/commands/loader.py +301 -0
- attune_llm/commands/models.py +231 -0
- attune_llm/commands/parser.py +371 -0
- attune_llm/commands/registry.py +429 -0
- attune_llm/config/__init__.py +29 -0
- attune_llm/config/unified.py +291 -0
- attune_llm/context/__init__.py +22 -0
- attune_llm/context/compaction.py +455 -0
- attune_llm/context/manager.py +434 -0
- attune_llm/contextual_patterns.py +361 -0
- attune_llm/core.py +907 -0
- attune_llm/git_pattern_extractor.py +435 -0
- attune_llm/hooks/__init__.py +24 -0
- attune_llm/hooks/config.py +306 -0
- attune_llm/hooks/executor.py +289 -0
- attune_llm/hooks/registry.py +302 -0
- attune_llm/hooks/scripts/__init__.py +39 -0
- attune_llm/hooks/scripts/evaluate_session.py +201 -0
- attune_llm/hooks/scripts/first_time_init.py +285 -0
- attune_llm/hooks/scripts/pre_compact.py +207 -0
- attune_llm/hooks/scripts/session_end.py +183 -0
- attune_llm/hooks/scripts/session_start.py +163 -0
- attune_llm/hooks/scripts/suggest_compact.py +225 -0
- attune_llm/learning/__init__.py +30 -0
- attune_llm/learning/evaluator.py +438 -0
- attune_llm/learning/extractor.py +514 -0
- attune_llm/learning/storage.py +560 -0
- attune_llm/levels.py +227 -0
- attune_llm/pattern_confidence.py +414 -0
- attune_llm/pattern_resolver.py +272 -0
- attune_llm/pattern_summary.py +350 -0
- attune_llm/providers.py +967 -0
- attune_llm/routing/__init__.py +32 -0
- attune_llm/routing/model_router.py +362 -0
- attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
- attune_llm/security/PHASE2_COMPLETE.md +384 -0
- attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- attune_llm/security/QUICK_REFERENCE.md +316 -0
- attune_llm/security/README.md +262 -0
- attune_llm/security/__init__.py +62 -0
- attune_llm/security/audit_logger.py +929 -0
- attune_llm/security/audit_logger_example.py +152 -0
- attune_llm/security/pii_scrubber.py +640 -0
- attune_llm/security/secrets_detector.py +678 -0
- attune_llm/security/secrets_detector_example.py +304 -0
- attune_llm/security/secure_memdocs.py +1192 -0
- attune_llm/security/secure_memdocs_example.py +278 -0
- attune_llm/session_status.py +745 -0
- attune_llm/state.py +246 -0
- attune_llm/utils/__init__.py +5 -0
- attune_llm/utils/tokens.py +349 -0
- attune_software/SOFTWARE_PLUGIN_README.md +57 -0
- attune_software/__init__.py +13 -0
- attune_software/cli/__init__.py +120 -0
- attune_software/cli/inspect.py +362 -0
- attune_software/cli.py +574 -0
- attune_software/plugin.py +188 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
attune/cli_unified.py
ADDED
|
@@ -0,0 +1,814 @@
|
|
|
1
|
+
"""Unified CLI for Empathy Framework
|
|
2
|
+
|
|
3
|
+
DEPRECATED: This module is deprecated as of v5.0.0.
|
|
4
|
+
Use the minimal CLI instead: `empathy` (attune.cli_minimal)
|
|
5
|
+
|
|
6
|
+
The minimal CLI provides:
|
|
7
|
+
- `empathy workflow list|info|run` - Workflow management
|
|
8
|
+
- `empathy telemetry show|savings|export` - Usage tracking
|
|
9
|
+
- `empathy provider show|set` - Provider configuration
|
|
10
|
+
- `empathy validate` - Configuration validation
|
|
11
|
+
|
|
12
|
+
For interactive features, use Claude Code slash commands:
|
|
13
|
+
- /dev, /testing, /docs, /release, /help
|
|
14
|
+
|
|
15
|
+
Migration guide: https://smartaimemory.com/framework-docs/migration/cli/
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
A simplified, intelligent CLI using Socratic questioning.
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
empathy do "review code in src/" # Intelligent - asks questions if needed
|
|
23
|
+
empathy r . # Quick: review
|
|
24
|
+
empathy s . # Quick: security
|
|
25
|
+
empathy t . # Quick: test
|
|
26
|
+
empathy scan . # Quick scan (no API)
|
|
27
|
+
empathy ship # Pre-commit check
|
|
28
|
+
|
|
29
|
+
Copyright 2025 Smart-AI-Memory
|
|
30
|
+
Licensed under Fair Source License 0.9
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
import warnings
|
|
34
|
+
|
|
35
|
+
warnings.warn(
|
|
36
|
+
"empathy-unified CLI is deprecated. Use 'empathy' (cli_minimal) instead. "
|
|
37
|
+
"See: https://smartaimemory.com/framework-docs/reference/cli-reference/",
|
|
38
|
+
DeprecationWarning,
|
|
39
|
+
stacklevel=2,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
import json
|
|
43
|
+
import subprocess
|
|
44
|
+
import sys
|
|
45
|
+
from importlib.metadata import version as get_version
|
|
46
|
+
from pathlib import Path
|
|
47
|
+
|
|
48
|
+
import typer
|
|
49
|
+
from rich.console import Console
|
|
50
|
+
from rich.panel import Panel
|
|
51
|
+
|
|
52
|
+
# =============================================================================
|
|
53
|
+
# CONSTANTS
|
|
54
|
+
# =============================================================================
|
|
55
|
+
|
|
56
|
+
CHEATSHEET_CONTENT = """\
|
|
57
|
+
[bold]Main Command[/bold]
|
|
58
|
+
empathy do "..." Intelligent task execution (asks questions if needed)
|
|
59
|
+
|
|
60
|
+
[bold]Quick Actions (short aliases)[/bold]
|
|
61
|
+
empathy r [path] Review code
|
|
62
|
+
empathy s [path] Security audit
|
|
63
|
+
empathy t [path] Generate tests
|
|
64
|
+
empathy d [path] Generate docs
|
|
65
|
+
|
|
66
|
+
[bold]Utilities[/bold]
|
|
67
|
+
empathy scan [path] Quick scan (no API needed)
|
|
68
|
+
empathy ship Pre-commit validation
|
|
69
|
+
empathy health Project health check
|
|
70
|
+
|
|
71
|
+
[bold]Reports[/bold]
|
|
72
|
+
empathy report costs API cost tracking
|
|
73
|
+
empathy report health Project health summary
|
|
74
|
+
empathy report patterns Learned patterns
|
|
75
|
+
|
|
76
|
+
[bold]Memory[/bold]
|
|
77
|
+
empathy memory Memory system status
|
|
78
|
+
empathy memory start Start Redis"""
|
|
79
|
+
|
|
80
|
+
TIER_CONFIG_PATH = Path(".empathy") / "tier_config.json"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# =============================================================================
|
|
84
|
+
# HELPER FUNCTIONS
|
|
85
|
+
# =============================================================================
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _load_tier_config() -> dict:
|
|
89
|
+
"""Load tier configuration from .attune/tier_config.json."""
|
|
90
|
+
if TIER_CONFIG_PATH.exists():
|
|
91
|
+
try:
|
|
92
|
+
return json.loads(TIER_CONFIG_PATH.read_text())
|
|
93
|
+
except json.JSONDecodeError:
|
|
94
|
+
return {}
|
|
95
|
+
return {}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _save_tier_config(config: dict) -> None:
|
|
99
|
+
"""Save tier configuration to .attune/tier_config.json."""
|
|
100
|
+
TIER_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
TIER_CONFIG_PATH.write_text(json.dumps(config, indent=2))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _auto_sync_patterns() -> None:
|
|
105
|
+
"""Automatically sync patterns to Claude Code after workflow completion."""
|
|
106
|
+
try:
|
|
107
|
+
result = subprocess.run(
|
|
108
|
+
["empathy-sync-claude", "--source", "patterns"],
|
|
109
|
+
capture_output=True,
|
|
110
|
+
text=True,
|
|
111
|
+
timeout=30,
|
|
112
|
+
check=False,
|
|
113
|
+
)
|
|
114
|
+
if result.returncode == 0:
|
|
115
|
+
console.print("\n[dim]✓ Patterns synced to Claude Code[/dim]")
|
|
116
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, Exception):
|
|
117
|
+
pass # Silent fail
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _run_workflow(name: str, path: Path, json_output: bool = False):
|
|
121
|
+
"""Helper to run a workflow via the legacy CLI."""
|
|
122
|
+
workflow_input = f'{{"path": "{path}"}}'
|
|
123
|
+
|
|
124
|
+
cmd = [
|
|
125
|
+
sys.executable,
|
|
126
|
+
"-m",
|
|
127
|
+
"attune.cli",
|
|
128
|
+
"workflow",
|
|
129
|
+
"run",
|
|
130
|
+
name,
|
|
131
|
+
"--input",
|
|
132
|
+
workflow_input,
|
|
133
|
+
]
|
|
134
|
+
if json_output:
|
|
135
|
+
cmd.append("--json")
|
|
136
|
+
|
|
137
|
+
result = subprocess.run(cmd, check=False)
|
|
138
|
+
|
|
139
|
+
if result.returncode == 0 and not json_output:
|
|
140
|
+
_auto_sync_patterns()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# =============================================================================
|
|
144
|
+
# APP SETUP
|
|
145
|
+
# =============================================================================
|
|
146
|
+
|
|
147
|
+
app = typer.Typer(
|
|
148
|
+
name="empathy",
|
|
149
|
+
help="Empathy Framework - Intelligent AI-Developer Collaboration",
|
|
150
|
+
no_args_is_help=True,
|
|
151
|
+
rich_markup_mode="rich",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
console = Console()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def get_empathy_version() -> str:
|
|
158
|
+
"""Get the installed version of empathy-framework."""
|
|
159
|
+
try:
|
|
160
|
+
return get_version("empathy-framework")
|
|
161
|
+
except Exception:
|
|
162
|
+
return "dev"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def version_callback(value: bool):
|
|
166
|
+
"""Show version and exit."""
|
|
167
|
+
if value:
|
|
168
|
+
console.print(f"[bold blue]Empathy Framework[/bold blue] v{get_empathy_version()}")
|
|
169
|
+
raise typer.Exit()
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@app.callback()
|
|
173
|
+
def callback(
|
|
174
|
+
version: bool = typer.Option(
|
|
175
|
+
None,
|
|
176
|
+
"--version",
|
|
177
|
+
"-v",
|
|
178
|
+
callback=version_callback,
|
|
179
|
+
is_eager=True,
|
|
180
|
+
help="Show version and exit",
|
|
181
|
+
),
|
|
182
|
+
):
|
|
183
|
+
"""Empathy Framework - Intelligent AI-Developer Collaboration
|
|
184
|
+
|
|
185
|
+
[bold]Quick Start:[/bold]
|
|
186
|
+
empathy do "review the code" Ask AI to do something
|
|
187
|
+
empathy r . Quick code review
|
|
188
|
+
empathy scan . Quick security scan
|
|
189
|
+
|
|
190
|
+
[bold]Shortcuts:[/bold]
|
|
191
|
+
r = review, s = security, t = test, d = docs
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# =============================================================================
|
|
196
|
+
# MAIN COMMAND: do
|
|
197
|
+
# =============================================================================
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@app.command("do")
|
|
201
|
+
def do_command(
|
|
202
|
+
goal: str = typer.Argument(..., help="What you want to accomplish"),
|
|
203
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Path to analyze"),
|
|
204
|
+
interactive: bool = typer.Option(
|
|
205
|
+
True, "--interactive/--no-interactive", "-i", help="Ask clarifying questions"
|
|
206
|
+
),
|
|
207
|
+
):
|
|
208
|
+
"""Intelligent task execution using Socratic questioning.
|
|
209
|
+
|
|
210
|
+
The AI will understand your goal and ask clarifying questions if needed.
|
|
211
|
+
Uses domain templates for common tasks like code review, security, testing.
|
|
212
|
+
|
|
213
|
+
Examples:
|
|
214
|
+
empathy do "review the authentication code"
|
|
215
|
+
empathy do "find security vulnerabilities" --path ./src
|
|
216
|
+
empathy do "generate tests for the API" --no-interactive
|
|
217
|
+
"""
|
|
218
|
+
console.print(f"\n[bold]Goal:[/bold] {goal}")
|
|
219
|
+
console.print(f"[dim]Path: {path}[/dim]\n")
|
|
220
|
+
|
|
221
|
+
# Use Socratic system for intelligent task execution
|
|
222
|
+
try:
|
|
223
|
+
from attune.socratic import SocraticWorkflowBuilder
|
|
224
|
+
from attune.socratic.cli import console as socratic_console
|
|
225
|
+
from attune.socratic.cli import render_form_interactive
|
|
226
|
+
from attune.socratic.storage import get_default_storage
|
|
227
|
+
|
|
228
|
+
builder = SocraticWorkflowBuilder()
|
|
229
|
+
storage = get_default_storage()
|
|
230
|
+
|
|
231
|
+
# Start session with the goal
|
|
232
|
+
session = builder.start_session()
|
|
233
|
+
session = builder.set_goal(session, f"{goal} (path: {path})")
|
|
234
|
+
storage.save_session(session)
|
|
235
|
+
|
|
236
|
+
# Show domain detection
|
|
237
|
+
if session.goal_analysis:
|
|
238
|
+
console.print(f"[cyan]Detected domain:[/cyan] {session.goal_analysis.domain}")
|
|
239
|
+
console.print(f"[cyan]Confidence:[/cyan] {session.goal_analysis.confidence:.0%}")
|
|
240
|
+
|
|
241
|
+
if session.goal_analysis.ambiguities and interactive:
|
|
242
|
+
console.print("\n[yellow]Clarifications needed:[/yellow]")
|
|
243
|
+
for amb in session.goal_analysis.ambiguities:
|
|
244
|
+
console.print(f" • {amb}")
|
|
245
|
+
|
|
246
|
+
# Interactive questioning if needed
|
|
247
|
+
if interactive:
|
|
248
|
+
while not builder.is_ready_to_generate(session):
|
|
249
|
+
form = builder.get_next_questions(session)
|
|
250
|
+
if not form:
|
|
251
|
+
break
|
|
252
|
+
|
|
253
|
+
answers = render_form_interactive(form, socratic_console)
|
|
254
|
+
session = builder.submit_answers(session, answers)
|
|
255
|
+
storage.save_session(session)
|
|
256
|
+
|
|
257
|
+
# Generate and execute workflow
|
|
258
|
+
if builder.is_ready_to_generate(session):
|
|
259
|
+
console.print("\n[bold]Generating workflow...[/bold]")
|
|
260
|
+
workflow = builder.generate_workflow(session)
|
|
261
|
+
storage.save_session(session)
|
|
262
|
+
|
|
263
|
+
console.print(
|
|
264
|
+
f"\n[green]✓ Generated workflow with {len(workflow.agents)} agents[/green]"
|
|
265
|
+
)
|
|
266
|
+
console.print(workflow.describe())
|
|
267
|
+
|
|
268
|
+
# Execute the workflow
|
|
269
|
+
if session.blueprint:
|
|
270
|
+
storage.save_blueprint(session.blueprint)
|
|
271
|
+
console.print(f"\n[dim]Blueprint saved: {session.blueprint.id[:8]}...[/dim]")
|
|
272
|
+
|
|
273
|
+
_auto_sync_patterns()
|
|
274
|
+
|
|
275
|
+
except ImportError as e:
|
|
276
|
+
console.print(f"[yellow]Socratic system not fully available: {e}[/yellow]")
|
|
277
|
+
console.print("[dim]Falling back to keyword matching...[/dim]\n")
|
|
278
|
+
|
|
279
|
+
# Fallback: keyword-based workflow selection
|
|
280
|
+
goal_lower = goal.lower()
|
|
281
|
+
if any(w in goal_lower for w in ["review", "check", "analyze"]):
|
|
282
|
+
_run_workflow("code-review", path)
|
|
283
|
+
elif any(w in goal_lower for w in ["security", "vulnerab", "owasp"]):
|
|
284
|
+
_run_workflow("security-audit", path)
|
|
285
|
+
elif any(w in goal_lower for w in ["test", "coverage"]):
|
|
286
|
+
_run_workflow("test-gen", path)
|
|
287
|
+
elif any(w in goal_lower for w in ["doc", "document"]):
|
|
288
|
+
_run_workflow("doc-gen", path)
|
|
289
|
+
else:
|
|
290
|
+
_run_workflow("code-review", path)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# =============================================================================
|
|
294
|
+
# SHORT ALIASES
|
|
295
|
+
# =============================================================================
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@app.command("r")
|
|
299
|
+
def review_short(
|
|
300
|
+
path: Path = typer.Argument(Path("."), help="Path to review"),
|
|
301
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
302
|
+
):
|
|
303
|
+
"""[bold]Review[/bold] - Quick code review.
|
|
304
|
+
|
|
305
|
+
Alias for: empathy do "review code"
|
|
306
|
+
"""
|
|
307
|
+
_run_workflow("code-review", path, json_output)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
@app.command("s")
|
|
311
|
+
def security_short(
|
|
312
|
+
path: Path = typer.Argument(Path("."), help="Path to scan"),
|
|
313
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
314
|
+
):
|
|
315
|
+
"""[bold]Security[/bold] - Quick security audit.
|
|
316
|
+
|
|
317
|
+
Alias for: empathy do "security audit"
|
|
318
|
+
"""
|
|
319
|
+
_run_workflow("security-audit", path, json_output)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@app.command("t")
|
|
323
|
+
def test_short(
|
|
324
|
+
path: Path = typer.Argument(Path("."), help="Path to analyze"),
|
|
325
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
326
|
+
):
|
|
327
|
+
"""[bold]Test[/bold] - Generate tests.
|
|
328
|
+
|
|
329
|
+
Alias for: empathy do "generate tests"
|
|
330
|
+
"""
|
|
331
|
+
_run_workflow("test-gen", path, json_output)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@app.command("d")
|
|
335
|
+
def docs_short(
|
|
336
|
+
path: Path = typer.Argument(Path("."), help="Path to document"),
|
|
337
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
338
|
+
):
|
|
339
|
+
"""[bold]Docs[/bold] - Generate documentation.
|
|
340
|
+
|
|
341
|
+
Alias for: empathy do "generate docs"
|
|
342
|
+
"""
|
|
343
|
+
_run_workflow("doc-gen", path, json_output)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
# =============================================================================
|
|
347
|
+
# UTILITY COMMANDS
|
|
348
|
+
# =============================================================================
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
@app.command("scan")
|
|
352
|
+
def scan_command(
|
|
353
|
+
scan_type: str = typer.Argument("all", help="Scan type: security, performance, or all"),
|
|
354
|
+
path: Path = typer.Argument(Path("."), help="Path to scan"),
|
|
355
|
+
):
|
|
356
|
+
"""Quick security/performance scan (no API needed).
|
|
357
|
+
|
|
358
|
+
Examples:
|
|
359
|
+
empathy scan all .
|
|
360
|
+
empathy scan security ./src
|
|
361
|
+
"""
|
|
362
|
+
if scan_type not in ("security", "performance", "all"):
|
|
363
|
+
console.print(f"[red]Invalid scan type: {scan_type}[/red]")
|
|
364
|
+
console.print("Valid types: security, performance, all")
|
|
365
|
+
raise typer.Exit(code=1)
|
|
366
|
+
|
|
367
|
+
console.print(f"[bold blue]Scanning {path} ({scan_type})...[/bold blue]\n")
|
|
368
|
+
|
|
369
|
+
if scan_type in ("all", "security"):
|
|
370
|
+
# Run ruff for linting
|
|
371
|
+
console.print("[bold]Running ruff (linting)...[/bold]")
|
|
372
|
+
subprocess.run(["ruff", "check", str(path)], check=False)
|
|
373
|
+
|
|
374
|
+
# Run bandit for security
|
|
375
|
+
console.print("\n[bold]Running bandit (security)...[/bold]")
|
|
376
|
+
result = subprocess.run(["bandit", "-r", str(path), "-q"], check=False, capture_output=True)
|
|
377
|
+
if result.returncode == 0:
|
|
378
|
+
console.print("[green]No security issues found[/green]")
|
|
379
|
+
elif result.stdout:
|
|
380
|
+
console.print(result.stdout.decode())
|
|
381
|
+
|
|
382
|
+
if scan_type in ("all", "performance"):
|
|
383
|
+
console.print("\n[bold]Checking for performance patterns...[/bold]")
|
|
384
|
+
# Basic performance check - look for common issues
|
|
385
|
+
subprocess.run(["ruff", "check", str(path), "--select", "PERF"], check=False)
|
|
386
|
+
|
|
387
|
+
console.print("\n[bold green]Scan complete![/bold green]")
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
@app.command("ship")
|
|
391
|
+
def ship_command(
|
|
392
|
+
skip_sync: bool = typer.Option(False, "--skip-sync", help="Skip pattern sync"),
|
|
393
|
+
):
|
|
394
|
+
"""Pre-commit validation (lint, format, tests, security).
|
|
395
|
+
|
|
396
|
+
Run this before committing to ensure code quality.
|
|
397
|
+
"""
|
|
398
|
+
args = [sys.executable, "-m", "attune.cli", "ship"]
|
|
399
|
+
if skip_sync:
|
|
400
|
+
args.append("--skip-sync")
|
|
401
|
+
subprocess.run(args, check=False)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
@app.command("health")
|
|
405
|
+
def health_command(
|
|
406
|
+
deep: bool = typer.Option(False, "--deep", help="Comprehensive check"),
|
|
407
|
+
fix: bool = typer.Option(False, "--fix", help="Auto-fix issues"),
|
|
408
|
+
):
|
|
409
|
+
"""Quick project health check.
|
|
410
|
+
|
|
411
|
+
Shows lint issues, test status, and overall health score.
|
|
412
|
+
"""
|
|
413
|
+
args = [sys.executable, "-m", "attune.cli", "health"]
|
|
414
|
+
if deep:
|
|
415
|
+
args.append("--deep")
|
|
416
|
+
if fix:
|
|
417
|
+
args.append("--fix")
|
|
418
|
+
subprocess.run(args, check=False)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# =============================================================================
|
|
422
|
+
# REPORT SUBCOMMAND GROUP
|
|
423
|
+
# =============================================================================
|
|
424
|
+
|
|
425
|
+
report_app = typer.Typer(help="View reports and dashboards")
|
|
426
|
+
app.add_typer(report_app, name="report")
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
@report_app.command("costs")
|
|
430
|
+
def report_costs():
|
|
431
|
+
"""View API cost tracking."""
|
|
432
|
+
subprocess.run([sys.executable, "-m", "attune.cli", "costs"], check=False)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@report_app.command("health")
|
|
436
|
+
def report_health():
|
|
437
|
+
"""View project health summary."""
|
|
438
|
+
subprocess.run([sys.executable, "-m", "attune.cli", "status"], check=False)
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
@report_app.command("patterns")
|
|
442
|
+
def report_patterns():
|
|
443
|
+
"""View learned patterns."""
|
|
444
|
+
subprocess.run(
|
|
445
|
+
[sys.executable, "-m", "attune.memory.control_panel", "patterns"],
|
|
446
|
+
check=False,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
@report_app.command("telemetry")
|
|
451
|
+
def report_telemetry(
|
|
452
|
+
limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
|
|
453
|
+
):
|
|
454
|
+
"""View LLM usage telemetry."""
|
|
455
|
+
subprocess.run(
|
|
456
|
+
[sys.executable, "-m", "attune.cli", "telemetry", "show", "--limit", str(limit)],
|
|
457
|
+
check=False,
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
# =============================================================================
|
|
462
|
+
# MEMORY SUBCOMMAND GROUP
|
|
463
|
+
# =============================================================================
|
|
464
|
+
|
|
465
|
+
memory_app = typer.Typer(help="Memory system control panel")
|
|
466
|
+
app.add_typer(memory_app, name="memory")
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
@memory_app.callback(invoke_without_command=True)
|
|
470
|
+
def memory_default(ctx: typer.Context):
|
|
471
|
+
"""Memory system control panel."""
|
|
472
|
+
if ctx.invoked_subcommand is None:
|
|
473
|
+
subprocess.run(
|
|
474
|
+
[sys.executable, "-m", "attune.memory.control_panel", "status"],
|
|
475
|
+
check=False,
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
@memory_app.command("status")
|
|
480
|
+
def memory_status():
|
|
481
|
+
"""Check memory system status."""
|
|
482
|
+
subprocess.run(
|
|
483
|
+
[sys.executable, "-m", "attune.memory.control_panel", "status"],
|
|
484
|
+
check=False,
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@memory_app.command("start")
|
|
489
|
+
def memory_start():
|
|
490
|
+
"""Start Redis server for short-term memory."""
|
|
491
|
+
subprocess.run(
|
|
492
|
+
[sys.executable, "-m", "attune.memory.control_panel", "start"],
|
|
493
|
+
check=False,
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
@memory_app.command("stop")
|
|
498
|
+
def memory_stop():
|
|
499
|
+
"""Stop Redis server."""
|
|
500
|
+
subprocess.run(
|
|
501
|
+
[sys.executable, "-m", "attune.memory.control_panel", "stop"],
|
|
502
|
+
check=False,
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
@memory_app.command("patterns")
|
|
507
|
+
def memory_patterns():
|
|
508
|
+
"""List stored patterns."""
|
|
509
|
+
subprocess.run(
|
|
510
|
+
[sys.executable, "-m", "attune.memory.control_panel", "patterns"],
|
|
511
|
+
check=False,
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
# =============================================================================
|
|
516
|
+
# UTILITIES SUBCOMMAND GROUP
|
|
517
|
+
# =============================================================================
|
|
518
|
+
|
|
519
|
+
utilities_app = typer.Typer(help="Utility tools - init, cheatsheet, dashboard, sync")
|
|
520
|
+
app.add_typer(utilities_app, name="utilities")
|
|
521
|
+
app.add_typer(utilities_app, name="utility", hidden=True) # Alias for common typo
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
@utilities_app.command("cheatsheet")
|
|
525
|
+
def utilities_cheatsheet():
|
|
526
|
+
"""Show quick reference for all commands."""
|
|
527
|
+
console.print(
|
|
528
|
+
Panel.fit(
|
|
529
|
+
CHEATSHEET_CONTENT,
|
|
530
|
+
title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
|
|
531
|
+
),
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
@utilities_app.command("init")
|
|
536
|
+
def utilities_init():
|
|
537
|
+
"""Create a new configuration file."""
|
|
538
|
+
subprocess.run([sys.executable, "-m", "attune.cli", "init"], check=False)
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
@utilities_app.command("dashboard")
|
|
542
|
+
def utilities_dashboard():
|
|
543
|
+
"""Launch visual dashboard."""
|
|
544
|
+
subprocess.run([sys.executable, "-m", "attune.cli", "dashboard"], check=False)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
@utilities_app.command("sync-claude")
|
|
548
|
+
def utilities_sync_claude(
|
|
549
|
+
source: str = typer.Option("patterns", "--source", "-s", help="Source to sync"),
|
|
550
|
+
):
|
|
551
|
+
"""Sync patterns to Claude Code memory."""
|
|
552
|
+
subprocess.run(["empathy-sync-claude", "--source", source], check=False)
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
@utilities_app.command("costs")
|
|
556
|
+
def utilities_costs():
|
|
557
|
+
"""View API cost tracking."""
|
|
558
|
+
subprocess.run([sys.executable, "-m", "attune.cli", "costs"], check=False)
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
@utilities_app.command("status")
|
|
562
|
+
def utilities_status():
|
|
563
|
+
"""What needs attention now."""
|
|
564
|
+
subprocess.run([sys.executable, "-m", "attune.cli", "status"], check=False)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
@utilities_app.command("scan")
|
|
568
|
+
def utilities_scan(
|
|
569
|
+
path: Path = typer.Argument(Path("."), help="Path to scan"),
|
|
570
|
+
scan_type: str = typer.Option(
|
|
571
|
+
"all", "--type", "-t", help="Scan type: security, performance, or all"
|
|
572
|
+
),
|
|
573
|
+
):
|
|
574
|
+
"""Scan codebase for issues.
|
|
575
|
+
|
|
576
|
+
Examples:
|
|
577
|
+
empathy utility scan .
|
|
578
|
+
empathy utility scan ./src --type security
|
|
579
|
+
"""
|
|
580
|
+
# Delegate to main scan command
|
|
581
|
+
scan_command(scan_type, path)
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
# =============================================================================
|
|
585
|
+
# CHEATSHEET (top-level alias for convenience)
|
|
586
|
+
# =============================================================================
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
@app.command("cheatsheet")
|
|
590
|
+
def cheatsheet():
|
|
591
|
+
"""Show quick reference for all commands."""
|
|
592
|
+
console.print(
|
|
593
|
+
Panel.fit(
|
|
594
|
+
CHEATSHEET_CONTENT,
|
|
595
|
+
title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
|
|
596
|
+
),
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
# =============================================================================
|
|
601
|
+
# ADDITIONAL COMMAND APPS (exported for cli/__init__.py)
|
|
602
|
+
# These provide structure for commands that will be migrated from legacy CLI
|
|
603
|
+
# =============================================================================
|
|
604
|
+
|
|
605
|
+
# Workflow commands - run multi-model AI workflows
|
|
606
|
+
workflow_app = typer.Typer(help="Run multi-model AI workflows")
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
@workflow_app.command("list")
|
|
610
|
+
def workflow_list():
|
|
611
|
+
"""List available workflows."""
|
|
612
|
+
subprocess.run(
|
|
613
|
+
[sys.executable, "-m", "attune.cli", "workflow", "list"],
|
|
614
|
+
check=False,
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
@workflow_app.command("run")
|
|
619
|
+
def workflow_run(
|
|
620
|
+
name: str = typer.Argument(..., help="Workflow name"),
|
|
621
|
+
input_json: str = typer.Option("{}", "--input", "-i", help="Input JSON"),
|
|
622
|
+
json_output: bool = typer.Option(False, "--json", "-j", help="JSON output"),
|
|
623
|
+
):
|
|
624
|
+
"""Run a workflow by name."""
|
|
625
|
+
args = [sys.executable, "-m", "attune.cli", "workflow", "run", name, "--input", input_json]
|
|
626
|
+
if json_output:
|
|
627
|
+
args.append("--json")
|
|
628
|
+
subprocess.run(args, check=False)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
@workflow_app.command("describe")
|
|
632
|
+
def workflow_describe(name: str = typer.Argument(..., help="Workflow name")):
|
|
633
|
+
"""Describe a workflow."""
|
|
634
|
+
subprocess.run(
|
|
635
|
+
[sys.executable, "-m", "attune.cli", "workflow", "describe", name],
|
|
636
|
+
check=False,
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
# Orchestrate commands - advanced orchestration features
|
|
641
|
+
orchestrate_app = typer.Typer(help="Advanced workflow orchestration")
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
@orchestrate_app.command("run")
|
|
645
|
+
def orchestrate_run(
|
|
646
|
+
task: str = typer.Argument(..., help="Task description"),
|
|
647
|
+
path: Path = typer.Option(Path("."), "--path", "-p", help="Path to analyze"),
|
|
648
|
+
):
|
|
649
|
+
"""Run orchestrated task."""
|
|
650
|
+
task_json = json.dumps({"task": task, "path": str(path)})
|
|
651
|
+
subprocess.run(
|
|
652
|
+
[sys.executable, "-m", "attune.cli", "orchestrate", "--input", task_json],
|
|
653
|
+
check=False,
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
# Telemetry commands - LLM usage tracking
|
|
658
|
+
telemetry_app = typer.Typer(help="LLM usage telemetry and cost tracking")
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
@telemetry_app.command("show")
|
|
662
|
+
def telemetry_show(
|
|
663
|
+
limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
|
|
664
|
+
):
|
|
665
|
+
"""Show telemetry data."""
|
|
666
|
+
subprocess.run(
|
|
667
|
+
[sys.executable, "-m", "attune.cli", "telemetry", "show", "--limit", str(limit)],
|
|
668
|
+
check=False,
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
@telemetry_app.command("export")
|
|
673
|
+
def telemetry_export(
|
|
674
|
+
output: Path = typer.Argument(..., help="Output file path"),
|
|
675
|
+
format_type: str = typer.Option("json", "--format", "-f", help="Output format: json, csv"),
|
|
676
|
+
):
|
|
677
|
+
"""Export telemetry data."""
|
|
678
|
+
subprocess.run(
|
|
679
|
+
[
|
|
680
|
+
sys.executable,
|
|
681
|
+
"-m",
|
|
682
|
+
"attune.cli",
|
|
683
|
+
"telemetry",
|
|
684
|
+
"export",
|
|
685
|
+
str(output),
|
|
686
|
+
"--format",
|
|
687
|
+
format_type,
|
|
688
|
+
],
|
|
689
|
+
check=False,
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
@telemetry_app.command("reset")
|
|
694
|
+
def telemetry_reset():
|
|
695
|
+
"""Reset telemetry data."""
|
|
696
|
+
subprocess.run(
|
|
697
|
+
[sys.executable, "-m", "attune.cli", "telemetry", "reset"],
|
|
698
|
+
check=False,
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
# Service commands - background services
|
|
703
|
+
service_app = typer.Typer(help="Background services management")
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
@service_app.command("status")
|
|
707
|
+
def service_status():
|
|
708
|
+
"""Check service status."""
|
|
709
|
+
# Check Redis status via memory control panel
|
|
710
|
+
subprocess.run(
|
|
711
|
+
[sys.executable, "-m", "attune.memory.control_panel", "status"],
|
|
712
|
+
check=False,
|
|
713
|
+
)
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
@service_app.command("start")
|
|
717
|
+
def service_start(service_name: str = typer.Argument("all", help="Service to start")):
|
|
718
|
+
"""Start background services."""
|
|
719
|
+
if service_name in ("all", "redis"):
|
|
720
|
+
subprocess.run(
|
|
721
|
+
[sys.executable, "-m", "attune.memory.control_panel", "start"],
|
|
722
|
+
check=False,
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
@service_app.command("stop")
|
|
727
|
+
def service_stop(service_name: str = typer.Argument("all", help="Service to stop")):
|
|
728
|
+
"""Stop background services."""
|
|
729
|
+
if service_name in ("all", "redis"):
|
|
730
|
+
subprocess.run(
|
|
731
|
+
[sys.executable, "-m", "attune.memory.control_panel", "stop"],
|
|
732
|
+
check=False,
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
# Progressive commands - progressive test generation
|
|
737
|
+
progressive_app = typer.Typer(help="Progressive test generation")
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
@progressive_app.command("list")
|
|
741
|
+
def progressive_list():
|
|
742
|
+
"""List progressive test results."""
|
|
743
|
+
subprocess.run(
|
|
744
|
+
[sys.executable, "-m", "attune.cli", "progressive", "list"],
|
|
745
|
+
check=False,
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
@progressive_app.command("report")
|
|
750
|
+
def progressive_report(session_id: str = typer.Argument(..., help="Session ID")):
|
|
751
|
+
"""Show progressive test report."""
|
|
752
|
+
subprocess.run(
|
|
753
|
+
[sys.executable, "-m", "attune.cli", "progressive", "report", session_id],
|
|
754
|
+
check=False,
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
@progressive_app.command("analytics")
|
|
759
|
+
def progressive_analytics():
|
|
760
|
+
"""Show progressive test analytics."""
|
|
761
|
+
subprocess.run(
|
|
762
|
+
[sys.executable, "-m", "attune.cli", "progressive", "analytics"],
|
|
763
|
+
check=False,
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
# Tier commands - model tier management
|
|
768
|
+
tier_app = typer.Typer(help="Model tier configuration")
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
@tier_app.command("recommend")
|
|
772
|
+
def tier_recommend(
|
|
773
|
+
task: str = typer.Argument("code-review", help="Task type"),
|
|
774
|
+
):
|
|
775
|
+
"""Get tier recommendation for a task."""
|
|
776
|
+
subprocess.run(
|
|
777
|
+
[sys.executable, "-m", "attune.cli", "tier", "recommend", task],
|
|
778
|
+
check=False,
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
@tier_app.command("stats")
|
|
783
|
+
def tier_stats():
|
|
784
|
+
"""Show tier usage statistics."""
|
|
785
|
+
subprocess.run(
|
|
786
|
+
[sys.executable, "-m", "attune.cli", "tier", "stats"],
|
|
787
|
+
check=False,
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
@tier_app.command("set")
|
|
792
|
+
def tier_set(
|
|
793
|
+
task: str = typer.Argument(..., help="Task type"),
|
|
794
|
+
tier_name: str = typer.Argument(..., help="Tier name: cheap, balanced, premium"),
|
|
795
|
+
):
|
|
796
|
+
"""Set tier for a task type."""
|
|
797
|
+
config = _load_tier_config()
|
|
798
|
+
config[task] = tier_name
|
|
799
|
+
_save_tier_config(config)
|
|
800
|
+
console.print(f"[green]Set {task} to use {tier_name} tier[/green]")
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
# =============================================================================
|
|
804
|
+
# ENTRY POINT
|
|
805
|
+
# =============================================================================
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
def main():
|
|
809
|
+
"""Entry point for the unified CLI."""
|
|
810
|
+
app()
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
if __name__ == "__main__":
|
|
814
|
+
main()
|