roadmap-cli 0.1.1__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.
- roadmap/__init__.py +27 -0
- roadmap/adapters/__init__.py +1 -0
- roadmap/adapters/base_paginated_adapter.py +117 -0
- roadmap/adapters/cli/__init__.py +249 -0
- roadmap/adapters/cli/analysis/__init__.py +5 -0
- roadmap/adapters/cli/analysis/commands.py +370 -0
- roadmap/adapters/cli/analysis/presenter.py +125 -0
- roadmap/adapters/cli/archive_operations.py +86 -0
- roadmap/adapters/cli/cli_command_helpers.py +109 -0
- roadmap/adapters/cli/cli_confirmations.py +74 -0
- roadmap/adapters/cli/cli_error_handlers.py +146 -0
- roadmap/adapters/cli/cli_validators.py +39 -0
- roadmap/adapters/cli/commands/sync_status.py +308 -0
- roadmap/adapters/cli/comment/__init__.py +5 -0
- roadmap/adapters/cli/comment/commands.py +106 -0
- roadmap/adapters/cli/config/__init__.py +5 -0
- roadmap/adapters/cli/config/commands.py +198 -0
- roadmap/adapters/cli/console_exports.py +10 -0
- roadmap/adapters/cli/core.py +26 -0
- roadmap/adapters/cli/crud/__init__.py +47 -0
- roadmap/adapters/cli/crud/base_archive.py +208 -0
- roadmap/adapters/cli/crud/base_create.py +154 -0
- roadmap/adapters/cli/crud/base_delete.py +155 -0
- roadmap/adapters/cli/crud/base_restore.py +283 -0
- roadmap/adapters/cli/crud/base_update.py +193 -0
- roadmap/adapters/cli/crud/crud_helpers.py +206 -0
- roadmap/adapters/cli/crud/crud_utils.py +152 -0
- roadmap/adapters/cli/crud/entity_builders.py +374 -0
- roadmap/adapters/cli/data/__init__.py +8 -0
- roadmap/adapters/cli/data/commands.py +149 -0
- roadmap/adapters/cli/decorators.py +208 -0
- roadmap/adapters/cli/dtos/__init__.py +155 -0
- roadmap/adapters/cli/exception_handler.py +105 -0
- roadmap/adapters/cli/git/__init__.py +8 -0
- roadmap/adapters/cli/git/commands.py +475 -0
- roadmap/adapters/cli/git/handlers/__init__.py +1 -0
- roadmap/adapters/cli/git/handlers/git_authentication_handler.py +124 -0
- roadmap/adapters/cli/git/handlers/git_branch_handler.py +238 -0
- roadmap/adapters/cli/git/handlers/git_connectivity_handler.py +122 -0
- roadmap/adapters/cli/git/handlers/git_hooks_handler.py +105 -0
- roadmap/adapters/cli/git/hooks_config.py +327 -0
- roadmap/adapters/cli/git/status_display.py +158 -0
- roadmap/adapters/cli/health/__init__.py +8 -0
- roadmap/adapters/cli/health/db_integrity.py +204 -0
- roadmap/adapters/cli/health/enhancer.py +227 -0
- roadmap/adapters/cli/health/fixer.py +295 -0
- roadmap/adapters/cli/health/fixers/__init__.py +10 -0
- roadmap/adapters/cli/health/fixers/corrupted_comments_fixer.py +231 -0
- roadmap/adapters/cli/health/fixers/data_integrity_fixer.py +137 -0
- roadmap/adapters/cli/health/fixers/duplicate_issues_fixer.py +138 -0
- roadmap/adapters/cli/health/fixers/folder_structure_fixer.py +114 -0
- roadmap/adapters/cli/health/fixers/label_normalization_fixer.py +162 -0
- roadmap/adapters/cli/health/fixers/milestone_name_normalization_fixer.py +181 -0
- roadmap/adapters/cli/health/fixers/milestone_naming_compliance_fixer.py +244 -0
- roadmap/adapters/cli/health/fixers/milestone_parse_error_fixer.py +162 -0
- roadmap/adapters/cli/health/fixers/milestone_validation_fixer.py +211 -0
- roadmap/adapters/cli/health/fixers/old_backups_fixer.py +135 -0
- roadmap/adapters/cli/health/fixers/orphaned_issues_fixer.py +252 -0
- roadmap/adapters/cli/health/formatter.py +250 -0
- roadmap/adapters/cli/health/formatters.py +427 -0
- roadmap/adapters/cli/health/scan.py +293 -0
- roadmap/adapters/cli/init/__init__.py +5 -0
- roadmap/adapters/cli/init/commands.py +587 -0
- roadmap/adapters/cli/init.py +9 -0
- roadmap/adapters/cli/issues/__init__.py +70 -0
- roadmap/adapters/cli/issues/archive.py +137 -0
- roadmap/adapters/cli/issues/archive_class.py +253 -0
- roadmap/adapters/cli/issues/block.py +39 -0
- roadmap/adapters/cli/issues/close.py +216 -0
- roadmap/adapters/cli/issues/comment.py +178 -0
- roadmap/adapters/cli/issues/create.py +162 -0
- roadmap/adapters/cli/issues/delete.py +31 -0
- roadmap/adapters/cli/issues/deps.py +161 -0
- roadmap/adapters/cli/issues/issue_status_helpers.py +111 -0
- roadmap/adapters/cli/issues/link.py +308 -0
- roadmap/adapters/cli/issues/list.py +402 -0
- roadmap/adapters/cli/issues/lookup.py +96 -0
- roadmap/adapters/cli/issues/progress.py +102 -0
- roadmap/adapters/cli/issues/restore.py +96 -0
- roadmap/adapters/cli/issues/restore_class.py +57 -0
- roadmap/adapters/cli/issues/start.py +165 -0
- roadmap/adapters/cli/issues/sync_status.py +374 -0
- roadmap/adapters/cli/issues/unblock.py +43 -0
- roadmap/adapters/cli/issues/unlink.py +104 -0
- roadmap/adapters/cli/issues/update.py +120 -0
- roadmap/adapters/cli/issues/view.py +36 -0
- roadmap/adapters/cli/layout.py +220 -0
- roadmap/adapters/cli/mappers.py +200 -0
- roadmap/adapters/cli/milestones/__init__.py +52 -0
- roadmap/adapters/cli/milestones/archive.py +125 -0
- roadmap/adapters/cli/milestones/archive_class.py +236 -0
- roadmap/adapters/cli/milestones/assign.py +62 -0
- roadmap/adapters/cli/milestones/close.py +177 -0
- roadmap/adapters/cli/milestones/create.py +131 -0
- roadmap/adapters/cli/milestones/delete.py +27 -0
- roadmap/adapters/cli/milestones/kanban.py +123 -0
- roadmap/adapters/cli/milestones/list.py +87 -0
- roadmap/adapters/cli/milestones/recalculate.py +79 -0
- roadmap/adapters/cli/milestones/restore.py +87 -0
- roadmap/adapters/cli/milestones/restore_class.py +99 -0
- roadmap/adapters/cli/milestones/update.py +61 -0
- roadmap/adapters/cli/milestones/view.py +142 -0
- roadmap/adapters/cli/output_manager.py +319 -0
- roadmap/adapters/cli/presentation/base_presenter.py +121 -0
- roadmap/adapters/cli/presentation/cleanup_presenter.py +235 -0
- roadmap/adapters/cli/presentation/core_initialization_presenter.py +277 -0
- roadmap/adapters/cli/presentation/crud_presenter.py +134 -0
- roadmap/adapters/cli/presentation/daily_summary_presenter.py +266 -0
- roadmap/adapters/cli/presentation/issue_presenter.py +258 -0
- roadmap/adapters/cli/presentation/milestone_list_presenter.py +135 -0
- roadmap/adapters/cli/presentation/milestone_presenter.py +297 -0
- roadmap/adapters/cli/presentation/project_presenter.py +233 -0
- roadmap/adapters/cli/presentation/project_status_presenter.py +186 -0
- roadmap/adapters/cli/presentation/table_builders.py +95 -0
- roadmap/adapters/cli/projects/__init__.py +42 -0
- roadmap/adapters/cli/projects/archive.py +127 -0
- roadmap/adapters/cli/projects/archive_class.py +96 -0
- roadmap/adapters/cli/projects/close.py +94 -0
- roadmap/adapters/cli/projects/create.py +50 -0
- roadmap/adapters/cli/projects/delete.py +27 -0
- roadmap/adapters/cli/projects/list.py +227 -0
- roadmap/adapters/cli/projects/restore.py +87 -0
- roadmap/adapters/cli/projects/restore_class.py +56 -0
- roadmap/adapters/cli/projects/update.py +57 -0
- roadmap/adapters/cli/projects/view.py +157 -0
- roadmap/adapters/cli/services/__init__.py +1 -0
- roadmap/adapters/cli/services/daily_summary_service.py +313 -0
- roadmap/adapters/cli/services/export_manager.py +268 -0
- roadmap/adapters/cli/services/milestone_list_service.py +266 -0
- roadmap/adapters/cli/services/project_initialization_service.py +29 -0
- roadmap/adapters/cli/services/project_status_service.py +462 -0
- roadmap/adapters/cli/services/sync_service.py +62 -0
- roadmap/adapters/cli/status.py +408 -0
- roadmap/adapters/cli/styling.py +21 -0
- roadmap/adapters/cli/sync.py +1117 -0
- roadmap/adapters/cli/sync_context.py +432 -0
- roadmap/adapters/cli/sync_handlers/__init__.py +77 -0
- roadmap/adapters/cli/sync_handlers/apply_ops.py +522 -0
- roadmap/adapters/cli/sync_handlers/baseline_ops.py +366 -0
- roadmap/adapters/cli/sync_handlers/conflict_ops.py +161 -0
- roadmap/adapters/cli/sync_handlers/dry_run_display.py +237 -0
- roadmap/adapters/cli/sync_handlers/interactive_resolver.py +396 -0
- roadmap/adapters/cli/sync_handlers/progress_tracker.py +128 -0
- roadmap/adapters/cli/sync_metrics_command.py +190 -0
- roadmap/adapters/cli/sync_presenter.py +58 -0
- roadmap/adapters/cli/sync_validation.py +295 -0
- roadmap/adapters/cli/today.py +52 -0
- roadmap/adapters/cli/utils/click_options.py +38 -0
- roadmap/adapters/git/__init__.py +1 -0
- roadmap/adapters/git/git.py +208 -0
- roadmap/adapters/git/git_branch_manager.py +400 -0
- roadmap/adapters/git/git_command_executor.py +56 -0
- roadmap/adapters/git/git_commit_analyzer.py +334 -0
- roadmap/adapters/git/git_hooks.py +22 -0
- roadmap/adapters/git/git_hooks_manager.py +455 -0
- roadmap/adapters/git/git_repository_info.py +65 -0
- roadmap/adapters/git/hook_installer.py +106 -0
- roadmap/adapters/git/hook_registry.py +97 -0
- roadmap/adapters/git/hook_script_generator.py +58 -0
- roadmap/adapters/git/sync_monitor.py +409 -0
- roadmap/adapters/git/workflow_automation.py +286 -0
- roadmap/adapters/github/__init__.py +1 -0
- roadmap/adapters/github/github.py +360 -0
- roadmap/adapters/github/handlers/__init__.py +17 -0
- roadmap/adapters/github/handlers/base.py +337 -0
- roadmap/adapters/github/handlers/collaborators.py +165 -0
- roadmap/adapters/github/handlers/comments.py +118 -0
- roadmap/adapters/github/handlers/issues.py +150 -0
- roadmap/adapters/github/handlers/labels.py +164 -0
- roadmap/adapters/github/handlers/milestones.py +104 -0
- roadmap/adapters/persistence/__init__.py +35 -0
- roadmap/adapters/persistence/conflict_resolver.py +190 -0
- roadmap/adapters/persistence/database_manager.py +492 -0
- roadmap/adapters/persistence/entity_sync_coordinators.py +672 -0
- roadmap/adapters/persistence/file_locking.py +348 -0
- roadmap/adapters/persistence/file_parser.py +92 -0
- roadmap/adapters/persistence/file_synchronizer.py +107 -0
- roadmap/adapters/persistence/focused_managers.py +140 -0
- roadmap/adapters/persistence/git_history.py +330 -0
- roadmap/adapters/persistence/parser/__init__.py +20 -0
- roadmap/adapters/persistence/parser/frontmatter.py +152 -0
- roadmap/adapters/persistence/parser/issue.py +245 -0
- roadmap/adapters/persistence/parser/milestone.py +146 -0
- roadmap/adapters/persistence/parser/project.py +106 -0
- roadmap/adapters/persistence/persistence.py +288 -0
- roadmap/adapters/persistence/repositories/__init__.py +15 -0
- roadmap/adapters/persistence/repositories/issue_repository.py +223 -0
- roadmap/adapters/persistence/repositories/milestone_repository.py +140 -0
- roadmap/adapters/persistence/repositories/project_repository.py +168 -0
- roadmap/adapters/persistence/repositories/remote_link_repository.py +355 -0
- roadmap/adapters/persistence/repositories/sync_state_repository.py +66 -0
- roadmap/adapters/persistence/storage/__init__.py +36 -0
- roadmap/adapters/persistence/storage/conflicts.py +101 -0
- roadmap/adapters/persistence/storage/connection_manager.py +79 -0
- roadmap/adapters/persistence/storage/issue_storage.py +89 -0
- roadmap/adapters/persistence/storage/milestone_storage.py +80 -0
- roadmap/adapters/persistence/storage/project_storage.py +102 -0
- roadmap/adapters/persistence/storage/queries.py +227 -0
- roadmap/adapters/persistence/storage/state_manager.py +652 -0
- roadmap/adapters/persistence/storage/sync_state_storage.py +207 -0
- roadmap/adapters/persistence/sync_metrics_repository.py +342 -0
- roadmap/adapters/persistence/sync_orchestrator.py +293 -0
- roadmap/adapters/persistence/sync_state_tracker.py +86 -0
- roadmap/adapters/persistence/yaml_repositories.py +711 -0
- roadmap/adapters/sync/__init__.py +21 -0
- roadmap/adapters/sync/backend_factory.py +108 -0
- roadmap/adapters/sync/backends/__init__.py +15 -0
- roadmap/adapters/sync/backends/converters.py +209 -0
- roadmap/adapters/sync/backends/github_backend_helpers.py +380 -0
- roadmap/adapters/sync/backends/github_client.py +99 -0
- roadmap/adapters/sync/backends/github_sync_backend.py +792 -0
- roadmap/adapters/sync/backends/github_sync_ops.py +908 -0
- roadmap/adapters/sync/backends/services/__init__.py +1 -0
- roadmap/adapters/sync/backends/services/github_authentication_service.py +105 -0
- roadmap/adapters/sync/backends/services/github_issue_delete_service.py +423 -0
- roadmap/adapters/sync/backends/services/github_issue_dependency_service.py +63 -0
- roadmap/adapters/sync/backends/services/github_issue_fetch_service.py +158 -0
- roadmap/adapters/sync/backends/services/github_label_sync_service.py +126 -0
- roadmap/adapters/sync/backends/services/github_local_issue_sync_service.py +229 -0
- roadmap/adapters/sync/backends/services/github_milestone_fetch_service.py +204 -0
- roadmap/adapters/sync/backends/vanilla_git_sync_backend.py +198 -0
- roadmap/adapters/sync/services/__init__.py +11 -0
- roadmap/adapters/sync/services/baseline_state_handler.py +83 -0
- roadmap/adapters/sync/services/conflict_converter.py +85 -0
- roadmap/adapters/sync/services/issue_persistence_service.py +263 -0
- roadmap/adapters/sync/services/issue_state_service.py +243 -0
- roadmap/adapters/sync/services/local_change_filter.py +129 -0
- roadmap/adapters/sync/services/pull_result_processor.py +71 -0
- roadmap/adapters/sync/services/remote_issue_creation_service.py +112 -0
- roadmap/adapters/sync/services/sync_analysis_service.py +250 -0
- roadmap/adapters/sync/services/sync_authentication_service.py +57 -0
- roadmap/adapters/sync/services/sync_data_fetch_service.py +212 -0
- roadmap/adapters/sync/services/sync_linking_service.py +329 -0
- roadmap/adapters/sync/services/sync_report_service.py +62 -0
- roadmap/adapters/sync/services/sync_state_update_service.py +51 -0
- roadmap/adapters/sync/sync_cache_orchestrator.py +454 -0
- roadmap/adapters/sync/sync_merge_engine.py +416 -0
- roadmap/adapters/sync/sync_merge_orchestrator.py +1313 -0
- roadmap/adapters/sync/sync_retrieval_orchestrator.py +810 -0
- roadmap/application/services/__init__.py +1 -0
- roadmap/application/services/deduplicate_service.py +517 -0
- roadmap/application/use_cases/__init__.py +1 -0
- roadmap/common/__init__.py +308 -0
- roadmap/common/cache.py +209 -0
- roadmap/common/cli_errors.py +147 -0
- roadmap/common/configuration/__init__.py +33 -0
- roadmap/common/configuration/config_loader.py +264 -0
- roadmap/common/configuration/config_manager.py +164 -0
- roadmap/common/configuration/config_schema.py +145 -0
- roadmap/common/configuration/github/__init__.py +9 -0
- roadmap/common/configuration/github/config_manager.py +154 -0
- roadmap/common/configuration/github/token_resolver.py +84 -0
- roadmap/common/console.py +184 -0
- roadmap/common/constants.py +134 -0
- roadmap/common/datetime_parser.py +319 -0
- roadmap/common/error_formatter.py +84 -0
- roadmap/common/errors/__init__.py +143 -0
- roadmap/common/errors/error_base.py +73 -0
- roadmap/common/errors/error_file.py +82 -0
- roadmap/common/errors/error_git.py +67 -0
- roadmap/common/errors/error_handler.py +166 -0
- roadmap/common/errors/error_network.py +90 -0
- roadmap/common/errors/error_security.py +78 -0
- roadmap/common/errors/error_standards.py +561 -0
- roadmap/common/errors/error_validation.py +111 -0
- roadmap/common/errors/exceptions.py +432 -0
- roadmap/common/formatters/__init__.py +29 -0
- roadmap/common/formatters/base_table_formatter.py +96 -0
- roadmap/common/formatters/export/__init__.py +7 -0
- roadmap/common/formatters/export/issue_exporter.py +97 -0
- roadmap/common/formatters/helpers.py +28 -0
- roadmap/common/formatters/kanban/__init__.py +9 -0
- roadmap/common/formatters/kanban/layout.py +48 -0
- roadmap/common/formatters/kanban/organizer.py +81 -0
- roadmap/common/formatters/output/__init__.py +15 -0
- roadmap/common/formatters/tables/__init__.py +11 -0
- roadmap/common/formatters/tables/column_factory.py +312 -0
- roadmap/common/formatters/tables/issue_table.py +276 -0
- roadmap/common/formatters/tables/milestone_table.py +247 -0
- roadmap/common/formatters/tables/project_table.py +195 -0
- roadmap/common/formatters/text/__init__.py +57 -0
- roadmap/common/formatters/text/basic.py +217 -0
- roadmap/common/formatters/text/display.py +42 -0
- roadmap/common/formatters/text/duration.py +36 -0
- roadmap/common/formatters/text/operations.py +325 -0
- roadmap/common/formatters/text/status_badges.py +57 -0
- roadmap/common/initialization/github/__init__.py +11 -0
- roadmap/common/initialization/github/setup_service.py +238 -0
- roadmap/common/initialization/github/setup_validator.py +78 -0
- roadmap/common/logging/__init__.py +113 -0
- roadmap/common/logging/audit_logging.py +5 -0
- roadmap/common/logging/correlation.py +45 -0
- roadmap/common/logging/decorators.py +267 -0
- roadmap/common/logging/error_logging.py +217 -0
- roadmap/common/logging/formatters.py +124 -0
- roadmap/common/logging/loggers.py +68 -0
- roadmap/common/logging/performance_tracking.py +267 -0
- roadmap/common/logging/utils.py +335 -0
- roadmap/common/models/__init__.py +44 -0
- roadmap/common/models/cli_models.py +118 -0
- roadmap/common/models/config_models.py +199 -0
- roadmap/common/models/output_models.py +381 -0
- roadmap/common/observability/__init__.py +28 -0
- roadmap/common/observability/instrumentation.py +103 -0
- roadmap/common/observability/observability.py +76 -0
- roadmap/common/observability/otel_init.py +109 -0
- roadmap/common/output_formatter.py +393 -0
- roadmap/common/progress.py +379 -0
- roadmap/common/result.py +396 -0
- roadmap/common/security/__init__.py +48 -0
- roadmap/common/security/exceptions.py +13 -0
- roadmap/common/security/export_cleanup.py +79 -0
- roadmap/common/security/file_operations.py +104 -0
- roadmap/common/security/filename_sanitization.py +54 -0
- roadmap/common/security/logging.py +27 -0
- roadmap/common/security/path_validation.py +137 -0
- roadmap/common/security/temp_files.py +41 -0
- roadmap/common/services/__init__.py +65 -0
- roadmap/common/services/decorators.py +183 -0
- roadmap/common/services/logging_utils.py +208 -0
- roadmap/common/services/metrics.py +161 -0
- roadmap/common/services/performance.py +219 -0
- roadmap/common/services/profiling.py +288 -0
- roadmap/common/services/retry.py +288 -0
- roadmap/common/status_style_manager.py +114 -0
- roadmap/common/union_find.py +88 -0
- roadmap/common/update_constants.py +13 -0
- roadmap/common/utils/__init__.py +65 -0
- roadmap/common/utils/cli_helpers.py +381 -0
- roadmap/common/utils/file_utils.py +440 -0
- roadmap/common/utils/path_utils.py +38 -0
- roadmap/common/utils/status_utils.py +130 -0
- roadmap/common/utils/timezone_utils.py +480 -0
- roadmap/common/validation/__init__.py +37 -0
- roadmap/common/validation/field_validator.py +104 -0
- roadmap/common/validation/result.py +37 -0
- roadmap/common/validation/roadmap_validator.py +310 -0
- roadmap/common/validation/schema_validator.py +36 -0
- roadmap/common/validation/validators.py +50 -0
- roadmap/core/__init__.py +1 -0
- roadmap/core/domain/__init__.py +30 -0
- roadmap/core/domain/comment.py +24 -0
- roadmap/core/domain/health.py +15 -0
- roadmap/core/domain/issue.py +274 -0
- roadmap/core/domain/milestone.py +173 -0
- roadmap/core/domain/ports/__init__.py +1 -0
- roadmap/core/domain/ports/baseline_repository.py +24 -0
- roadmap/core/domain/ports/issue_repository.py +34 -0
- roadmap/core/domain/ports/remote_backend_port.py +31 -0
- roadmap/core/domain/project.py +130 -0
- roadmap/core/interfaces/__init__.py +109 -0
- roadmap/core/interfaces/assignee_validator.py +40 -0
- roadmap/core/interfaces/backend_factory.py +175 -0
- roadmap/core/interfaces/github.py +102 -0
- roadmap/core/interfaces/parsers.py +140 -0
- roadmap/core/interfaces/persistence.py +45 -0
- roadmap/core/interfaces/repositories.py +174 -0
- roadmap/core/interfaces/state_managers.py +111 -0
- roadmap/core/interfaces/state_storage.py +64 -0
- roadmap/core/interfaces/sync_backend.py +275 -0
- roadmap/core/interfaces/sync_services.py +119 -0
- roadmap/core/interfaces/sync_validators.py +180 -0
- roadmap/core/models/__init__.py +31 -0
- roadmap/core/models/sync_models.py +162 -0
- roadmap/core/models.py +115 -0
- roadmap/core/observability/__init__.py +17 -0
- roadmap/core/observability/sync_metrics.py +699 -0
- roadmap/core/repositories.py +200 -0
- roadmap/core/services/__init__.py +313 -0
- roadmap/core/services/baseline/__init__.py +1 -0
- roadmap/core/services/baseline/baseline_builder_progress.py +274 -0
- roadmap/core/services/baseline/baseline_retriever.py +63 -0
- roadmap/core/services/baseline/baseline_selector.py +248 -0
- roadmap/core/services/baseline/baseline_state_retriever.py +284 -0
- roadmap/core/services/baseline/optimized_baseline_builder.py +425 -0
- roadmap/core/services/comment/__init__.py +1 -0
- roadmap/core/services/comment/comment_service.py +277 -0
- roadmap/core/services/git/__init__.py +1 -0
- roadmap/core/services/git/git_hook_auto_sync_service.py +403 -0
- roadmap/core/services/github/__init__.py +1 -0
- roadmap/core/services/github/github_change_detector.py +162 -0
- roadmap/core/services/github/github_config_validator.py +148 -0
- roadmap/core/services/github/github_conflict_detector.py +179 -0
- roadmap/core/services/github/github_entity_classifier.py +51 -0
- roadmap/core/services/github/github_integration_service.py +439 -0
- roadmap/core/services/github/github_issue_client.py +346 -0
- roadmap/core/services/health/__init__.py +1 -0
- roadmap/core/services/health/backup_cleanup_service.py +202 -0
- roadmap/core/services/health/data_integrity_validator_service.py +90 -0
- roadmap/core/services/health/entity_health_scanner.py +460 -0
- roadmap/core/services/health/file_repair_service.py +193 -0
- roadmap/core/services/health/health_check_service.py +166 -0
- roadmap/core/services/health/health_models.py +80 -0
- roadmap/core/services/health/infrastructure_validator_service.py +328 -0
- roadmap/core/services/health/issue_health_scanner.py +263 -0
- roadmap/core/services/helpers/__init__.py +18 -0
- roadmap/core/services/helpers/status_change_helpers.py +88 -0
- roadmap/core/services/initialization/__init__.py +19 -0
- roadmap/core/services/initialization/utils.py +104 -0
- roadmap/core/services/initialization/validator.py +78 -0
- roadmap/core/services/initialization/workflow.py +182 -0
- roadmap/core/services/initialization_service.py +111 -0
- roadmap/core/services/issue/__init__.py +1 -0
- roadmap/core/services/issue/assignee_validation_service.py +312 -0
- roadmap/core/services/issue/issue_creation_service.py +309 -0
- roadmap/core/services/issue/issue_filter_service.py +302 -0
- roadmap/core/services/issue/issue_matching_service.py +127 -0
- roadmap/core/services/issue/issue_service.py +765 -0
- roadmap/core/services/issue/issue_update_service.py +144 -0
- roadmap/core/services/issue/start_issue_service.py +174 -0
- roadmap/core/services/issue_helpers/__init__.py +18 -0
- roadmap/core/services/issue_helpers/issue_filters.py +296 -0
- roadmap/core/services/milestone_service.py +438 -0
- roadmap/core/services/project/__init__.py +1 -0
- roadmap/core/services/project/project_service.py +434 -0
- roadmap/core/services/project/project_status_service.py +125 -0
- roadmap/core/services/project_init/__init__.py +22 -0
- roadmap/core/services/project_init/context_detection.py +146 -0
- roadmap/core/services/project_init/creation.py +76 -0
- roadmap/core/services/project_init/detection.py +51 -0
- roadmap/core/services/project_init/template.py +228 -0
- roadmap/core/services/status_change_service.py +88 -0
- roadmap/core/services/sync/__init__.py +1 -0
- roadmap/core/services/sync/batch_processor.py +290 -0
- roadmap/core/services/sync/conflict_resolver.py +154 -0
- roadmap/core/services/sync/dependency_resolver.py +367 -0
- roadmap/core/services/sync/duplicate_detector.py +771 -0
- roadmap/core/services/sync/duplicate_resolver.py +315 -0
- roadmap/core/services/sync/error_classification.py +470 -0
- roadmap/core/services/sync/performance.py +263 -0
- roadmap/core/services/sync/sync_change_computer.py +211 -0
- roadmap/core/services/sync/sync_checkpoint.py +348 -0
- roadmap/core/services/sync/sync_conflict_detector.py +147 -0
- roadmap/core/services/sync/sync_conflict_resolver.py +448 -0
- roadmap/core/services/sync/sync_errors.py +383 -0
- roadmap/core/services/sync/sync_key_normalizer.py +222 -0
- roadmap/core/services/sync/sync_metadata_service.py +361 -0
- roadmap/core/services/sync/sync_plan.py +171 -0
- roadmap/core/services/sync/sync_plan_executor.py +447 -0
- roadmap/core/services/sync/sync_report.py +296 -0
- roadmap/core/services/sync/sync_state.py +173 -0
- roadmap/core/services/sync/sync_state_comparator.py +690 -0
- roadmap/core/services/sync/sync_state_manager.py +431 -0
- roadmap/core/services/sync/sync_state_normalizer.py +98 -0
- roadmap/core/services/sync/sync_three_way.py +78 -0
- roadmap/core/services/sync/three_way_merger.py +178 -0
- roadmap/core/services/utils/__init__.py +1 -0
- roadmap/core/services/utils/configuration_service.py +113 -0
- roadmap/core/services/utils/critical_path_calculator.py +418 -0
- roadmap/core/services/utils/dependency_analyzer.py +360 -0
- roadmap/core/services/utils/field_conflict_detector.py +126 -0
- roadmap/core/services/utils/remote_fetcher.py +202 -0
- roadmap/core/services/utils/remote_state_normalizer.py +110 -0
- roadmap/core/services/utils/retry_policy.py +51 -0
- roadmap/core/services/validator_base.py +130 -0
- roadmap/core/services/validators/__init__.py +28 -0
- roadmap/core/services/validators/_utils.py +20 -0
- roadmap/core/services/validators/archivable_issues_validator.py +71 -0
- roadmap/core/services/validators/archivable_milestones_validator.py +69 -0
- roadmap/core/services/validators/backup_validator.py +89 -0
- roadmap/core/services/validators/data_integrity_validator.py +84 -0
- roadmap/core/services/validators/duplicate_issues_validator.py +75 -0
- roadmap/core/services/validators/duplicate_milestones_validator.py +141 -0
- roadmap/core/services/validators/folder_structure_validator.py +165 -0
- roadmap/core/services/validators/health_status_utils.py +28 -0
- roadmap/core/services/validators/milestone_naming_validator.py +146 -0
- roadmap/core/services/validators/missing_headlines_validator.py +97 -0
- roadmap/core/services/validators/orphaned_issues_validator.py +142 -0
- roadmap/core/services/validators/orphaned_milestones_validator.py +85 -0
- roadmap/core/utils/git_remote_parser.py +83 -0
- roadmap/core/utils/github_urls.py +66 -0
- roadmap/domain/validation.py +30 -0
- roadmap/infrastructure/__init__.py +55 -0
- roadmap/infrastructure/coordination/__init__.py +8 -0
- roadmap/infrastructure/coordination/coordinator_params.py +82 -0
- roadmap/infrastructure/coordination/core.py +446 -0
- roadmap/infrastructure/coordination/git_coordinator.py +160 -0
- roadmap/infrastructure/coordination/initialization.py +348 -0
- roadmap/infrastructure/coordination/issue_coordinator.py +154 -0
- roadmap/infrastructure/coordination/issue_operations.py +456 -0
- roadmap/infrastructure/coordination/milestone_coordinator.py +135 -0
- roadmap/infrastructure/coordination/milestone_operations.py +201 -0
- roadmap/infrastructure/coordination/project_coordinator.py +113 -0
- roadmap/infrastructure/coordination/project_operations.py +144 -0
- roadmap/infrastructure/coordination/team_coordinator.py +107 -0
- roadmap/infrastructure/coordination/user_operations.py +150 -0
- roadmap/infrastructure/coordination/validation_coordinator.py +249 -0
- roadmap/infrastructure/coordination_gateway.py +152 -0
- roadmap/infrastructure/git/__init__.py +6 -0
- roadmap/infrastructure/git/git_integration_ops.py +234 -0
- roadmap/infrastructure/git_gateway.py +35 -0
- roadmap/infrastructure/github_gateway.py +52 -0
- roadmap/infrastructure/maintenance/__init__.py +5 -0
- roadmap/infrastructure/maintenance/cleanup.py +483 -0
- roadmap/infrastructure/observability/__init__.py +7 -0
- roadmap/infrastructure/observability/health.py +196 -0
- roadmap/infrastructure/observability/health_formatter.py +73 -0
- roadmap/infrastructure/observability/specialized_health_checkers.py +188 -0
- roadmap/infrastructure/persistence_gateway.py +164 -0
- roadmap/infrastructure/security/__init__.py +1 -0
- roadmap/infrastructure/security/credentials.py +489 -0
- roadmap/infrastructure/sync_gateway.py +94 -0
- roadmap/infrastructure/validation/__init__.py +7 -0
- roadmap/infrastructure/validation/file_enumeration.py +219 -0
- roadmap/infrastructure/validation/github_assignee_validator.py +47 -0
- roadmap/infrastructure/validation/github_validator.py +101 -0
- roadmap/infrastructure/validation/milestone_consistency_validator.py +96 -0
- roadmap/infrastructure/validation/vanilla_assignee_validator.py +37 -0
- roadmap/infrastructure/validation_gateway.py +96 -0
- roadmap/presentation/formatters/sync_metrics_formatter.py +355 -0
- roadmap/settings.py +345 -0
- roadmap/templates/github_workflows/ci-cd-roadmap.yml +241 -0
- roadmap/templates/github_workflows/issue-lifecycle.yml +236 -0
- roadmap/templates/github_workflows/roadmap-integration.yml +137 -0
- roadmap/templates/github_workflows/roadmap-starter.yml +59 -0
- roadmap/version.py +381 -0
- roadmap_cli-0.1.1.dist-info/METADATA +448 -0
- roadmap_cli-0.1.1.dist-info/RECORD +521 -0
- roadmap_cli-0.1.1.dist-info/WHEEL +4 -0
- roadmap_cli-0.1.1.dist-info/entry_points.txt +2 -0
- roadmap_cli-0.1.1.dist-info/licenses/LICENSE.md +21 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Project table formatting and display."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
4
|
+
|
|
5
|
+
from roadmap.common.console import get_console
|
|
6
|
+
from roadmap.common.formatters.base_table_formatter import BaseTableFormatter
|
|
7
|
+
from roadmap.common.formatters.tables.column_factory import create_project_columns
|
|
8
|
+
from roadmap.common.models import TableData
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_console():
|
|
15
|
+
"""Get a fresh console instance for test compatibility."""
|
|
16
|
+
return get_console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ProjectTableFormatter(BaseTableFormatter):
|
|
20
|
+
"""Formats projects for display and structured output."""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
"""Initialize project formatter with headers and columns."""
|
|
24
|
+
super().__init__()
|
|
25
|
+
self.columns_config = [
|
|
26
|
+
{"name": "ID", "style": "cyan", "width": 10},
|
|
27
|
+
{"name": "Name", "style": "white", "width": 25},
|
|
28
|
+
{"name": "Headline", "style": "white", "width": 30},
|
|
29
|
+
{"name": "Status", "style": "magenta", "width": 12},
|
|
30
|
+
{"name": "Priority", "style": "yellow", "width": 10},
|
|
31
|
+
{"name": "Owner", "style": "green", "width": 15},
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def create_table(self) -> Any:
|
|
35
|
+
"""Create a rich table with project columns."""
|
|
36
|
+
from rich.table import Table
|
|
37
|
+
|
|
38
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
39
|
+
for col in self.columns_config:
|
|
40
|
+
table.add_column(col["name"], style=col["style"], width=col["width"])
|
|
41
|
+
return table
|
|
42
|
+
|
|
43
|
+
def add_row(self, table: Any, item) -> None:
|
|
44
|
+
"""Add a single project row to the table.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
table: Rich Table object
|
|
48
|
+
item: Project object (dict or object) to add
|
|
49
|
+
"""
|
|
50
|
+
from rich.text import Text
|
|
51
|
+
|
|
52
|
+
# Handle both dict and object formats
|
|
53
|
+
if isinstance(item, dict):
|
|
54
|
+
project_id = item.get("id", "unknown")[:8]
|
|
55
|
+
project_name = item.get("name", "Unnamed")
|
|
56
|
+
project_headline = item.get("headline", "")
|
|
57
|
+
project_status = item.get("status", "unknown")
|
|
58
|
+
project_priority = item.get("priority", "medium")
|
|
59
|
+
project_owner = item.get("owner", "Unassigned")
|
|
60
|
+
else:
|
|
61
|
+
# Handle Project object
|
|
62
|
+
project_id = getattr(item, "id", "unknown")[:8]
|
|
63
|
+
project_name = getattr(item, "name", "Unnamed")
|
|
64
|
+
project_headline = getattr(item, "headline", "")
|
|
65
|
+
raw_status = getattr(item, "status", "unknown")
|
|
66
|
+
project_status = (
|
|
67
|
+
str(cast(Any, raw_status).value)
|
|
68
|
+
if hasattr(raw_status, "value")
|
|
69
|
+
else str(raw_status)
|
|
70
|
+
)
|
|
71
|
+
raw_priority = getattr(item, "priority", "medium")
|
|
72
|
+
project_priority = (
|
|
73
|
+
str(cast(Any, raw_priority).value)
|
|
74
|
+
if hasattr(raw_priority, "value")
|
|
75
|
+
else str(raw_priority)
|
|
76
|
+
)
|
|
77
|
+
project_owner = getattr(item, "owner", "Unassigned")
|
|
78
|
+
|
|
79
|
+
table.add_row(
|
|
80
|
+
Text(project_id, style="cyan"),
|
|
81
|
+
Text(project_name, style="white"),
|
|
82
|
+
Text(project_headline or "", style="white"),
|
|
83
|
+
Text(str(project_status), style="magenta"),
|
|
84
|
+
Text(str(project_priority), style="yellow"),
|
|
85
|
+
Text(str(project_owner), style="green"),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def get_filter_description(self, items: list) -> str:
|
|
89
|
+
"""Get human-readable description of filtered projects.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
items: List of projects being displayed
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Description string (e.g., "5 active projects")
|
|
96
|
+
"""
|
|
97
|
+
count = len(items)
|
|
98
|
+
return f"🎯 {count} project{'s' if count != 1 else ''}"
|
|
99
|
+
|
|
100
|
+
def display_items(self, items: list, filter_description: str = "all") -> None:
|
|
101
|
+
"""Display projects in a formatted table.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
items: List of project objects
|
|
105
|
+
filter_description: Description of filter applied
|
|
106
|
+
"""
|
|
107
|
+
if not items:
|
|
108
|
+
_get_console().print(
|
|
109
|
+
f"🎯 No {filter_description} projects found.", style="yellow"
|
|
110
|
+
)
|
|
111
|
+
_get_console().print(
|
|
112
|
+
"Create one with: roadmap project create 'Project name'", style="dim"
|
|
113
|
+
)
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
# Display header with filter info
|
|
117
|
+
header_text = f"🎯 {len(items)} {filter_description} project{'s' if len(items) != 1 else ''}"
|
|
118
|
+
_get_console().print(header_text, style="bold cyan")
|
|
119
|
+
_get_console().print()
|
|
120
|
+
|
|
121
|
+
# Rich table display
|
|
122
|
+
table = self.create_table()
|
|
123
|
+
for item in items:
|
|
124
|
+
self.add_row(table, item)
|
|
125
|
+
|
|
126
|
+
_get_console().print(table)
|
|
127
|
+
|
|
128
|
+
def items_to_table_data(
|
|
129
|
+
self, items: list, title: str = "Projects", description: str = ""
|
|
130
|
+
) -> TableData:
|
|
131
|
+
"""Convert Project list to TableData for structured output.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
items: List of project metadata dictionaries or Project objects.
|
|
135
|
+
title: Optional table title.
|
|
136
|
+
description: Optional filter description.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
TableData object ready for rendering in any format.
|
|
140
|
+
"""
|
|
141
|
+
columns = create_project_columns()
|
|
142
|
+
|
|
143
|
+
rows = []
|
|
144
|
+
for project in items:
|
|
145
|
+
# Handle both dict and object formats
|
|
146
|
+
if isinstance(project, dict):
|
|
147
|
+
project_id = project.get("id", "unknown")[:8]
|
|
148
|
+
project_name = project.get("name", "Unnamed")
|
|
149
|
+
project_status = project.get("status", "unknown")
|
|
150
|
+
project_priority = project.get("priority", "medium")
|
|
151
|
+
project_owner = project.get("owner", "Unassigned")
|
|
152
|
+
else:
|
|
153
|
+
# Handle Project object
|
|
154
|
+
project_id = getattr(project, "id", "unknown")[:8]
|
|
155
|
+
project_name = getattr(project, "name", "Unnamed")
|
|
156
|
+
raw_status = getattr(project, "status", "unknown")
|
|
157
|
+
project_status = (
|
|
158
|
+
str(cast(Any, raw_status).value)
|
|
159
|
+
if hasattr(raw_status, "value")
|
|
160
|
+
else str(raw_status)
|
|
161
|
+
)
|
|
162
|
+
raw_priority = getattr(project, "priority", "medium")
|
|
163
|
+
project_priority = (
|
|
164
|
+
str(cast(Any, raw_priority).value)
|
|
165
|
+
if hasattr(raw_priority, "value")
|
|
166
|
+
else str(raw_priority)
|
|
167
|
+
)
|
|
168
|
+
project_owner = getattr(project, "owner", "Unassigned")
|
|
169
|
+
|
|
170
|
+
rows.append(
|
|
171
|
+
[
|
|
172
|
+
project_id,
|
|
173
|
+
project_name,
|
|
174
|
+
project_status,
|
|
175
|
+
project_priority,
|
|
176
|
+
project_owner,
|
|
177
|
+
]
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
return TableData(
|
|
181
|
+
columns=columns,
|
|
182
|
+
rows=rows,
|
|
183
|
+
title=title,
|
|
184
|
+
headline=description,
|
|
185
|
+
total_count=len(items),
|
|
186
|
+
returned_count=len(items),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Backward compatibility methods (for existing code that uses static methods)
|
|
190
|
+
@staticmethod
|
|
191
|
+
def projects_to_table_data(
|
|
192
|
+
projects: list, title: str = "Projects", description: str = ""
|
|
193
|
+
) -> TableData:
|
|
194
|
+
"""Convert Project list to TableData for structured output (backward compatible)."""
|
|
195
|
+
return ProjectTableFormatter().items_to_table_data(projects, title, description)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Text module public API."""
|
|
2
|
+
|
|
3
|
+
from .basic import (
|
|
4
|
+
_format_table_simple,
|
|
5
|
+
format_error,
|
|
6
|
+
format_header,
|
|
7
|
+
format_info,
|
|
8
|
+
format_json,
|
|
9
|
+
format_key_value_pairs,
|
|
10
|
+
format_list,
|
|
11
|
+
format_panel,
|
|
12
|
+
format_success,
|
|
13
|
+
format_table,
|
|
14
|
+
format_warning,
|
|
15
|
+
truncate_text,
|
|
16
|
+
)
|
|
17
|
+
from .display import format_display_list, format_display_pairs
|
|
18
|
+
from .duration import format_count, format_duration
|
|
19
|
+
from .operations import (
|
|
20
|
+
OperationFormatter,
|
|
21
|
+
format_entity_details,
|
|
22
|
+
format_list_items,
|
|
23
|
+
format_operation_failure,
|
|
24
|
+
format_operation_success,
|
|
25
|
+
)
|
|
26
|
+
from .status_badges import format_percentage, format_status_badge
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
# Basic formatting
|
|
30
|
+
"format_table",
|
|
31
|
+
"format_panel",
|
|
32
|
+
"format_header",
|
|
33
|
+
"format_success",
|
|
34
|
+
"format_error",
|
|
35
|
+
"format_warning",
|
|
36
|
+
"format_info",
|
|
37
|
+
"format_list",
|
|
38
|
+
"format_key_value_pairs",
|
|
39
|
+
"format_json",
|
|
40
|
+
"truncate_text",
|
|
41
|
+
"_format_table_simple",
|
|
42
|
+
# Status and badges
|
|
43
|
+
"format_status_badge",
|
|
44
|
+
"format_percentage",
|
|
45
|
+
# Duration and counts
|
|
46
|
+
"format_duration",
|
|
47
|
+
"format_count",
|
|
48
|
+
# Operations
|
|
49
|
+
"OperationFormatter",
|
|
50
|
+
"format_operation_success",
|
|
51
|
+
"format_operation_failure",
|
|
52
|
+
"format_entity_details",
|
|
53
|
+
"format_list_items",
|
|
54
|
+
# Display
|
|
55
|
+
"format_display_list",
|
|
56
|
+
"format_display_pairs",
|
|
57
|
+
]
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""Basic text formatting utilities for terminal display."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
4
|
+
|
|
5
|
+
import structlog
|
|
6
|
+
from rich.text import Text
|
|
7
|
+
|
|
8
|
+
logger = structlog.get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.panel import Panel
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def format_table(
|
|
16
|
+
title: str,
|
|
17
|
+
columns: list[str],
|
|
18
|
+
rows: list[tuple],
|
|
19
|
+
console_obj: Optional["Console"] = None,
|
|
20
|
+
) -> str:
|
|
21
|
+
"""Format data as a rich table for display.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
title: Table title
|
|
25
|
+
columns: Column headers
|
|
26
|
+
rows: List of row tuples
|
|
27
|
+
console_obj: Optional console instance
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Formatted table as string
|
|
31
|
+
"""
|
|
32
|
+
logger.debug(
|
|
33
|
+
"formatting_table", title=title, col_count=len(columns), row_count=len(rows)
|
|
34
|
+
)
|
|
35
|
+
try:
|
|
36
|
+
from rich.console import Console
|
|
37
|
+
except ImportError as e:
|
|
38
|
+
logger.debug("rich_import_failed", error=str(e))
|
|
39
|
+
# Fallback to simple formatting
|
|
40
|
+
return _format_table_simple(title, columns, rows)
|
|
41
|
+
|
|
42
|
+
if console_obj is None:
|
|
43
|
+
from rich.console import Console
|
|
44
|
+
|
|
45
|
+
console_obj = Console()
|
|
46
|
+
|
|
47
|
+
from rich.table import Table
|
|
48
|
+
|
|
49
|
+
table = Table(title=title)
|
|
50
|
+
for col in columns:
|
|
51
|
+
table.add_column(col)
|
|
52
|
+
|
|
53
|
+
for row in rows:
|
|
54
|
+
table.add_row(*[str(cell) for cell in row])
|
|
55
|
+
|
|
56
|
+
return str(table)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _format_table_simple(title: str, columns: list[str], rows: list[tuple]) -> str:
|
|
60
|
+
"""Fallback simple table formatting without rich."""
|
|
61
|
+
logger.debug(
|
|
62
|
+
"formatting_table_simple",
|
|
63
|
+
title=title,
|
|
64
|
+
col_count=len(columns),
|
|
65
|
+
row_count=len(rows),
|
|
66
|
+
)
|
|
67
|
+
output = [f"\n{title}", "-" * len(title)]
|
|
68
|
+
output.append(" | ".join(columns))
|
|
69
|
+
output.append("-" * (sum(len(c) for c in columns) + len(columns) * 3 - 1))
|
|
70
|
+
for row in rows:
|
|
71
|
+
output.append(" | ".join(str(cell) for cell in row))
|
|
72
|
+
return "\n".join(output)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def format_panel(
|
|
76
|
+
content: str,
|
|
77
|
+
title: str | None = None,
|
|
78
|
+
expand: bool = False,
|
|
79
|
+
) -> "Panel":
|
|
80
|
+
"""Format content in a rich panel.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
content: Panel content
|
|
84
|
+
title: Optional panel title
|
|
85
|
+
expand: Whether to expand to console width
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Rich Panel object
|
|
89
|
+
"""
|
|
90
|
+
logger.debug(
|
|
91
|
+
"formatting_panel", title=title, expand=expand, content_length=len(content)
|
|
92
|
+
)
|
|
93
|
+
from rich.panel import Panel
|
|
94
|
+
|
|
95
|
+
return Panel(content, title=title, expand=expand)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def format_header(text: str, level: int = 1) -> Text:
|
|
99
|
+
"""Format text as a header with styling.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
text: Header text
|
|
103
|
+
level: Header level (1-3, controls styling)
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Styled Text object
|
|
107
|
+
"""
|
|
108
|
+
logger.debug("formatting_header", text=text, level=level)
|
|
109
|
+
if level == 1:
|
|
110
|
+
return Text(text, style="bold cyan", justify="center")
|
|
111
|
+
elif level == 2:
|
|
112
|
+
return Text(text, style="bold blue")
|
|
113
|
+
else:
|
|
114
|
+
return Text(text, style="bold")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def format_success(text: str) -> Text:
|
|
118
|
+
"""Format text as a success message."""
|
|
119
|
+
logger.debug("formatting_success", text=text)
|
|
120
|
+
return Text(text, style="bold green")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def format_error(text: str) -> Text:
|
|
124
|
+
"""Format text as an error message."""
|
|
125
|
+
logger.debug("formatting_error", text=text)
|
|
126
|
+
return Text(text, style="bold red")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def format_warning(text: str) -> Text:
|
|
130
|
+
"""Format text as a warning message."""
|
|
131
|
+
logger.debug("formatting_warning", text=text)
|
|
132
|
+
return Text(text, style="bold yellow")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def format_info(text: str) -> Text:
|
|
136
|
+
"""Format text as info message."""
|
|
137
|
+
logger.debug("formatting_info", text=text)
|
|
138
|
+
return Text(text, style="bold cyan")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def format_list(items: list[str], title: str | None = None) -> str:
|
|
142
|
+
"""Format items as a bulleted list.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
items: List of items to format
|
|
146
|
+
title: Optional list title
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Formatted list as string
|
|
150
|
+
"""
|
|
151
|
+
logger.debug("formatting_list", item_count=len(items), title=title)
|
|
152
|
+
output = []
|
|
153
|
+
if title:
|
|
154
|
+
output.append(f"[bold]{title}[/bold]")
|
|
155
|
+
for item in items:
|
|
156
|
+
output.append(f" • {item}")
|
|
157
|
+
return "\n".join(output)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def format_key_value_pairs(pairs: dict[str, Any], title: str | None = None) -> str:
|
|
161
|
+
"""Format key-value pairs for display.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
pairs: Dictionary of key-value pairs
|
|
165
|
+
title: Optional title
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Formatted output as string
|
|
169
|
+
"""
|
|
170
|
+
logger.debug("formatting_key_value_pairs", pair_count=len(pairs), title=title)
|
|
171
|
+
output = []
|
|
172
|
+
if title:
|
|
173
|
+
output.append(f"[bold]{title}[/bold]")
|
|
174
|
+
|
|
175
|
+
max_key_length = max(len(k) for k in pairs.keys()) if pairs else 0
|
|
176
|
+
for key, value in pairs.items():
|
|
177
|
+
output.append(f" {key.ljust(max_key_length)}: {value}")
|
|
178
|
+
|
|
179
|
+
return "\n".join(output)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def truncate_text(text: str, max_length: int = 50, suffix: str = "...") -> str:
|
|
183
|
+
"""Truncate text to maximum length with optional suffix.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
text: Text to truncate
|
|
187
|
+
max_length: Maximum length
|
|
188
|
+
suffix: Suffix to add if truncated
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Truncated text
|
|
192
|
+
"""
|
|
193
|
+
logger.debug(
|
|
194
|
+
"truncating_text",
|
|
195
|
+
text_length=len(text),
|
|
196
|
+
max_length=max_length,
|
|
197
|
+
was_truncated=len(text) > max_length,
|
|
198
|
+
)
|
|
199
|
+
if len(text) <= max_length:
|
|
200
|
+
return text
|
|
201
|
+
return text[: max_length - len(suffix)] + suffix
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def format_json(data: Any, indent: int = 2) -> str:
|
|
205
|
+
"""Format data as JSON.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
data: Data to format
|
|
209
|
+
indent: JSON indentation level
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Formatted JSON string
|
|
213
|
+
"""
|
|
214
|
+
logger.debug("formatting_json", data_type=type(data).__name__, indent=indent)
|
|
215
|
+
import json
|
|
216
|
+
|
|
217
|
+
return json.dumps(data, indent=indent, default=str)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Display formatting utilities for lists and panels."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def format_display_list(items: list[str], title: str | None = None) -> str:
|
|
7
|
+
"""Format items as a bulleted list.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
items: List of items to format
|
|
11
|
+
title: Optional list title
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
Formatted list as string
|
|
15
|
+
"""
|
|
16
|
+
output = []
|
|
17
|
+
if title:
|
|
18
|
+
output.append(f"[bold]{title}[/bold]")
|
|
19
|
+
for item in items:
|
|
20
|
+
output.append(f" • {item}")
|
|
21
|
+
return "\n".join(output)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def format_display_pairs(pairs: dict[str, Any], title: str | None = None) -> str:
|
|
25
|
+
"""Format key-value pairs for display.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
pairs: Dictionary of key-value pairs
|
|
29
|
+
title: Optional title
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Formatted output as string
|
|
33
|
+
"""
|
|
34
|
+
output = []
|
|
35
|
+
if title:
|
|
36
|
+
output.append(f"[bold]{title}[/bold]")
|
|
37
|
+
|
|
38
|
+
max_key_length = max(len(k) for k in pairs.keys()) if pairs else 0
|
|
39
|
+
for key, value in pairs.items():
|
|
40
|
+
output.append(f" {key.ljust(max_key_length)}: {value}")
|
|
41
|
+
|
|
42
|
+
return "\n".join(output)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Duration and count formatting utilities."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def format_duration(seconds: float) -> str:
|
|
5
|
+
"""Format duration in seconds to human-readable format.
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
seconds: Duration in seconds
|
|
9
|
+
|
|
10
|
+
Returns:
|
|
11
|
+
Formatted duration string
|
|
12
|
+
"""
|
|
13
|
+
if seconds < 60:
|
|
14
|
+
return f"{int(seconds)}s"
|
|
15
|
+
elif seconds < 3600:
|
|
16
|
+
minutes = seconds / 60
|
|
17
|
+
return f"{minutes:.1f}m"
|
|
18
|
+
else:
|
|
19
|
+
hours = seconds / 3600
|
|
20
|
+
return f"{hours:.1f}h"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def format_count(count: int, singular: str, plural: str | None = None) -> str:
|
|
24
|
+
"""Format a count with proper singular/plural form.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
count: The count
|
|
28
|
+
singular: Singular form
|
|
29
|
+
plural: Plural form (defaults to singular + 's')
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Formatted count string
|
|
33
|
+
"""
|
|
34
|
+
if plural is None:
|
|
35
|
+
plural = f"{singular}s"
|
|
36
|
+
return f"{count} {singular if count == 1 else plural}"
|