crackerjack 0.37.9__py3-none-any.whl → 0.45.2__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.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +30 -1
- crackerjack/__main__.py +342 -1263
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +27 -5
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
- crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
- crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +40 -12
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +49 -53
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +6 -8
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/performance_agent.py +121 -1152
- crackerjack/agents/refactoring_agent.py +156 -655
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +19 -1605
- crackerjack/api.py +5 -7
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +1 -1
- crackerjack/cli/cache_handlers.py +23 -18
- crackerjack/cli/cache_handlers_enhanced.py +1 -4
- crackerjack/cli/facade.py +70 -8
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +249 -49
- crackerjack/cli/interactive.py +8 -5
- crackerjack/cli/options.py +203 -110
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +60 -24
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +256 -0
- crackerjack/config/global_lock_config.py +191 -54
- crackerjack/config/hooks.py +188 -16
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/async_workflow_orchestrator.py +79 -53
- crackerjack/core/autofix_coordinator.py +22 -9
- crackerjack/core/container.py +10 -9
- crackerjack/core/enhanced_container.py +9 -9
- crackerjack/core/performance.py +1 -1
- crackerjack/core/performance_monitor.py +5 -3
- crackerjack/core/phase_coordinator.py +1018 -634
- crackerjack/core/proactive_workflow.py +3 -3
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +167 -23
- crackerjack/core/session_coordinator.py +187 -382
- crackerjack/core/timeout_manager.py +161 -44
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +1247 -953
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/documentation/dual_output_generator.py +11 -9
- crackerjack/documentation/reference_generator.py +104 -59
- crackerjack/dynamic_config.py +52 -61
- crackerjack/errors.py +1 -1
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +2 -0
- crackerjack/executors/async_hook_executor.py +539 -77
- crackerjack/executors/cached_hook_executor.py +3 -3
- crackerjack/executors/hook_executor.py +967 -102
- crackerjack/executors/hook_lock_manager.py +31 -22
- crackerjack/executors/individual_hook_executor.py +66 -32
- crackerjack/executors/lsp_aware_hook_executor.py +136 -57
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +23 -7
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +8 -9
- crackerjack/intelligence/README.md +557 -0
- crackerjack/interactive.py +37 -10
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/async_hook_manager.py +41 -57
- crackerjack/managers/hook_manager.py +449 -79
- crackerjack/managers/publish_manager.py +81 -36
- crackerjack/managers/test_command_builder.py +290 -12
- crackerjack/managers/test_executor.py +93 -8
- crackerjack/managers/test_manager.py +1082 -75
- crackerjack/managers/test_progress.py +118 -26
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/cache.py +25 -2
- crackerjack/mcp/client_runner.py +35 -18
- crackerjack/mcp/context.py +9 -9
- crackerjack/mcp/dashboard.py +24 -8
- crackerjack/mcp/enhanced_progress_monitor.py +34 -23
- crackerjack/mcp/file_monitor.py +27 -6
- crackerjack/mcp/progress_components.py +45 -34
- crackerjack/mcp/progress_monitor.py +6 -9
- crackerjack/mcp/rate_limiter.py +11 -7
- crackerjack/mcp/server.py +2 -0
- crackerjack/mcp/server_core.py +187 -55
- crackerjack/mcp/service_watchdog.py +12 -9
- crackerjack/mcp/task_manager.py +2 -2
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/core_tools.py +75 -52
- crackerjack/mcp/tools/execution_tools.py +87 -31
- crackerjack/mcp/tools/intelligence_tools.py +2 -2
- crackerjack/mcp/tools/proactive_tools.py +1 -1
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +180 -132
- crackerjack/mcp/tools/workflow_executor.py +87 -46
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/app.py +11 -1
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +27 -4
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
- crackerjack/mcp/websocket/server.py +1 -3
- crackerjack/mcp/websocket/websocket_handler.py +107 -6
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +10 -1
- crackerjack/models/config.py +639 -22
- crackerjack/models/config_adapter.py +6 -6
- crackerjack/models/protocols.py +1167 -23
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +19 -3
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/ai_agent_watchdog.py +5 -4
- crackerjack/monitoring/metrics_collector.py +4 -3
- crackerjack/monitoring/regression_prevention.py +4 -3
- crackerjack/monitoring/websocket_server.py +4 -241
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +20 -67
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +13 -6
- crackerjack/orchestration/execution_strategies.py +6 -6
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +1 -1
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/hooks.py +3 -2
- crackerjack/plugins/loader.py +3 -3
- crackerjack/plugins/managers.py +1 -1
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +8 -21
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/api_extractor.py +5 -3
- crackerjack/services/bounded_status_operations.py +45 -5
- crackerjack/services/cache.py +249 -318
- crackerjack/services/changelog_automation.py +7 -3
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +83 -39
- crackerjack/services/config_merge.py +9 -6
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +13 -26
- crackerjack/services/coverage_badge_service.py +6 -4
- crackerjack/services/coverage_ratchet.py +53 -27
- crackerjack/services/debug.py +18 -7
- crackerjack/services/dependency_analyzer.py +4 -4
- crackerjack/services/dependency_monitor.py +13 -13
- crackerjack/services/documentation_generator.py +4 -2
- crackerjack/services/documentation_service.py +62 -33
- crackerjack/services/enhanced_filesystem.py +81 -27
- crackerjack/services/enterprise_optimizer.py +1 -1
- crackerjack/services/error_pattern_analyzer.py +10 -10
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +5 -7
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +80 -109
- crackerjack/services/git.py +99 -5
- crackerjack/services/health_metrics.py +4 -6
- crackerjack/services/heatmap_generator.py +12 -3
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +101 -49
- crackerjack/services/log_manager.py +2 -2
- crackerjack/services/logging.py +120 -68
- crackerjack/services/lsp_client.py +12 -12
- crackerjack/services/memory_optimizer.py +27 -22
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
- crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
- crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
- crackerjack/services/parallel_executor.py +166 -55
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +21 -8
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
- crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
- crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
- crackerjack/services/regex_patterns.py +58 -2987
- crackerjack/services/regex_utils.py +55 -29
- crackerjack/services/secure_status_formatter.py +42 -15
- crackerjack/services/secure_subprocess.py +35 -2
- crackerjack/services/security.py +16 -8
- crackerjack/services/server_manager.py +40 -51
- crackerjack/services/smart_scheduling.py +46 -6
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/thread_safe_status_collector.py +1 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +9 -5
- crackerjack/services/unified_config.py +43 -351
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +6 -4
- crackerjack/services/version_checker.py +14 -8
- crackerjack/services/zuban_lsp_service.py +5 -4
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/init.md +2 -12
- crackerjack/slash_commands/run.md +84 -50
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_regex_patterns.py +7 -3
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack/managers/test_manager_backup.py +0 -1075
- crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
- crackerjack/mixins/__init__.py +0 -3
- crackerjack/mixins/error_handling.py +0 -145
- crackerjack/services/config.py +0 -358
- crackerjack/ui/server_panels.py +0 -125
- crackerjack-0.37.9.dist-info/RECORD +0 -231
- /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
- /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"""CLI handlers for semantic search operations."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from textwrap import dedent
|
|
5
|
+
|
|
6
|
+
from acb import console
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from crackerjack.models.semantic_models import SearchQuery, SemanticConfig
|
|
11
|
+
from crackerjack.services.vector_store import VectorStore
|
|
12
|
+
|
|
13
|
+
# console imported from acb
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def handle_semantic_index(file_path: str) -> None:
|
|
17
|
+
"""Handle indexing a file for semantic search.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
file_path: Path to the file or directory to index
|
|
21
|
+
"""
|
|
22
|
+
try:
|
|
23
|
+
console.print(f"[cyan]Indexing file for semantic search:[/cyan] {file_path}")
|
|
24
|
+
|
|
25
|
+
# Validate path
|
|
26
|
+
path_obj = Path(file_path)
|
|
27
|
+
if not path_obj.exists():
|
|
28
|
+
console.print(f"[red]Error:[/red] File does not exist: {file_path}")
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
# Create default configuration
|
|
32
|
+
config = SemanticConfig(
|
|
33
|
+
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
|
|
34
|
+
chunk_size=512,
|
|
35
|
+
chunk_overlap=50,
|
|
36
|
+
max_search_results=10,
|
|
37
|
+
similarity_threshold=0.7,
|
|
38
|
+
embedding_dimension=384,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Initialize vector store with persistent database
|
|
42
|
+
db_path = Path.cwd() / ".crackerjack" / "semantic_index.db"
|
|
43
|
+
db_path.parent.mkdir(exist_ok=True)
|
|
44
|
+
vector_store = VectorStore(config, db_path=db_path)
|
|
45
|
+
|
|
46
|
+
if path_obj.is_file():
|
|
47
|
+
# Index single file
|
|
48
|
+
embeddings = vector_store.index_file(path_obj)
|
|
49
|
+
console.print(
|
|
50
|
+
f"[green]✅ Successfully indexed {len(embeddings)} chunks from {path_obj.name}[/green]"
|
|
51
|
+
)
|
|
52
|
+
else:
|
|
53
|
+
# Index directory (recursively)
|
|
54
|
+
total_files = 0
|
|
55
|
+
total_chunks = 0
|
|
56
|
+
|
|
57
|
+
for file in path_obj.rglob("*.py"): # Index Python files
|
|
58
|
+
try:
|
|
59
|
+
embeddings = vector_store.index_file(file)
|
|
60
|
+
total_files += 1
|
|
61
|
+
total_chunks += len(embeddings)
|
|
62
|
+
console.print(
|
|
63
|
+
f"[dim]Indexed {len(embeddings)} chunks from {file.relative_to(path_obj)}[/dim]"
|
|
64
|
+
)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
console.print(
|
|
67
|
+
f"[yellow]Warning:[/yellow] Failed to index {file}: {e}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
console.print(
|
|
71
|
+
f"[green]✅ Successfully indexed {total_files} files with {total_chunks} total chunks[/green]"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Show index stats
|
|
75
|
+
stats = vector_store.get_stats()
|
|
76
|
+
console.print(
|
|
77
|
+
f"[cyan]Index now contains:[/cyan] {stats.total_files} files, {stats.total_chunks} chunks"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
console.print(
|
|
82
|
+
f"[red]Error indexing file:[/red] {str(e).replace('[', '\\[').replace(']', '\\]')}"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def handle_semantic_search(query: str) -> None:
|
|
87
|
+
"""Handle semantic search across indexed files.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
query: The search query text
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
console.print(f"[cyan]Performing semantic search for:[/cyan] {query}")
|
|
94
|
+
|
|
95
|
+
# Create default configuration
|
|
96
|
+
config = SemanticConfig(
|
|
97
|
+
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
|
|
98
|
+
chunk_size=512,
|
|
99
|
+
chunk_overlap=50,
|
|
100
|
+
max_search_results=10,
|
|
101
|
+
similarity_threshold=0.7,
|
|
102
|
+
embedding_dimension=384,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Create search query
|
|
106
|
+
search_query = SearchQuery(
|
|
107
|
+
query=query,
|
|
108
|
+
max_results=10,
|
|
109
|
+
min_similarity=0.3, # Lower threshold for CLI to show more results
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Initialize vector store with persistent database
|
|
113
|
+
db_path = Path.cwd() / ".crackerjack" / "semantic_index.db"
|
|
114
|
+
db_path.parent.mkdir(exist_ok=True)
|
|
115
|
+
vector_store = VectorStore(config, db_path=db_path)
|
|
116
|
+
results = vector_store.search(search_query)
|
|
117
|
+
|
|
118
|
+
if not results:
|
|
119
|
+
console.print(
|
|
120
|
+
"[yellow]No results found. Try a different search term or index more files.[/yellow]"
|
|
121
|
+
)
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
# Display results in a table
|
|
125
|
+
table = Table(title=f"Semantic Search Results for: '{query}'")
|
|
126
|
+
table.add_column("File", style="cyan", no_wrap=True)
|
|
127
|
+
table.add_column("Lines", style="magenta", justify="center")
|
|
128
|
+
table.add_column("Score", style="green", justify="center")
|
|
129
|
+
table.add_column("Content Preview", style="white")
|
|
130
|
+
|
|
131
|
+
for result in results:
|
|
132
|
+
# Truncate content for display
|
|
133
|
+
content_preview = (
|
|
134
|
+
result.content[:80] + "..."
|
|
135
|
+
if len(result.content) > 80
|
|
136
|
+
else result.content
|
|
137
|
+
)
|
|
138
|
+
content_preview = content_preview.replace("\n", " ").strip()
|
|
139
|
+
|
|
140
|
+
# Escape Rich markup in content to prevent rendering issues
|
|
141
|
+
content_preview = content_preview.replace("[", "\\[").replace("]", "\\]")
|
|
142
|
+
|
|
143
|
+
table.add_row(
|
|
144
|
+
str(result.file_path.name),
|
|
145
|
+
f"{result.start_line}-{result.end_line}",
|
|
146
|
+
f"{result.similarity_score:.3f}",
|
|
147
|
+
content_preview,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
console.print(
|
|
151
|
+
Panel(table, title="Semantic Search Results", border_style="cyan")
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Show detailed content for top result
|
|
155
|
+
if results:
|
|
156
|
+
top_result = results[0]
|
|
157
|
+
# Escape Rich markup in the detailed content
|
|
158
|
+
escaped_content = (
|
|
159
|
+
top_result.content.strip().replace("[", "\\[").replace("]", "\\]")
|
|
160
|
+
)
|
|
161
|
+
console.print(
|
|
162
|
+
Panel(
|
|
163
|
+
dedent(f"""
|
|
164
|
+
[cyan]Top Result Details:[/cyan]
|
|
165
|
+
[bold]File:[/bold] {top_result.file_path}
|
|
166
|
+
[bold]Lines:[/bold] {top_result.start_line}-{top_result.end_line}
|
|
167
|
+
[bold]Similarity Score:[/bold] {top_result.similarity_score:.4f}
|
|
168
|
+
|
|
169
|
+
[bold]Content:[/bold]
|
|
170
|
+
{escaped_content}
|
|
171
|
+
""").strip(),
|
|
172
|
+
title="🎯 Best Match",
|
|
173
|
+
border_style="green",
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
console.print(
|
|
179
|
+
f"[red]Error performing search:[/red] {str(e).replace('[', '\\[').replace(']', '\\]')}"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def handle_semantic_stats() -> None:
|
|
184
|
+
"""Handle displaying semantic search index statistics."""
|
|
185
|
+
try:
|
|
186
|
+
console.print("[cyan]Retrieving semantic search index statistics...[/cyan]")
|
|
187
|
+
|
|
188
|
+
# Create default configuration
|
|
189
|
+
config = SemanticConfig(
|
|
190
|
+
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
|
|
191
|
+
chunk_size=512,
|
|
192
|
+
chunk_overlap=50,
|
|
193
|
+
max_search_results=10,
|
|
194
|
+
similarity_threshold=0.7,
|
|
195
|
+
embedding_dimension=384,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Initialize vector store with persistent database
|
|
199
|
+
db_path = Path.cwd() / ".crackerjack" / "semantic_index.db"
|
|
200
|
+
db_path.parent.mkdir(exist_ok=True)
|
|
201
|
+
vector_store = VectorStore(config, db_path=db_path)
|
|
202
|
+
stats = vector_store.get_stats()
|
|
203
|
+
|
|
204
|
+
# Create stats table
|
|
205
|
+
table = Table(title="Semantic Search Index Statistics")
|
|
206
|
+
table.add_column("Metric", style="cyan", no_wrap=True)
|
|
207
|
+
table.add_column("Value", style="green")
|
|
208
|
+
|
|
209
|
+
table.add_row("Total Files", str(stats.total_files))
|
|
210
|
+
table.add_row("Total Chunks", str(stats.total_chunks))
|
|
211
|
+
table.add_row("Index Size", f"{stats.index_size_mb:.2f} MB")
|
|
212
|
+
|
|
213
|
+
# Calculate average chunks per file
|
|
214
|
+
avg_chunks = (
|
|
215
|
+
stats.total_chunks / stats.total_files if stats.total_files > 0 else 0.0
|
|
216
|
+
)
|
|
217
|
+
table.add_row("Average Chunks per File", f"{avg_chunks:.1f}")
|
|
218
|
+
|
|
219
|
+
table.add_row("Embedding Model", config.embedding_model)
|
|
220
|
+
table.add_row("Embedding Dimension", "384") # ONNX fallback uses 384 dimensions
|
|
221
|
+
|
|
222
|
+
if stats.last_updated:
|
|
223
|
+
table.add_row(
|
|
224
|
+
"Last Updated", stats.last_updated.strftime("%Y-%m-%d %H:%M:%S")
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
console.print(Panel(table, border_style="cyan"))
|
|
228
|
+
|
|
229
|
+
if stats.total_files == 0:
|
|
230
|
+
console.print(
|
|
231
|
+
Panel(
|
|
232
|
+
"[yellow]The semantic search index is empty. Use [bold]--index[/bold] to add files.[/yellow]",
|
|
233
|
+
title="💡 Tip",
|
|
234
|
+
border_style="yellow",
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
except Exception as e:
|
|
239
|
+
console.print(
|
|
240
|
+
f"[red]Error retrieving stats:[/red] {str(e).replace('[', '\\[').replace(']', '\\]')}"
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def handle_remove_from_semantic_index(file_path: str) -> None:
|
|
245
|
+
"""Handle removing a file from the semantic search index.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
file_path: Path to the file to remove
|
|
249
|
+
"""
|
|
250
|
+
try:
|
|
251
|
+
console.print(
|
|
252
|
+
f"[cyan]Removing file from semantic search index:[/cyan] {file_path}"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# Validate path
|
|
256
|
+
path_obj = Path(file_path)
|
|
257
|
+
|
|
258
|
+
# Create default configuration
|
|
259
|
+
config = SemanticConfig(
|
|
260
|
+
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
|
|
261
|
+
chunk_size=512,
|
|
262
|
+
chunk_overlap=50,
|
|
263
|
+
max_search_results=10,
|
|
264
|
+
similarity_threshold=0.7,
|
|
265
|
+
embedding_dimension=384,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Initialize vector store with persistent database
|
|
269
|
+
db_path = Path.cwd() / ".crackerjack" / "semantic_index.db"
|
|
270
|
+
db_path.parent.mkdir(exist_ok=True)
|
|
271
|
+
vector_store = VectorStore(config, db_path=db_path)
|
|
272
|
+
success = vector_store.remove_file(path_obj)
|
|
273
|
+
|
|
274
|
+
if success:
|
|
275
|
+
console.print(
|
|
276
|
+
f"[green]✅ Successfully removed {path_obj.name} from index[/green]"
|
|
277
|
+
)
|
|
278
|
+
else:
|
|
279
|
+
console.print(
|
|
280
|
+
f"[yellow]Warning:[/yellow] File {path_obj.name} was not found in index"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Show updated stats
|
|
284
|
+
stats = vector_store.get_stats()
|
|
285
|
+
console.print(
|
|
286
|
+
f"[cyan]Index now contains:[/cyan] {stats.total_files} files, {stats.total_chunks} chunks"
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
except Exception as e:
|
|
290
|
+
console.print(
|
|
291
|
+
f"[red]Error removing file:[/red] {str(e).replace('[', '\\[').replace(']', '\\]')}"
|
|
292
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_package_version() -> str:
|
|
5
|
+
try:
|
|
6
|
+
from importlib.metadata import version
|
|
7
|
+
|
|
8
|
+
return version("crackerjack")
|
|
9
|
+
except (ImportError, ModuleNotFoundError):
|
|
10
|
+
try:
|
|
11
|
+
import tomllib
|
|
12
|
+
|
|
13
|
+
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
|
|
14
|
+
with pyproject_path.open("rb") as f:
|
|
15
|
+
pyproject_data = tomllib.load(f)
|
|
16
|
+
version_value = pyproject_data["project"]["version"]
|
|
17
|
+
return str(version_value)
|
|
18
|
+
except Exception:
|
|
19
|
+
return "unknown"
|
crackerjack/code_cleaner.py
CHANGED
|
@@ -5,7 +5,6 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Protocol
|
|
6
6
|
|
|
7
7
|
from pydantic import BaseModel, ConfigDict
|
|
8
|
-
from rich.console import Console
|
|
9
8
|
|
|
10
9
|
from .errors import ErrorCode, ExecutionError
|
|
11
10
|
from .services.backup_service import BackupMetadata, PackageBackupService
|
|
@@ -23,10 +22,10 @@ from .services.security_logger import (
|
|
|
23
22
|
|
|
24
23
|
class SafePatternApplicator:
|
|
25
24
|
def apply_docstring_patterns(self, code: str) -> str:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return
|
|
25
|
+
# Intentionally a no-op for docstrings here. Actual docstring removal is
|
|
26
|
+
# handled by the structured AST cleaning step (_create_docstring_step).
|
|
27
|
+
# This keeps SafePatternApplicator focused on formatting-only changes.
|
|
28
|
+
return code
|
|
30
29
|
|
|
31
30
|
def apply_formatting_patterns(self, content: str) -> str:
|
|
32
31
|
content = SAFE_PATTERNS["spacing_after_comma"].apply(content)
|
|
@@ -35,17 +34,23 @@ class SafePatternApplicator:
|
|
|
35
34
|
return content
|
|
36
35
|
|
|
37
36
|
def has_preserved_comment(self, line: str) -> bool:
|
|
38
|
-
|
|
37
|
+
# Preserve shebangs (still useful for executable scripts)
|
|
38
|
+
if line.strip().startswith(("#! /", "#!/")):
|
|
39
39
|
return True
|
|
40
40
|
|
|
41
41
|
line_lower = line.lower()
|
|
42
42
|
preserved_keywords = [
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"type: ",
|
|
43
|
+
# Security & linting directives (critical)
|
|
44
|
+
"nosec",
|
|
46
45
|
"noqa",
|
|
47
46
|
"pragma",
|
|
47
|
+
# Type checking directives (critical)
|
|
48
|
+
"type: ",
|
|
49
|
+
# Security markers (custom)
|
|
48
50
|
"regex ok",
|
|
51
|
+
# Task tracking (useful)
|
|
52
|
+
"todo",
|
|
53
|
+
# Note: "coding:" and "encoding:" removed - obsolete since Python 3.0
|
|
49
54
|
]
|
|
50
55
|
return any(keyword in line_lower for keyword in preserved_keywords)
|
|
51
56
|
|
|
@@ -86,7 +91,7 @@ class CleaningStepProtocol(Protocol):
|
|
|
86
91
|
class FileProcessor(BaseModel):
|
|
87
92
|
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
|
|
88
93
|
|
|
89
|
-
console:
|
|
94
|
+
console: t.Any
|
|
90
95
|
logger: t.Any = None
|
|
91
96
|
base_directory: Path | None = None
|
|
92
97
|
security_logger: t.Any = None
|
|
@@ -198,7 +203,7 @@ class FileProcessor(BaseModel):
|
|
|
198
203
|
class CleaningErrorHandler(BaseModel):
|
|
199
204
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
200
205
|
|
|
201
|
-
console:
|
|
206
|
+
console: t.Any
|
|
202
207
|
logger: t.Any = None
|
|
203
208
|
|
|
204
209
|
def model_post_init(self, _: t.Any) -> None:
|
|
@@ -256,7 +261,7 @@ class CleaningPipeline(BaseModel):
|
|
|
256
261
|
|
|
257
262
|
file_processor: t.Any
|
|
258
263
|
error_handler: t.Any
|
|
259
|
-
console:
|
|
264
|
+
console: t.Any
|
|
260
265
|
logger: t.Any = None
|
|
261
266
|
|
|
262
267
|
def model_post_init(self, _: t.Any) -> None:
|
|
@@ -374,7 +379,7 @@ class CleaningPipeline(BaseModel):
|
|
|
374
379
|
class CodeCleaner(BaseModel):
|
|
375
380
|
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
|
|
376
381
|
|
|
377
|
-
console:
|
|
382
|
+
console: t.Any
|
|
378
383
|
file_processor: t.Any = None
|
|
379
384
|
error_handler: t.Any = None
|
|
380
385
|
pipeline: t.Any = None
|
|
@@ -442,7 +447,8 @@ class CodeCleaner(BaseModel):
|
|
|
442
447
|
)
|
|
443
448
|
|
|
444
449
|
if pkg_dir is None:
|
|
445
|
-
|
|
450
|
+
# Use configured base directory when no explicit path is provided
|
|
451
|
+
pkg_dir = self.base_directory or Path.cwd()
|
|
446
452
|
|
|
447
453
|
python_files = self._discover_package_files(pkg_dir)
|
|
448
454
|
|
|
@@ -500,9 +506,20 @@ class CodeCleaner(BaseModel):
|
|
|
500
506
|
|
|
501
507
|
def _prepare_package_directory(self, pkg_dir: Path | None) -> Path:
|
|
502
508
|
if pkg_dir is None:
|
|
503
|
-
pkg_dir = Path.cwd()
|
|
504
|
-
|
|
505
|
-
|
|
509
|
+
pkg_dir = self.base_directory or Path.cwd()
|
|
510
|
+
# Avoid normalizing symlinks to preserve exact input path semantics
|
|
511
|
+
# while still enforcing base-directory containment.
|
|
512
|
+
if self.base_directory and not SecurePathValidator.is_within_directory(
|
|
513
|
+
pkg_dir, self.base_directory
|
|
514
|
+
):
|
|
515
|
+
raise ExecutionError(
|
|
516
|
+
message=(
|
|
517
|
+
f"Path outside allowed directory: {pkg_dir} not within "
|
|
518
|
+
f"{self.base_directory}"
|
|
519
|
+
),
|
|
520
|
+
error_code=ErrorCode.VALIDATION_ERROR,
|
|
521
|
+
)
|
|
522
|
+
return pkg_dir
|
|
506
523
|
|
|
507
524
|
def _create_backup(self, validated_pkg_dir: Path) -> BackupMetadata:
|
|
508
525
|
self.console.print(
|
|
@@ -1108,12 +1125,18 @@ class CodeCleaner(BaseModel):
|
|
|
1108
1125
|
return '"' in line or "'" in line or "#" in line
|
|
1109
1126
|
|
|
1110
1127
|
def _process_line_for_comment_removal(self, line: str) -> str:
|
|
1111
|
-
"""Process line to remove comments while preserving strings."""
|
|
1128
|
+
"""Process line to remove comments while preserving strings and special comments."""
|
|
1112
1129
|
result_chars = []
|
|
1113
1130
|
string_state = {"in_string": False, "quote_char": None}
|
|
1114
1131
|
|
|
1115
1132
|
for i, char in enumerate(line):
|
|
1116
|
-
|
|
1133
|
+
should_stop, preserve_rest = self._should_stop_for_comment(
|
|
1134
|
+
char, string_state, line, i
|
|
1135
|
+
)
|
|
1136
|
+
if should_stop:
|
|
1137
|
+
if preserve_rest:
|
|
1138
|
+
# Preserve the rest of the line (special comment like nosec, noqa, type:)
|
|
1139
|
+
result_chars.extend(line[i:])
|
|
1117
1140
|
break
|
|
1118
1141
|
|
|
1119
1142
|
self._update_string_state(char, i, line, string_state)
|
|
@@ -1121,11 +1144,24 @@ class CodeCleaner(BaseModel):
|
|
|
1121
1144
|
|
|
1122
1145
|
return "".join(result_chars).rstrip()
|
|
1123
1146
|
|
|
1124
|
-
def
|
|
1125
|
-
self, char: str, string_state: dict[str, t.Any]
|
|
1126
|
-
) -> bool:
|
|
1127
|
-
"""Check if we should
|
|
1128
|
-
|
|
1147
|
+
def _should_stop_for_comment(
|
|
1148
|
+
self, char: str, string_state: dict[str, t.Any], line: str, index: int
|
|
1149
|
+
) -> tuple[bool, bool]:
|
|
1150
|
+
"""Check if we should stop processing at comment.
|
|
1151
|
+
|
|
1152
|
+
Returns:
|
|
1153
|
+
(should_stop, preserve_rest): should_stop=True when comment found,
|
|
1154
|
+
preserve_rest=True if comment should be kept
|
|
1155
|
+
"""
|
|
1156
|
+
if string_state["in_string"] or char != "#":
|
|
1157
|
+
return (False, False)
|
|
1158
|
+
|
|
1159
|
+
# Check if the comment portion should be preserved
|
|
1160
|
+
comment_part = line[index:].strip()
|
|
1161
|
+
if _safe_applicator.has_preserved_comment(comment_part):
|
|
1162
|
+
return (True, True) # Stop processing, preserve the comment
|
|
1163
|
+
|
|
1164
|
+
return (True, False) # Stop processing, discard the comment
|
|
1129
1165
|
|
|
1130
1166
|
def _update_string_state(
|
|
1131
1167
|
self, char: str, index: int, line: str, string_state: dict[str, t.Any]
|