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,120 @@
|
|
|
1
|
+
"""CLI tools for the Empathy Software Plugin.
|
|
2
|
+
|
|
3
|
+
This package exists alongside a legacy ``cli.py`` module at the
|
|
4
|
+
package root. To maintain backwards compatibility with existing
|
|
5
|
+
callers and tests, we dynamically import the root ``cli.py`` and
|
|
6
|
+
re-export its public API from here.
|
|
7
|
+
|
|
8
|
+
Tests also expect a couple of small helper functions to exist at the
|
|
9
|
+
package level:
|
|
10
|
+
|
|
11
|
+
* ``get_logger()`` – returns the configured logger instance
|
|
12
|
+
* ``get_global_registry()`` – indirection around the plugin registry
|
|
13
|
+
|
|
14
|
+
These helpers make the CLI easier to patch in tests while keeping the
|
|
15
|
+
core implementation in the shared registry module.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import importlib.util
|
|
19
|
+
import os
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from .inspect import main as inspect_main
|
|
23
|
+
|
|
24
|
+
# Re-export from parent cli.py module for backwards compatibility
|
|
25
|
+
# This handles the cli/ package shadowing the cli.py file
|
|
26
|
+
_parent_dir = os.path.dirname(os.path.dirname(__file__))
|
|
27
|
+
_cli_module_path = os.path.join(_parent_dir, "cli.py")
|
|
28
|
+
|
|
29
|
+
logger = None # Will be populated if cli.py is found
|
|
30
|
+
Colors = None # type: ignore[assignment]
|
|
31
|
+
analyze_project = None # type: ignore[assignment]
|
|
32
|
+
display_wizard_results = None # type: ignore[assignment]
|
|
33
|
+
gather_project_context = None # type: ignore[assignment]
|
|
34
|
+
list_wizards = None # type: ignore[assignment]
|
|
35
|
+
main = None # type: ignore[assignment]
|
|
36
|
+
scan_command = None # type: ignore[assignment]
|
|
37
|
+
wizard_info = None # type: ignore[assignment]
|
|
38
|
+
print_header = None # type: ignore[assignment]
|
|
39
|
+
print_alert = None # type: ignore[assignment]
|
|
40
|
+
print_success = None # type: ignore[assignment]
|
|
41
|
+
print_error = None # type: ignore[assignment]
|
|
42
|
+
print_info = None # type: ignore[assignment]
|
|
43
|
+
print_summary = None # type: ignore[assignment]
|
|
44
|
+
parse_ai_calls = None # type: ignore[assignment]
|
|
45
|
+
parse_git_history = None # type: ignore[assignment]
|
|
46
|
+
prepare_wizard_context = None # type: ignore[assignment]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if os.path.exists(_cli_module_path):
|
|
50
|
+
_spec = importlib.util.spec_from_file_location("_cli_module", _cli_module_path)
|
|
51
|
+
if _spec is not None and _spec.loader is not None:
|
|
52
|
+
_cli_module = importlib.util.module_from_spec(_spec)
|
|
53
|
+
_spec.loader.exec_module(_cli_module)
|
|
54
|
+
|
|
55
|
+
# Re-export all items from cli.py
|
|
56
|
+
logger = _cli_module.logger
|
|
57
|
+
Colors = _cli_module.Colors
|
|
58
|
+
analyze_project = _cli_module.analyze_project
|
|
59
|
+
display_wizard_results = _cli_module.display_wizard_results
|
|
60
|
+
gather_project_context = _cli_module.gather_project_context
|
|
61
|
+
list_wizards = _cli_module.list_wizards
|
|
62
|
+
main = _cli_module.main
|
|
63
|
+
scan_command = _cli_module.scan_command
|
|
64
|
+
wizard_info = _cli_module.wizard_info
|
|
65
|
+
print_header = _cli_module.print_header
|
|
66
|
+
print_alert = _cli_module.print_alert
|
|
67
|
+
print_success = _cli_module.print_success
|
|
68
|
+
print_error = _cli_module.print_error
|
|
69
|
+
print_info = _cli_module.print_info
|
|
70
|
+
print_summary = _cli_module.print_summary
|
|
71
|
+
parse_ai_calls = _cli_module.parse_ai_calls
|
|
72
|
+
parse_git_history = _cli_module.parse_git_history
|
|
73
|
+
prepare_wizard_context = _cli_module.prepare_wizard_context
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_logger():
|
|
77
|
+
"""Return the CLI logger instance.
|
|
78
|
+
|
|
79
|
+
This thin wrapper exists so tests can patch the logger via
|
|
80
|
+
``empathy_software_plugin.cli.get_logger`` without reaching into
|
|
81
|
+
the underlying implementation module.
|
|
82
|
+
"""
|
|
83
|
+
return logger
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_global_registry() -> Any:
|
|
87
|
+
"""Return the global plugin registry used by the software plugin.
|
|
88
|
+
|
|
89
|
+
The concrete implementation lives in the core plugin registry
|
|
90
|
+
module. We import lazily to avoid import cycles and to keep this
|
|
91
|
+
function easy to patch in tests via ``unittest.mock.patch``.
|
|
92
|
+
"""
|
|
93
|
+
from attune.plugins.registry import get_global_registry as _get_global_registry
|
|
94
|
+
|
|
95
|
+
return _get_global_registry()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
__all__ = [
|
|
99
|
+
"Colors",
|
|
100
|
+
"analyze_project",
|
|
101
|
+
"display_wizard_results",
|
|
102
|
+
"gather_project_context",
|
|
103
|
+
"get_global_registry",
|
|
104
|
+
"get_logger",
|
|
105
|
+
"inspect_main",
|
|
106
|
+
"list_wizards",
|
|
107
|
+
"logger",
|
|
108
|
+
"main",
|
|
109
|
+
"parse_ai_calls",
|
|
110
|
+
"parse_git_history",
|
|
111
|
+
"prepare_wizard_context",
|
|
112
|
+
"print_alert",
|
|
113
|
+
"print_error",
|
|
114
|
+
"print_header",
|
|
115
|
+
"print_info",
|
|
116
|
+
"print_success",
|
|
117
|
+
"print_summary",
|
|
118
|
+
"scan_command",
|
|
119
|
+
"wizard_info",
|
|
120
|
+
]
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"""Code Inspection CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for the Code Inspection Agent Pipeline.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
empathy-inspect [path] [options]
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
empathy-inspect . # Inspect current directory
|
|
10
|
+
empathy-inspect ./src --parallel # Parallel mode
|
|
11
|
+
empathy-inspect . --format json # JSON output
|
|
12
|
+
empathy-inspect . --staged # Only staged changes
|
|
13
|
+
empathy-inspect . --fix # Auto-fix safe issues
|
|
14
|
+
|
|
15
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
16
|
+
Licensed under Fair Source 0.9
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import asyncio
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def run_auto_fix(project_path: str, verbose: bool = False) -> int:
|
|
27
|
+
"""Run auto-fix using ruff.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
project_path: Path to project to fix
|
|
31
|
+
verbose: Whether to show verbose output
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Number of issues fixed
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
import subprocess
|
|
38
|
+
|
|
39
|
+
fixed_count = 0
|
|
40
|
+
|
|
41
|
+
# Run ruff check with --fix
|
|
42
|
+
try:
|
|
43
|
+
print("\nRunning ruff --fix...")
|
|
44
|
+
result = subprocess.run(
|
|
45
|
+
["ruff", "check", project_path, "--fix", "--exit-zero"],
|
|
46
|
+
check=False,
|
|
47
|
+
capture_output=True,
|
|
48
|
+
text=True,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if verbose and result.stdout:
|
|
52
|
+
print(result.stdout)
|
|
53
|
+
|
|
54
|
+
# Count fixes from output
|
|
55
|
+
if "Fixed" in result.stdout:
|
|
56
|
+
# Parse "Fixed X errors" or similar
|
|
57
|
+
import re
|
|
58
|
+
|
|
59
|
+
match = re.search(r"Fixed (\d+)", result.stdout)
|
|
60
|
+
if match:
|
|
61
|
+
fixed_count += int(match.group(1))
|
|
62
|
+
|
|
63
|
+
except FileNotFoundError:
|
|
64
|
+
print("Warning: ruff not found. Install with: pip install ruff")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
print(f"Warning: ruff fix failed: {e}")
|
|
67
|
+
|
|
68
|
+
# Run ruff format for formatting fixes
|
|
69
|
+
try:
|
|
70
|
+
print("Running ruff format...")
|
|
71
|
+
result = subprocess.run(
|
|
72
|
+
["ruff", "format", project_path],
|
|
73
|
+
check=False,
|
|
74
|
+
capture_output=True,
|
|
75
|
+
text=True,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if verbose and result.stdout:
|
|
79
|
+
print(result.stdout)
|
|
80
|
+
|
|
81
|
+
# Count formatted files
|
|
82
|
+
if "file" in result.stderr.lower():
|
|
83
|
+
import re
|
|
84
|
+
|
|
85
|
+
match = re.search(r"(\d+) file", result.stderr)
|
|
86
|
+
if match:
|
|
87
|
+
fixed_count += int(match.group(1))
|
|
88
|
+
|
|
89
|
+
except FileNotFoundError:
|
|
90
|
+
pass # Already warned above
|
|
91
|
+
except Exception as e:
|
|
92
|
+
if verbose:
|
|
93
|
+
print(f"Warning: ruff format failed: {e}")
|
|
94
|
+
|
|
95
|
+
# Run isort for import sorting
|
|
96
|
+
try:
|
|
97
|
+
print("Running isort...")
|
|
98
|
+
result = subprocess.run(
|
|
99
|
+
["isort", project_path, "--profile", "black"],
|
|
100
|
+
check=False,
|
|
101
|
+
capture_output=True,
|
|
102
|
+
text=True,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
if verbose and result.stdout:
|
|
106
|
+
print(result.stdout)
|
|
107
|
+
|
|
108
|
+
# isort shows "Fixing" for each file
|
|
109
|
+
if "Fixing" in result.stdout:
|
|
110
|
+
fixed_count += result.stdout.count("Fixing")
|
|
111
|
+
|
|
112
|
+
except FileNotFoundError:
|
|
113
|
+
if verbose:
|
|
114
|
+
print("Note: isort not found. Install with: pip install isort")
|
|
115
|
+
except Exception as e:
|
|
116
|
+
if verbose:
|
|
117
|
+
print(f"Warning: isort failed: {e}")
|
|
118
|
+
|
|
119
|
+
return fixed_count
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def parse_args() -> argparse.Namespace:
|
|
123
|
+
"""Parse command-line arguments."""
|
|
124
|
+
parser = argparse.ArgumentParser(
|
|
125
|
+
prog="empathy-inspect",
|
|
126
|
+
description="Code Inspection Agent Pipeline",
|
|
127
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
128
|
+
epilog="""
|
|
129
|
+
Examples:
|
|
130
|
+
empathy-inspect . Inspect current directory
|
|
131
|
+
empathy-inspect ./src --parallel Run static checks in parallel
|
|
132
|
+
empathy-inspect . --format json Output as JSON
|
|
133
|
+
empathy-inspect . --staged Inspect staged git changes only
|
|
134
|
+
empathy-inspect . --quick Quick mode (skip slow checks)
|
|
135
|
+
""",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
parser.add_argument(
|
|
139
|
+
"path",
|
|
140
|
+
nargs="?",
|
|
141
|
+
default=".",
|
|
142
|
+
help="Path to inspect (default: current directory)",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
parser.add_argument(
|
|
146
|
+
"--parallel",
|
|
147
|
+
action="store_true",
|
|
148
|
+
default=True,
|
|
149
|
+
help="Run Phase 1 tools in parallel (default: True)",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
parser.add_argument(
|
|
153
|
+
"--no-parallel",
|
|
154
|
+
action="store_true",
|
|
155
|
+
help="Disable parallel execution",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
parser.add_argument(
|
|
159
|
+
"--learning",
|
|
160
|
+
action="store_true",
|
|
161
|
+
default=True,
|
|
162
|
+
help="Enable pattern learning (default: True)",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
"--no-learning",
|
|
167
|
+
action="store_true",
|
|
168
|
+
help="Disable pattern learning",
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
parser.add_argument(
|
|
172
|
+
"--format",
|
|
173
|
+
"-f",
|
|
174
|
+
choices=["terminal", "json", "markdown", "sarif", "html"],
|
|
175
|
+
default="terminal",
|
|
176
|
+
help="Output format (default: terminal). Use 'sarif' for GitHub Actions.",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
parser.add_argument(
|
|
180
|
+
"--staged",
|
|
181
|
+
action="store_true",
|
|
182
|
+
help="Only inspect staged git changes",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
parser.add_argument(
|
|
186
|
+
"--changed",
|
|
187
|
+
action="store_true",
|
|
188
|
+
help="Only inspect changed files (vs HEAD)",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
parser.add_argument(
|
|
192
|
+
"--quick",
|
|
193
|
+
"-q",
|
|
194
|
+
action="store_true",
|
|
195
|
+
help="Quick mode (skip slow checks like deep debugging)",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
parser.add_argument(
|
|
199
|
+
"--fix",
|
|
200
|
+
action="store_true",
|
|
201
|
+
help="Auto-fix safe issues (formatting, imports)",
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
parser.add_argument(
|
|
205
|
+
"--verbose",
|
|
206
|
+
"-v",
|
|
207
|
+
action="store_true",
|
|
208
|
+
help="Verbose output",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
parser.add_argument(
|
|
212
|
+
"--output",
|
|
213
|
+
"-o",
|
|
214
|
+
type=str,
|
|
215
|
+
help="Write report to file",
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
parser.add_argument(
|
|
219
|
+
"--exclude",
|
|
220
|
+
"-e",
|
|
221
|
+
type=str,
|
|
222
|
+
action="append",
|
|
223
|
+
default=[],
|
|
224
|
+
help="Glob patterns to exclude (can be used multiple times)",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Baseline/suppression options
|
|
228
|
+
parser.add_argument(
|
|
229
|
+
"--no-baseline",
|
|
230
|
+
action="store_true",
|
|
231
|
+
help="Disable baseline filtering (show all findings)",
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
parser.add_argument(
|
|
235
|
+
"--baseline-init",
|
|
236
|
+
action="store_true",
|
|
237
|
+
help="Create an empty .empathy-baseline.json file",
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
parser.add_argument(
|
|
241
|
+
"--baseline-cleanup",
|
|
242
|
+
action="store_true",
|
|
243
|
+
help="Remove expired suppressions from baseline",
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
return parser.parse_args()
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
async def run_inspection(args: argparse.Namespace) -> int:
|
|
250
|
+
"""Run the inspection and return exit code."""
|
|
251
|
+
# Import here to avoid slow startup
|
|
252
|
+
from agents.code_inspection import CodeInspectionAgent
|
|
253
|
+
|
|
254
|
+
# Resolve path
|
|
255
|
+
project_path = str(Path(args.path).resolve())
|
|
256
|
+
|
|
257
|
+
# Determine target mode
|
|
258
|
+
if args.staged:
|
|
259
|
+
target_mode = "staged"
|
|
260
|
+
elif args.changed:
|
|
261
|
+
target_mode = "changed"
|
|
262
|
+
else:
|
|
263
|
+
target_mode = "all"
|
|
264
|
+
|
|
265
|
+
# Create agent
|
|
266
|
+
agent = CodeInspectionAgent(
|
|
267
|
+
parallel_mode=args.parallel and not args.no_parallel,
|
|
268
|
+
learning_enabled=args.learning and not args.no_learning,
|
|
269
|
+
baseline_enabled=not args.no_baseline,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Configure verbose logging
|
|
273
|
+
if args.verbose:
|
|
274
|
+
import logging
|
|
275
|
+
|
|
276
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
277
|
+
|
|
278
|
+
# Run inspection
|
|
279
|
+
state = await agent.inspect(
|
|
280
|
+
project_path=project_path,
|
|
281
|
+
target_mode=target_mode,
|
|
282
|
+
exclude_patterns=args.exclude if args.exclude else None,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Format report
|
|
286
|
+
report = agent.format_report(state, args.format)
|
|
287
|
+
|
|
288
|
+
# Output
|
|
289
|
+
if args.output:
|
|
290
|
+
output_path = Path(args.output)
|
|
291
|
+
output_path.write_text(report)
|
|
292
|
+
print(f"Report written to {output_path}")
|
|
293
|
+
else:
|
|
294
|
+
print(report)
|
|
295
|
+
|
|
296
|
+
# Auto-fix if requested
|
|
297
|
+
if args.fix:
|
|
298
|
+
fixed_count = await run_auto_fix(project_path, args.verbose)
|
|
299
|
+
if fixed_count > 0:
|
|
300
|
+
print(f"\nAuto-fixed {fixed_count} issues. Run inspection again to verify.")
|
|
301
|
+
|
|
302
|
+
# Return exit code based on health status
|
|
303
|
+
if state["health_status"] == "fail":
|
|
304
|
+
return 1
|
|
305
|
+
if state["health_status"] == "warn":
|
|
306
|
+
return 0 # Warn but don't fail
|
|
307
|
+
return 0
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def handle_baseline_commands(args: argparse.Namespace) -> bool:
|
|
311
|
+
"""Handle baseline-specific commands.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
True if a baseline command was handled (and should exit)
|
|
315
|
+
|
|
316
|
+
"""
|
|
317
|
+
from agents.code_inspection.baseline import BaselineManager, create_baseline_file
|
|
318
|
+
|
|
319
|
+
project_path = str(Path(args.path).resolve())
|
|
320
|
+
|
|
321
|
+
if args.baseline_init:
|
|
322
|
+
baseline_path = create_baseline_file(project_path)
|
|
323
|
+
print(f"Created baseline file: {baseline_path}")
|
|
324
|
+
return True
|
|
325
|
+
|
|
326
|
+
if args.baseline_cleanup:
|
|
327
|
+
manager = BaselineManager(project_path)
|
|
328
|
+
if manager.load():
|
|
329
|
+
removed = manager.cleanup_expired()
|
|
330
|
+
print(f"Removed {removed} expired suppressions")
|
|
331
|
+
else:
|
|
332
|
+
print("No baseline file found")
|
|
333
|
+
return True
|
|
334
|
+
|
|
335
|
+
return False
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def main():
|
|
339
|
+
"""Main entry point for CLI."""
|
|
340
|
+
args = parse_args()
|
|
341
|
+
|
|
342
|
+
try:
|
|
343
|
+
# Handle baseline commands first
|
|
344
|
+
if handle_baseline_commands(args):
|
|
345
|
+
sys.exit(0)
|
|
346
|
+
|
|
347
|
+
exit_code = asyncio.run(run_inspection(args))
|
|
348
|
+
sys.exit(exit_code)
|
|
349
|
+
except KeyboardInterrupt:
|
|
350
|
+
print("\nInspection cancelled.")
|
|
351
|
+
sys.exit(130)
|
|
352
|
+
except Exception as e:
|
|
353
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
354
|
+
if args.verbose:
|
|
355
|
+
import traceback
|
|
356
|
+
|
|
357
|
+
traceback.print_exc()
|
|
358
|
+
sys.exit(1)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
if __name__ == "__main__":
|
|
362
|
+
main()
|