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
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""Orchestration commands for meta-workflows.
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Smart-AI-Memory
|
|
4
|
+
Licensed under Fair Source License 0.9
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
from attune.logging_config import get_logger
|
|
11
|
+
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def cmd_orchestrate(args):
|
|
16
|
+
"""Run meta-orchestration workflows.
|
|
17
|
+
|
|
18
|
+
Orchestrates teams of agents to accomplish complex tasks through
|
|
19
|
+
intelligent composition patterns.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
args: Namespace object from argparse with attributes:
|
|
23
|
+
- workflow (str): Orchestration workflow name.
|
|
24
|
+
- path (str): Target path for orchestration.
|
|
25
|
+
- mode (str | None): Execution mode (e.g., 'daily', 'weekly', 'release').
|
|
26
|
+
- json (bool): If True, output as JSON format.
|
|
27
|
+
- dry_run (bool): If True, show plan without executing.
|
|
28
|
+
- verbose (bool): If True, show detailed output.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
int: 0 on success, 1 on failure.
|
|
32
|
+
"""
|
|
33
|
+
from attune.workflows.orchestrated_health_check import OrchestratedHealthCheckWorkflow
|
|
34
|
+
from attune.workflows.orchestrated_release_prep import OrchestratedReleasePrepWorkflow
|
|
35
|
+
|
|
36
|
+
# Get workflow type
|
|
37
|
+
workflow_type = args.workflow
|
|
38
|
+
|
|
39
|
+
# Only print header in non-JSON mode
|
|
40
|
+
if not (hasattr(args, "json") and args.json):
|
|
41
|
+
print()
|
|
42
|
+
print("=" * 60)
|
|
43
|
+
print(f" META-ORCHESTRATION: {workflow_type.upper()}")
|
|
44
|
+
print("=" * 60)
|
|
45
|
+
print()
|
|
46
|
+
|
|
47
|
+
if workflow_type == "release-prep":
|
|
48
|
+
# Release Preparation workflow
|
|
49
|
+
path = args.path or "."
|
|
50
|
+
quality_gates = {}
|
|
51
|
+
|
|
52
|
+
# Collect custom quality gates
|
|
53
|
+
if hasattr(args, "min_coverage") and args.min_coverage is not None:
|
|
54
|
+
quality_gates["min_coverage"] = args.min_coverage
|
|
55
|
+
if hasattr(args, "min_quality") and args.min_quality is not None:
|
|
56
|
+
quality_gates["min_quality_score"] = args.min_quality
|
|
57
|
+
if hasattr(args, "max_critical") and args.max_critical is not None:
|
|
58
|
+
quality_gates["max_critical_issues"] = args.max_critical
|
|
59
|
+
|
|
60
|
+
# Only print details in non-JSON mode
|
|
61
|
+
if not (hasattr(args, "json") and args.json):
|
|
62
|
+
print(f" Project Path: {path}")
|
|
63
|
+
if quality_gates:
|
|
64
|
+
print(f" Quality Gates: {quality_gates}")
|
|
65
|
+
print()
|
|
66
|
+
print(" 🔍 Parallel Validation Agents:")
|
|
67
|
+
print(" • Security Auditor (vulnerability scan)")
|
|
68
|
+
print(" • Test Coverage Analyzer (gap analysis)")
|
|
69
|
+
print(" • Code Quality Reviewer (best practices)")
|
|
70
|
+
print(" • Documentation Writer (completeness)")
|
|
71
|
+
print()
|
|
72
|
+
|
|
73
|
+
# Create workflow
|
|
74
|
+
workflow = OrchestratedReleasePrepWorkflow(
|
|
75
|
+
quality_gates=quality_gates if quality_gates else None
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
# Execute workflow
|
|
80
|
+
report = asyncio.run(workflow.execute(path=path))
|
|
81
|
+
|
|
82
|
+
# Display results
|
|
83
|
+
if hasattr(args, "json") and args.json:
|
|
84
|
+
print(json.dumps(report.to_dict(), indent=2))
|
|
85
|
+
else:
|
|
86
|
+
print(report.format_console_output())
|
|
87
|
+
|
|
88
|
+
# Return appropriate exit code
|
|
89
|
+
return 0 if report.approved else 1
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f" ❌ Error executing release prep workflow: {e}")
|
|
93
|
+
print()
|
|
94
|
+
logger.exception("Release prep workflow failed")
|
|
95
|
+
return 1
|
|
96
|
+
|
|
97
|
+
elif workflow_type == "test-coverage":
|
|
98
|
+
# Test Coverage Boost workflow - DISABLED in v4.0.0
|
|
99
|
+
print(" ⚠️ FEATURE DISABLED")
|
|
100
|
+
print(" " + "-" * 56)
|
|
101
|
+
print()
|
|
102
|
+
print(" The test-coverage workflow has been disabled in v4.0.0")
|
|
103
|
+
print(" due to poor quality (0% test pass rate).")
|
|
104
|
+
print()
|
|
105
|
+
print(" This feature is being redesigned and will return in a")
|
|
106
|
+
print(" future release with improved test generation quality.")
|
|
107
|
+
print()
|
|
108
|
+
print(" Available v4.0 workflows:")
|
|
109
|
+
print(" • health-check - Real-time codebase health analysis")
|
|
110
|
+
print(" • release-prep - Quality gate validation")
|
|
111
|
+
print()
|
|
112
|
+
return 1
|
|
113
|
+
|
|
114
|
+
elif workflow_type == "health-check":
|
|
115
|
+
# Health Check workflow
|
|
116
|
+
mode = args.mode or "daily"
|
|
117
|
+
project_root = args.project_root or "."
|
|
118
|
+
focus_area = getattr(args, "focus", None)
|
|
119
|
+
|
|
120
|
+
# Only print details in non-JSON mode
|
|
121
|
+
if not (hasattr(args, "json") and args.json):
|
|
122
|
+
print(f" Mode: {mode.upper()}")
|
|
123
|
+
print(f" Project Root: {project_root}")
|
|
124
|
+
if focus_area:
|
|
125
|
+
print(f" Focus Area: {focus_area}")
|
|
126
|
+
print()
|
|
127
|
+
|
|
128
|
+
# Show agents for mode
|
|
129
|
+
mode_agents = {
|
|
130
|
+
"daily": ["Security", "Coverage", "Quality"],
|
|
131
|
+
"weekly": ["Security", "Coverage", "Quality", "Performance", "Documentation"],
|
|
132
|
+
"release": [
|
|
133
|
+
"Security",
|
|
134
|
+
"Coverage",
|
|
135
|
+
"Quality",
|
|
136
|
+
"Performance",
|
|
137
|
+
"Documentation",
|
|
138
|
+
"Architecture",
|
|
139
|
+
],
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
print(f" 🔍 {mode.capitalize()} Check Agents:")
|
|
143
|
+
for agent in mode_agents.get(mode, []):
|
|
144
|
+
print(f" • {agent}")
|
|
145
|
+
print()
|
|
146
|
+
|
|
147
|
+
# Create workflow
|
|
148
|
+
workflow = OrchestratedHealthCheckWorkflow(mode=mode, project_root=project_root)
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
# Execute workflow
|
|
152
|
+
report = asyncio.run(workflow.execute())
|
|
153
|
+
|
|
154
|
+
# Display results
|
|
155
|
+
if hasattr(args, "json") and args.json:
|
|
156
|
+
print(json.dumps(report.to_dict(), indent=2))
|
|
157
|
+
else:
|
|
158
|
+
print(report.format_console_output())
|
|
159
|
+
|
|
160
|
+
# Return appropriate exit code (70+ is passing)
|
|
161
|
+
return 0 if report.overall_health_score >= 70 else 1
|
|
162
|
+
|
|
163
|
+
except Exception as e:
|
|
164
|
+
print(f" ❌ Error executing health check workflow: {e}")
|
|
165
|
+
print()
|
|
166
|
+
logger.exception("Health check workflow failed")
|
|
167
|
+
return 1
|
|
168
|
+
|
|
169
|
+
else:
|
|
170
|
+
print(f" ❌ Unknown workflow type: {workflow_type}")
|
|
171
|
+
print()
|
|
172
|
+
print(" Available workflows:")
|
|
173
|
+
print(" - release-prep: Release readiness validation (parallel agents)")
|
|
174
|
+
print(" - health-check: Project health assessment (daily/weekly/release modes)")
|
|
175
|
+
print()
|
|
176
|
+
print(" Note: test-coverage workflow disabled in v4.0.0 (being redesigned)")
|
|
177
|
+
print()
|
|
178
|
+
return 1
|
|
179
|
+
|
|
180
|
+
print()
|
|
181
|
+
print("=" * 60)
|
|
182
|
+
print()
|
|
183
|
+
|
|
184
|
+
return 0
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Pattern management commands for the CLI.
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Smart-AI-Memory
|
|
4
|
+
Licensed under Fair Source License 0.9
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from attune.config import _validate_file_path
|
|
10
|
+
from attune.logging_config import get_logger
|
|
11
|
+
from attune.persistence import PatternPersistence
|
|
12
|
+
|
|
13
|
+
logger = get_logger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def cmd_patterns_list(args):
|
|
17
|
+
"""List patterns in a pattern library.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
args: Namespace object from argparse with attributes:
|
|
21
|
+
- library (str): Path to pattern library file.
|
|
22
|
+
- format (str): Library format ('json' or 'sqlite').
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
None: Prints pattern list to stdout. Exits with code 1 on failure.
|
|
26
|
+
"""
|
|
27
|
+
filepath = args.library
|
|
28
|
+
format_type = args.format
|
|
29
|
+
logger.info(f"Listing patterns from library: {filepath} (format: {format_type})")
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
if format_type == "json":
|
|
33
|
+
library = PatternPersistence.load_from_json(filepath)
|
|
34
|
+
elif format_type == "sqlite":
|
|
35
|
+
library = PatternPersistence.load_from_sqlite(filepath)
|
|
36
|
+
else:
|
|
37
|
+
logger.error(f"Unknown pattern library format: {format_type}")
|
|
38
|
+
logger.error(f"✗ Unknown format: {format_type}")
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
logger.info(f"Loaded {len(library.patterns)} patterns from {filepath}")
|
|
42
|
+
logger.info(f"=== Pattern Library: {filepath} ===\n")
|
|
43
|
+
logger.info(f"Total patterns: {len(library.patterns)}")
|
|
44
|
+
logger.info(f"Total agents: {len(library.agent_contributions)}")
|
|
45
|
+
|
|
46
|
+
if library.patterns:
|
|
47
|
+
logger.info("\nPatterns:")
|
|
48
|
+
for pattern_id, pattern in library.patterns.items():
|
|
49
|
+
logger.info(f"\n [{pattern_id}] {pattern.name}")
|
|
50
|
+
logger.info(f" Agent: {pattern.agent_id}")
|
|
51
|
+
logger.info(f" Type: {pattern.pattern_type}")
|
|
52
|
+
logger.info(f" Confidence: {pattern.confidence:.2f}")
|
|
53
|
+
logger.info(f" Usage: {pattern.usage_count}")
|
|
54
|
+
logger.info(f" Success Rate: {pattern.success_rate:.2f}")
|
|
55
|
+
except FileNotFoundError:
|
|
56
|
+
logger.error(f"Pattern library not found: {filepath}")
|
|
57
|
+
logger.error(f"✗ Pattern library not found: {filepath}")
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def cmd_patterns_export(args):
|
|
62
|
+
"""Export patterns from one format to another.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
args: Namespace object from argparse with attributes:
|
|
66
|
+
- input (str): Input file path.
|
|
67
|
+
- output (str): Output file path.
|
|
68
|
+
- input_format (str): Input format ('json' or 'sqlite').
|
|
69
|
+
- output_format (str): Output format ('json' or 'sqlite').
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
None: Exports patterns to output file. Exits with code 1 on failure.
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
ValueError: If output path is invalid or unsafe.
|
|
76
|
+
"""
|
|
77
|
+
input_file = args.input
|
|
78
|
+
input_format = args.input_format
|
|
79
|
+
output_file = args.output
|
|
80
|
+
output_format = args.output_format
|
|
81
|
+
|
|
82
|
+
logger.info(f"Exporting patterns from {input_format} to {output_format}")
|
|
83
|
+
|
|
84
|
+
# Load from input format
|
|
85
|
+
try:
|
|
86
|
+
if input_format == "json":
|
|
87
|
+
library = PatternPersistence.load_from_json(input_file)
|
|
88
|
+
elif input_format == "sqlite":
|
|
89
|
+
library = PatternPersistence.load_from_sqlite(input_file)
|
|
90
|
+
else:
|
|
91
|
+
logger.error(f"Unknown input format: {input_format}")
|
|
92
|
+
logger.error(f"✗ Unknown input format: {input_format}")
|
|
93
|
+
sys.exit(1)
|
|
94
|
+
|
|
95
|
+
logger.info(f"Loaded {len(library.patterns)} patterns from {input_file}")
|
|
96
|
+
logger.info(f"✓ Loaded {len(library.patterns)} patterns from {input_file}")
|
|
97
|
+
except (OSError, FileNotFoundError) as e:
|
|
98
|
+
# Input file not found or cannot be read
|
|
99
|
+
logger.error(f"Pattern file error: {e}")
|
|
100
|
+
logger.error(f"✗ Cannot read pattern file: {e}")
|
|
101
|
+
sys.exit(1)
|
|
102
|
+
except (ValueError, KeyError) as e:
|
|
103
|
+
# Invalid pattern data format
|
|
104
|
+
logger.error(f"Pattern data error: {e}")
|
|
105
|
+
logger.error(f"✗ Invalid pattern data: {e}")
|
|
106
|
+
sys.exit(1)
|
|
107
|
+
except Exception as e:
|
|
108
|
+
# Unexpected errors loading patterns
|
|
109
|
+
logger.exception(f"Unexpected error loading patterns: {e}")
|
|
110
|
+
logger.error(f"✗ Failed to load patterns: {e}")
|
|
111
|
+
sys.exit(1)
|
|
112
|
+
|
|
113
|
+
# Validate output path
|
|
114
|
+
validated_output = _validate_file_path(output_file)
|
|
115
|
+
|
|
116
|
+
# Save to output format
|
|
117
|
+
try:
|
|
118
|
+
if output_format == "json":
|
|
119
|
+
PatternPersistence.save_to_json(library, str(validated_output))
|
|
120
|
+
elif output_format == "sqlite":
|
|
121
|
+
PatternPersistence.save_to_sqlite(library, str(validated_output))
|
|
122
|
+
|
|
123
|
+
logger.info(f"Saved {len(library.patterns)} patterns to {output_file}")
|
|
124
|
+
logger.info(f"✓ Saved {len(library.patterns)} patterns to {output_file}")
|
|
125
|
+
except (OSError, FileNotFoundError, PermissionError) as e:
|
|
126
|
+
# Cannot write output file
|
|
127
|
+
logger.error(f"Pattern file write error: {e}")
|
|
128
|
+
logger.error(f"✗ Cannot write pattern file: {e}")
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
# Unexpected errors saving patterns
|
|
132
|
+
logger.exception(f"Unexpected error saving patterns: {e}")
|
|
133
|
+
logger.error(f"✗ Failed to save patterns: {e}")
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def cmd_patterns_resolve(args):
|
|
138
|
+
"""Resolve investigating bug patterns with root cause and fix.
|
|
139
|
+
|
|
140
|
+
Updates pattern status and adds resolution information.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
args: Namespace object from argparse with attributes:
|
|
144
|
+
- pattern_id (str | None): Pattern ID to resolve.
|
|
145
|
+
- root_cause (str | None): Root cause description.
|
|
146
|
+
- fix (str | None): Fix description.
|
|
147
|
+
- fix_code (str | None): Code snippet of the fix.
|
|
148
|
+
- time (int | None): Resolution time in minutes.
|
|
149
|
+
- status (str): New status ('resolved', 'wont_fix', etc.).
|
|
150
|
+
- patterns_dir (str): Patterns directory path.
|
|
151
|
+
- commit (str | None): Related commit hash.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
None: Updates pattern and prints result. Exits with code 1 on failure.
|
|
155
|
+
"""
|
|
156
|
+
from attune_llm.pattern_resolver import PatternResolver
|
|
157
|
+
|
|
158
|
+
resolver = PatternResolver(args.patterns_dir)
|
|
159
|
+
|
|
160
|
+
# If no bug_id, list investigating bugs
|
|
161
|
+
if not args.bug_id:
|
|
162
|
+
investigating = resolver.list_investigating()
|
|
163
|
+
if not investigating:
|
|
164
|
+
print("No bugs with 'investigating' status found.")
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
print(f"\nBugs needing resolution ({len(investigating)}):\n")
|
|
168
|
+
for bug in investigating:
|
|
169
|
+
print(f" {bug.get('bug_id', 'unknown')}")
|
|
170
|
+
print(f" Type: {bug.get('error_type', 'unknown')}")
|
|
171
|
+
print(f" File: {bug.get('file_path', 'unknown')}")
|
|
172
|
+
msg = bug.get("error_message", "N/A")
|
|
173
|
+
print(f" Message: {msg[:60]}..." if len(msg) > 60 else f" Message: {msg}")
|
|
174
|
+
print()
|
|
175
|
+
return
|
|
176
|
+
|
|
177
|
+
# Validate required args
|
|
178
|
+
if not args.root_cause or not args.fix:
|
|
179
|
+
print("✗ --root-cause and --fix are required when resolving a bug")
|
|
180
|
+
print(
|
|
181
|
+
" Example: empathy patterns resolve bug_123 --root-cause 'Null check' --fix 'Added ?.'",
|
|
182
|
+
)
|
|
183
|
+
sys.exit(1)
|
|
184
|
+
|
|
185
|
+
# Resolve the specified bug
|
|
186
|
+
success = resolver.resolve_bug(
|
|
187
|
+
bug_id=args.bug_id,
|
|
188
|
+
root_cause=args.root_cause,
|
|
189
|
+
fix_applied=args.fix,
|
|
190
|
+
fix_code=args.fix_code,
|
|
191
|
+
resolution_time_minutes=args.time or 0,
|
|
192
|
+
resolved_by=args.resolved_by or "@developer",
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
if success:
|
|
196
|
+
print(f"✓ Resolved: {args.bug_id}")
|
|
197
|
+
|
|
198
|
+
# Regenerate summary if requested
|
|
199
|
+
if not args.no_regenerate:
|
|
200
|
+
if resolver.regenerate_summary():
|
|
201
|
+
print("✓ Regenerated patterns_summary.md")
|
|
202
|
+
else:
|
|
203
|
+
print("⚠ Failed to regenerate summary")
|
|
204
|
+
else:
|
|
205
|
+
print(f"✗ Failed to resolve: {args.bug_id}")
|
|
206
|
+
print(" Use 'empathy patterns resolve' (no args) to list investigating bugs")
|
|
207
|
+
sys.exit(1)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Profiling commands for Empathy Framework CLI.
|
|
2
|
+
|
|
3
|
+
Performance profiling and memory analysis commands.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
empathy profile memory-scan # Scan for memory leaks
|
|
7
|
+
empathy profile memory-scan --json # JSON output for CI
|
|
8
|
+
empathy profile memory-test # Profile memory module
|
|
9
|
+
|
|
10
|
+
Copyright 2025 Smart-AI-Memory
|
|
11
|
+
Licensed under Fair Source License 0.9
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import typer
|
|
19
|
+
from rich.console import Console
|
|
20
|
+
|
|
21
|
+
console = Console()
|
|
22
|
+
|
|
23
|
+
# Create the profile command group
|
|
24
|
+
profile_app = typer.Typer(
|
|
25
|
+
name="profile",
|
|
26
|
+
help="Performance profiling and memory analysis",
|
|
27
|
+
no_args_is_help=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@profile_app.command("memory-scan")
|
|
32
|
+
def memory_scan(
|
|
33
|
+
path: Path = typer.Argument(
|
|
34
|
+
Path("src"),
|
|
35
|
+
help="Directory to scan for memory issues",
|
|
36
|
+
),
|
|
37
|
+
feature: str = typer.Option(
|
|
38
|
+
None,
|
|
39
|
+
"--feature",
|
|
40
|
+
"-f",
|
|
41
|
+
help="Scan files related to a specific feature",
|
|
42
|
+
),
|
|
43
|
+
min_severity: str = typer.Option(
|
|
44
|
+
"MEDIUM",
|
|
45
|
+
"--min-severity",
|
|
46
|
+
"-s",
|
|
47
|
+
help="Minimum severity to report (HIGH, MEDIUM, LOW)",
|
|
48
|
+
),
|
|
49
|
+
top: int = typer.Option(
|
|
50
|
+
10,
|
|
51
|
+
"--top",
|
|
52
|
+
"-t",
|
|
53
|
+
help="Number of hot files to show",
|
|
54
|
+
),
|
|
55
|
+
json_output: bool = typer.Option(
|
|
56
|
+
False,
|
|
57
|
+
"--json",
|
|
58
|
+
"-j",
|
|
59
|
+
help="Output in JSON format",
|
|
60
|
+
),
|
|
61
|
+
run_profile: bool = typer.Option(
|
|
62
|
+
False,
|
|
63
|
+
"--profile",
|
|
64
|
+
"-p",
|
|
65
|
+
help="Run dynamic memory profiling on hot files",
|
|
66
|
+
),
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Scan codebase for memory leak patterns.
|
|
69
|
+
|
|
70
|
+
Detects common memory issues like:
|
|
71
|
+
- sorted()[:N] patterns (should use heapq)
|
|
72
|
+
- get_all_* methods that load entire datasets
|
|
73
|
+
- Unbounded caches without eviction
|
|
74
|
+
- Large list comprehensions that could be generators
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
empathy profile memory-scan # Scan src/
|
|
78
|
+
empathy profile memory-scan src/attune # Scan specific dir
|
|
79
|
+
empathy profile memory-scan --feature "cache" # Scan cache-related files
|
|
80
|
+
empathy profile memory-scan --json > report.json # CI integration
|
|
81
|
+
"""
|
|
82
|
+
scanner_path = (
|
|
83
|
+
Path(__file__).parent.parent.parent.parent.parent / "benchmarks" / "memory_leak_scanner.py"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if not scanner_path.exists():
|
|
87
|
+
console.print("[red]Error:[/red] Memory leak scanner not found at expected path")
|
|
88
|
+
console.print(f"Expected: {scanner_path}")
|
|
89
|
+
console.print("\nThe scanner script may have been moved or renamed.")
|
|
90
|
+
console.print("Check the scripts/ directory or reinstall the package.")
|
|
91
|
+
raise typer.Exit(1)
|
|
92
|
+
|
|
93
|
+
args = [sys.executable, str(scanner_path), "--path", str(path)]
|
|
94
|
+
|
|
95
|
+
if feature:
|
|
96
|
+
args.extend(["--feature", feature])
|
|
97
|
+
if min_severity:
|
|
98
|
+
args.extend(["--min-severity", min_severity])
|
|
99
|
+
if top:
|
|
100
|
+
args.extend(["--top", str(top)])
|
|
101
|
+
if json_output:
|
|
102
|
+
args.append("--json")
|
|
103
|
+
if run_profile:
|
|
104
|
+
args.append("--profile")
|
|
105
|
+
|
|
106
|
+
subprocess.run(args, check=False)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@profile_app.command("memory-test")
|
|
110
|
+
def memory_test(
|
|
111
|
+
module: str = typer.Argument(
|
|
112
|
+
"unified",
|
|
113
|
+
help="Memory module to profile (unified, short_term, graph)",
|
|
114
|
+
),
|
|
115
|
+
) -> None:
|
|
116
|
+
"""Run memory profiling tests on memory modules.
|
|
117
|
+
|
|
118
|
+
Profiles the specified memory module and reports memory usage
|
|
119
|
+
for key operations like search, store, and retrieve.
|
|
120
|
+
|
|
121
|
+
Examples:
|
|
122
|
+
empathy profile memory-test # Profile unified memory
|
|
123
|
+
empathy profile memory-test unified # Same as above
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
import memory_profiler # noqa: F401 - check if installed
|
|
127
|
+
except ImportError:
|
|
128
|
+
console.print("[yellow]Installing memory_profiler...[/yellow]")
|
|
129
|
+
subprocess.run([sys.executable, "-m", "pip", "install", "memory_profiler"], check=True)
|
|
130
|
+
|
|
131
|
+
profile_script = (
|
|
132
|
+
Path(__file__).parent.parent.parent.parent.parent
|
|
133
|
+
/ "benchmarks"
|
|
134
|
+
/ "profile_unified_memory.py"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if not profile_script.exists():
|
|
138
|
+
console.print("[red]Error:[/red] Memory profiling script not found")
|
|
139
|
+
console.print(f"Expected: {profile_script}")
|
|
140
|
+
console.print("\nInstall memory_profiler with: pip install memory-profiler")
|
|
141
|
+
console.print("Or check that the benchmarks directory exists.")
|
|
142
|
+
raise typer.Exit(1)
|
|
143
|
+
|
|
144
|
+
console.print(f"[bold]Profiling memory module: {module}[/bold]\n")
|
|
145
|
+
subprocess.run([sys.executable, "-m", "memory_profiler", str(profile_script)], check=False)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@profile_app.command("hot-files")
|
|
149
|
+
def hot_files(
|
|
150
|
+
path: Path = typer.Argument(
|
|
151
|
+
Path("src"),
|
|
152
|
+
help="Directory to analyze",
|
|
153
|
+
),
|
|
154
|
+
top: int = typer.Option(
|
|
155
|
+
15,
|
|
156
|
+
"--top",
|
|
157
|
+
"-t",
|
|
158
|
+
help="Number of files to show",
|
|
159
|
+
),
|
|
160
|
+
) -> None:
|
|
161
|
+
"""Show files most likely to have memory issues.
|
|
162
|
+
|
|
163
|
+
Quick scan that ranks files by risk score based on
|
|
164
|
+
detected memory leak patterns.
|
|
165
|
+
|
|
166
|
+
Examples:
|
|
167
|
+
empathy profile hot-files # Scan src/
|
|
168
|
+
empathy profile hot-files --top 20 # Show top 20
|
|
169
|
+
"""
|
|
170
|
+
scanner_path = (
|
|
171
|
+
Path(__file__).parent.parent.parent.parent.parent / "benchmarks" / "memory_leak_scanner.py"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if not scanner_path.exists():
|
|
175
|
+
console.print("[red]Error:[/red] Memory leak scanner not found")
|
|
176
|
+
raise typer.Exit(1)
|
|
177
|
+
|
|
178
|
+
args = [
|
|
179
|
+
sys.executable,
|
|
180
|
+
str(scanner_path),
|
|
181
|
+
"--path",
|
|
182
|
+
str(path),
|
|
183
|
+
"--min-severity",
|
|
184
|
+
"MEDIUM",
|
|
185
|
+
"--top",
|
|
186
|
+
str(top),
|
|
187
|
+
]
|
|
188
|
+
subprocess.run(args, check=False)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@profile_app.callback()
|
|
192
|
+
def callback() -> None:
|
|
193
|
+
"""Performance profiling and memory analysis tools.
|
|
194
|
+
|
|
195
|
+
Use these commands to identify memory leaks, inefficient patterns,
|
|
196
|
+
and performance bottlenecks in your codebase.
|
|
197
|
+
|
|
198
|
+
[bold]Quick Start:[/bold]
|
|
199
|
+
empathy profile memory-scan Scan for memory issues
|
|
200
|
+
empathy profile hot-files Show riskiest files
|
|
201
|
+
empathy profile memory-test Profile memory module
|
|
202
|
+
"""
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Provider configuration commands.
|
|
2
|
+
|
|
3
|
+
Copyright 2025 Smart-AI-Memory
|
|
4
|
+
Licensed under Fair Source License 0.9
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from attune.config import _validate_file_path
|
|
10
|
+
from attune.logging_config import get_logger
|
|
11
|
+
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def cmd_provider_show(args):
|
|
16
|
+
"""Show current provider configuration (Anthropic-only as of v5.0.0).
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
args: Namespace object from argparse (no additional attributes used).
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
None: Prints Anthropic provider configuration and model mappings.
|
|
23
|
+
"""
|
|
24
|
+
from attune.models import MODEL_REGISTRY
|
|
25
|
+
from attune.models.provider_config import ProviderConfig
|
|
26
|
+
|
|
27
|
+
print("\n" + "=" * 60)
|
|
28
|
+
print("Provider Configuration (Claude-Native v5.0.0)")
|
|
29
|
+
print("=" * 60)
|
|
30
|
+
|
|
31
|
+
# Check for Anthropic API key
|
|
32
|
+
config = ProviderConfig.auto_detect()
|
|
33
|
+
if config.available_providers:
|
|
34
|
+
print("\n✓ ANTHROPIC_API_KEY detected")
|
|
35
|
+
else:
|
|
36
|
+
print("\n⚠️ ANTHROPIC_API_KEY not detected")
|
|
37
|
+
print(" Set your API key: export ANTHROPIC_API_KEY='your-key-here'")
|
|
38
|
+
print(" Get key at: https://console.anthropic.com/settings/keys")
|
|
39
|
+
|
|
40
|
+
print("\nProvider: anthropic")
|
|
41
|
+
|
|
42
|
+
# Show Anthropic models
|
|
43
|
+
print("\nModel mapping:")
|
|
44
|
+
anthropic_models = MODEL_REGISTRY.get("anthropic", {})
|
|
45
|
+
for tier in ["cheap", "capable", "premium"]:
|
|
46
|
+
model_info = anthropic_models.get(tier)
|
|
47
|
+
if model_info:
|
|
48
|
+
cost = f"${model_info.input_cost_per_million:.2f}/${model_info.output_cost_per_million:.2f} per M tokens"
|
|
49
|
+
print(f" {tier:8} → {model_info.id:40} {cost}")
|
|
50
|
+
|
|
51
|
+
print()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def cmd_provider_set(args):
|
|
55
|
+
"""Set default provider (Anthropic-only as of v5.0.0).
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
args: Namespace object from argparse with attributes:
|
|
59
|
+
- name (str): Provider name to set as default (must be 'anthropic').
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
None: Saves provider to .attune/workflows.yaml.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
SystemExit: If provider is not 'anthropic'.
|
|
66
|
+
"""
|
|
67
|
+
import sys
|
|
68
|
+
|
|
69
|
+
import yaml
|
|
70
|
+
|
|
71
|
+
provider = args.name
|
|
72
|
+
|
|
73
|
+
# Validate provider is Anthropic
|
|
74
|
+
if provider.lower() != "anthropic":
|
|
75
|
+
print(f"❌ Error: Provider '{provider}' is not supported.")
|
|
76
|
+
print(" Empathy Framework is now Claude-native (v5.0.0).")
|
|
77
|
+
print(" Only 'anthropic' provider is available.")
|
|
78
|
+
print(" See docs/CLAUDE_NATIVE.md for migration guide.")
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
|
|
81
|
+
workflows_path = Path(".attune/workflows.yaml")
|
|
82
|
+
|
|
83
|
+
# Load existing config or create new
|
|
84
|
+
if workflows_path.exists():
|
|
85
|
+
with open(workflows_path) as f:
|
|
86
|
+
config = yaml.safe_load(f) or {}
|
|
87
|
+
else:
|
|
88
|
+
config = {}
|
|
89
|
+
workflows_path.parent.mkdir(parents=True, exist_ok=True)
|
|
90
|
+
|
|
91
|
+
config["default_provider"] = provider
|
|
92
|
+
|
|
93
|
+
validated_workflows_path = _validate_file_path(str(workflows_path))
|
|
94
|
+
with open(validated_workflows_path, "w") as f:
|
|
95
|
+
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
96
|
+
|
|
97
|
+
print(f"✓ Default provider set to: {provider}")
|
|
98
|
+
print(f" Saved to: {validated_workflows_path}")
|