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.
Files changed (521) hide show
  1. roadmap/__init__.py +27 -0
  2. roadmap/adapters/__init__.py +1 -0
  3. roadmap/adapters/base_paginated_adapter.py +117 -0
  4. roadmap/adapters/cli/__init__.py +249 -0
  5. roadmap/adapters/cli/analysis/__init__.py +5 -0
  6. roadmap/adapters/cli/analysis/commands.py +370 -0
  7. roadmap/adapters/cli/analysis/presenter.py +125 -0
  8. roadmap/adapters/cli/archive_operations.py +86 -0
  9. roadmap/adapters/cli/cli_command_helpers.py +109 -0
  10. roadmap/adapters/cli/cli_confirmations.py +74 -0
  11. roadmap/adapters/cli/cli_error_handlers.py +146 -0
  12. roadmap/adapters/cli/cli_validators.py +39 -0
  13. roadmap/adapters/cli/commands/sync_status.py +308 -0
  14. roadmap/adapters/cli/comment/__init__.py +5 -0
  15. roadmap/adapters/cli/comment/commands.py +106 -0
  16. roadmap/adapters/cli/config/__init__.py +5 -0
  17. roadmap/adapters/cli/config/commands.py +198 -0
  18. roadmap/adapters/cli/console_exports.py +10 -0
  19. roadmap/adapters/cli/core.py +26 -0
  20. roadmap/adapters/cli/crud/__init__.py +47 -0
  21. roadmap/adapters/cli/crud/base_archive.py +208 -0
  22. roadmap/adapters/cli/crud/base_create.py +154 -0
  23. roadmap/adapters/cli/crud/base_delete.py +155 -0
  24. roadmap/adapters/cli/crud/base_restore.py +283 -0
  25. roadmap/adapters/cli/crud/base_update.py +193 -0
  26. roadmap/adapters/cli/crud/crud_helpers.py +206 -0
  27. roadmap/adapters/cli/crud/crud_utils.py +152 -0
  28. roadmap/adapters/cli/crud/entity_builders.py +374 -0
  29. roadmap/adapters/cli/data/__init__.py +8 -0
  30. roadmap/adapters/cli/data/commands.py +149 -0
  31. roadmap/adapters/cli/decorators.py +208 -0
  32. roadmap/adapters/cli/dtos/__init__.py +155 -0
  33. roadmap/adapters/cli/exception_handler.py +105 -0
  34. roadmap/adapters/cli/git/__init__.py +8 -0
  35. roadmap/adapters/cli/git/commands.py +475 -0
  36. roadmap/adapters/cli/git/handlers/__init__.py +1 -0
  37. roadmap/adapters/cli/git/handlers/git_authentication_handler.py +124 -0
  38. roadmap/adapters/cli/git/handlers/git_branch_handler.py +238 -0
  39. roadmap/adapters/cli/git/handlers/git_connectivity_handler.py +122 -0
  40. roadmap/adapters/cli/git/handlers/git_hooks_handler.py +105 -0
  41. roadmap/adapters/cli/git/hooks_config.py +327 -0
  42. roadmap/adapters/cli/git/status_display.py +158 -0
  43. roadmap/adapters/cli/health/__init__.py +8 -0
  44. roadmap/adapters/cli/health/db_integrity.py +204 -0
  45. roadmap/adapters/cli/health/enhancer.py +227 -0
  46. roadmap/adapters/cli/health/fixer.py +295 -0
  47. roadmap/adapters/cli/health/fixers/__init__.py +10 -0
  48. roadmap/adapters/cli/health/fixers/corrupted_comments_fixer.py +231 -0
  49. roadmap/adapters/cli/health/fixers/data_integrity_fixer.py +137 -0
  50. roadmap/adapters/cli/health/fixers/duplicate_issues_fixer.py +138 -0
  51. roadmap/adapters/cli/health/fixers/folder_structure_fixer.py +114 -0
  52. roadmap/adapters/cli/health/fixers/label_normalization_fixer.py +162 -0
  53. roadmap/adapters/cli/health/fixers/milestone_name_normalization_fixer.py +181 -0
  54. roadmap/adapters/cli/health/fixers/milestone_naming_compliance_fixer.py +244 -0
  55. roadmap/adapters/cli/health/fixers/milestone_parse_error_fixer.py +162 -0
  56. roadmap/adapters/cli/health/fixers/milestone_validation_fixer.py +211 -0
  57. roadmap/adapters/cli/health/fixers/old_backups_fixer.py +135 -0
  58. roadmap/adapters/cli/health/fixers/orphaned_issues_fixer.py +252 -0
  59. roadmap/adapters/cli/health/formatter.py +250 -0
  60. roadmap/adapters/cli/health/formatters.py +427 -0
  61. roadmap/adapters/cli/health/scan.py +293 -0
  62. roadmap/adapters/cli/init/__init__.py +5 -0
  63. roadmap/adapters/cli/init/commands.py +587 -0
  64. roadmap/adapters/cli/init.py +9 -0
  65. roadmap/adapters/cli/issues/__init__.py +70 -0
  66. roadmap/adapters/cli/issues/archive.py +137 -0
  67. roadmap/adapters/cli/issues/archive_class.py +253 -0
  68. roadmap/adapters/cli/issues/block.py +39 -0
  69. roadmap/adapters/cli/issues/close.py +216 -0
  70. roadmap/adapters/cli/issues/comment.py +178 -0
  71. roadmap/adapters/cli/issues/create.py +162 -0
  72. roadmap/adapters/cli/issues/delete.py +31 -0
  73. roadmap/adapters/cli/issues/deps.py +161 -0
  74. roadmap/adapters/cli/issues/issue_status_helpers.py +111 -0
  75. roadmap/adapters/cli/issues/link.py +308 -0
  76. roadmap/adapters/cli/issues/list.py +402 -0
  77. roadmap/adapters/cli/issues/lookup.py +96 -0
  78. roadmap/adapters/cli/issues/progress.py +102 -0
  79. roadmap/adapters/cli/issues/restore.py +96 -0
  80. roadmap/adapters/cli/issues/restore_class.py +57 -0
  81. roadmap/adapters/cli/issues/start.py +165 -0
  82. roadmap/adapters/cli/issues/sync_status.py +374 -0
  83. roadmap/adapters/cli/issues/unblock.py +43 -0
  84. roadmap/adapters/cli/issues/unlink.py +104 -0
  85. roadmap/adapters/cli/issues/update.py +120 -0
  86. roadmap/adapters/cli/issues/view.py +36 -0
  87. roadmap/adapters/cli/layout.py +220 -0
  88. roadmap/adapters/cli/mappers.py +200 -0
  89. roadmap/adapters/cli/milestones/__init__.py +52 -0
  90. roadmap/adapters/cli/milestones/archive.py +125 -0
  91. roadmap/adapters/cli/milestones/archive_class.py +236 -0
  92. roadmap/adapters/cli/milestones/assign.py +62 -0
  93. roadmap/adapters/cli/milestones/close.py +177 -0
  94. roadmap/adapters/cli/milestones/create.py +131 -0
  95. roadmap/adapters/cli/milestones/delete.py +27 -0
  96. roadmap/adapters/cli/milestones/kanban.py +123 -0
  97. roadmap/adapters/cli/milestones/list.py +87 -0
  98. roadmap/adapters/cli/milestones/recalculate.py +79 -0
  99. roadmap/adapters/cli/milestones/restore.py +87 -0
  100. roadmap/adapters/cli/milestones/restore_class.py +99 -0
  101. roadmap/adapters/cli/milestones/update.py +61 -0
  102. roadmap/adapters/cli/milestones/view.py +142 -0
  103. roadmap/adapters/cli/output_manager.py +319 -0
  104. roadmap/adapters/cli/presentation/base_presenter.py +121 -0
  105. roadmap/adapters/cli/presentation/cleanup_presenter.py +235 -0
  106. roadmap/adapters/cli/presentation/core_initialization_presenter.py +277 -0
  107. roadmap/adapters/cli/presentation/crud_presenter.py +134 -0
  108. roadmap/adapters/cli/presentation/daily_summary_presenter.py +266 -0
  109. roadmap/adapters/cli/presentation/issue_presenter.py +258 -0
  110. roadmap/adapters/cli/presentation/milestone_list_presenter.py +135 -0
  111. roadmap/adapters/cli/presentation/milestone_presenter.py +297 -0
  112. roadmap/adapters/cli/presentation/project_presenter.py +233 -0
  113. roadmap/adapters/cli/presentation/project_status_presenter.py +186 -0
  114. roadmap/adapters/cli/presentation/table_builders.py +95 -0
  115. roadmap/adapters/cli/projects/__init__.py +42 -0
  116. roadmap/adapters/cli/projects/archive.py +127 -0
  117. roadmap/adapters/cli/projects/archive_class.py +96 -0
  118. roadmap/adapters/cli/projects/close.py +94 -0
  119. roadmap/adapters/cli/projects/create.py +50 -0
  120. roadmap/adapters/cli/projects/delete.py +27 -0
  121. roadmap/adapters/cli/projects/list.py +227 -0
  122. roadmap/adapters/cli/projects/restore.py +87 -0
  123. roadmap/adapters/cli/projects/restore_class.py +56 -0
  124. roadmap/adapters/cli/projects/update.py +57 -0
  125. roadmap/adapters/cli/projects/view.py +157 -0
  126. roadmap/adapters/cli/services/__init__.py +1 -0
  127. roadmap/adapters/cli/services/daily_summary_service.py +313 -0
  128. roadmap/adapters/cli/services/export_manager.py +268 -0
  129. roadmap/adapters/cli/services/milestone_list_service.py +266 -0
  130. roadmap/adapters/cli/services/project_initialization_service.py +29 -0
  131. roadmap/adapters/cli/services/project_status_service.py +462 -0
  132. roadmap/adapters/cli/services/sync_service.py +62 -0
  133. roadmap/adapters/cli/status.py +408 -0
  134. roadmap/adapters/cli/styling.py +21 -0
  135. roadmap/adapters/cli/sync.py +1117 -0
  136. roadmap/adapters/cli/sync_context.py +432 -0
  137. roadmap/adapters/cli/sync_handlers/__init__.py +77 -0
  138. roadmap/adapters/cli/sync_handlers/apply_ops.py +522 -0
  139. roadmap/adapters/cli/sync_handlers/baseline_ops.py +366 -0
  140. roadmap/adapters/cli/sync_handlers/conflict_ops.py +161 -0
  141. roadmap/adapters/cli/sync_handlers/dry_run_display.py +237 -0
  142. roadmap/adapters/cli/sync_handlers/interactive_resolver.py +396 -0
  143. roadmap/adapters/cli/sync_handlers/progress_tracker.py +128 -0
  144. roadmap/adapters/cli/sync_metrics_command.py +190 -0
  145. roadmap/adapters/cli/sync_presenter.py +58 -0
  146. roadmap/adapters/cli/sync_validation.py +295 -0
  147. roadmap/adapters/cli/today.py +52 -0
  148. roadmap/adapters/cli/utils/click_options.py +38 -0
  149. roadmap/adapters/git/__init__.py +1 -0
  150. roadmap/adapters/git/git.py +208 -0
  151. roadmap/adapters/git/git_branch_manager.py +400 -0
  152. roadmap/adapters/git/git_command_executor.py +56 -0
  153. roadmap/adapters/git/git_commit_analyzer.py +334 -0
  154. roadmap/adapters/git/git_hooks.py +22 -0
  155. roadmap/adapters/git/git_hooks_manager.py +455 -0
  156. roadmap/adapters/git/git_repository_info.py +65 -0
  157. roadmap/adapters/git/hook_installer.py +106 -0
  158. roadmap/adapters/git/hook_registry.py +97 -0
  159. roadmap/adapters/git/hook_script_generator.py +58 -0
  160. roadmap/adapters/git/sync_monitor.py +409 -0
  161. roadmap/adapters/git/workflow_automation.py +286 -0
  162. roadmap/adapters/github/__init__.py +1 -0
  163. roadmap/adapters/github/github.py +360 -0
  164. roadmap/adapters/github/handlers/__init__.py +17 -0
  165. roadmap/adapters/github/handlers/base.py +337 -0
  166. roadmap/adapters/github/handlers/collaborators.py +165 -0
  167. roadmap/adapters/github/handlers/comments.py +118 -0
  168. roadmap/adapters/github/handlers/issues.py +150 -0
  169. roadmap/adapters/github/handlers/labels.py +164 -0
  170. roadmap/adapters/github/handlers/milestones.py +104 -0
  171. roadmap/adapters/persistence/__init__.py +35 -0
  172. roadmap/adapters/persistence/conflict_resolver.py +190 -0
  173. roadmap/adapters/persistence/database_manager.py +492 -0
  174. roadmap/adapters/persistence/entity_sync_coordinators.py +672 -0
  175. roadmap/adapters/persistence/file_locking.py +348 -0
  176. roadmap/adapters/persistence/file_parser.py +92 -0
  177. roadmap/adapters/persistence/file_synchronizer.py +107 -0
  178. roadmap/adapters/persistence/focused_managers.py +140 -0
  179. roadmap/adapters/persistence/git_history.py +330 -0
  180. roadmap/adapters/persistence/parser/__init__.py +20 -0
  181. roadmap/adapters/persistence/parser/frontmatter.py +152 -0
  182. roadmap/adapters/persistence/parser/issue.py +245 -0
  183. roadmap/adapters/persistence/parser/milestone.py +146 -0
  184. roadmap/adapters/persistence/parser/project.py +106 -0
  185. roadmap/adapters/persistence/persistence.py +288 -0
  186. roadmap/adapters/persistence/repositories/__init__.py +15 -0
  187. roadmap/adapters/persistence/repositories/issue_repository.py +223 -0
  188. roadmap/adapters/persistence/repositories/milestone_repository.py +140 -0
  189. roadmap/adapters/persistence/repositories/project_repository.py +168 -0
  190. roadmap/adapters/persistence/repositories/remote_link_repository.py +355 -0
  191. roadmap/adapters/persistence/repositories/sync_state_repository.py +66 -0
  192. roadmap/adapters/persistence/storage/__init__.py +36 -0
  193. roadmap/adapters/persistence/storage/conflicts.py +101 -0
  194. roadmap/adapters/persistence/storage/connection_manager.py +79 -0
  195. roadmap/adapters/persistence/storage/issue_storage.py +89 -0
  196. roadmap/adapters/persistence/storage/milestone_storage.py +80 -0
  197. roadmap/adapters/persistence/storage/project_storage.py +102 -0
  198. roadmap/adapters/persistence/storage/queries.py +227 -0
  199. roadmap/adapters/persistence/storage/state_manager.py +652 -0
  200. roadmap/adapters/persistence/storage/sync_state_storage.py +207 -0
  201. roadmap/adapters/persistence/sync_metrics_repository.py +342 -0
  202. roadmap/adapters/persistence/sync_orchestrator.py +293 -0
  203. roadmap/adapters/persistence/sync_state_tracker.py +86 -0
  204. roadmap/adapters/persistence/yaml_repositories.py +711 -0
  205. roadmap/adapters/sync/__init__.py +21 -0
  206. roadmap/adapters/sync/backend_factory.py +108 -0
  207. roadmap/adapters/sync/backends/__init__.py +15 -0
  208. roadmap/adapters/sync/backends/converters.py +209 -0
  209. roadmap/adapters/sync/backends/github_backend_helpers.py +380 -0
  210. roadmap/adapters/sync/backends/github_client.py +99 -0
  211. roadmap/adapters/sync/backends/github_sync_backend.py +792 -0
  212. roadmap/adapters/sync/backends/github_sync_ops.py +908 -0
  213. roadmap/adapters/sync/backends/services/__init__.py +1 -0
  214. roadmap/adapters/sync/backends/services/github_authentication_service.py +105 -0
  215. roadmap/adapters/sync/backends/services/github_issue_delete_service.py +423 -0
  216. roadmap/adapters/sync/backends/services/github_issue_dependency_service.py +63 -0
  217. roadmap/adapters/sync/backends/services/github_issue_fetch_service.py +158 -0
  218. roadmap/adapters/sync/backends/services/github_label_sync_service.py +126 -0
  219. roadmap/adapters/sync/backends/services/github_local_issue_sync_service.py +229 -0
  220. roadmap/adapters/sync/backends/services/github_milestone_fetch_service.py +204 -0
  221. roadmap/adapters/sync/backends/vanilla_git_sync_backend.py +198 -0
  222. roadmap/adapters/sync/services/__init__.py +11 -0
  223. roadmap/adapters/sync/services/baseline_state_handler.py +83 -0
  224. roadmap/adapters/sync/services/conflict_converter.py +85 -0
  225. roadmap/adapters/sync/services/issue_persistence_service.py +263 -0
  226. roadmap/adapters/sync/services/issue_state_service.py +243 -0
  227. roadmap/adapters/sync/services/local_change_filter.py +129 -0
  228. roadmap/adapters/sync/services/pull_result_processor.py +71 -0
  229. roadmap/adapters/sync/services/remote_issue_creation_service.py +112 -0
  230. roadmap/adapters/sync/services/sync_analysis_service.py +250 -0
  231. roadmap/adapters/sync/services/sync_authentication_service.py +57 -0
  232. roadmap/adapters/sync/services/sync_data_fetch_service.py +212 -0
  233. roadmap/adapters/sync/services/sync_linking_service.py +329 -0
  234. roadmap/adapters/sync/services/sync_report_service.py +62 -0
  235. roadmap/adapters/sync/services/sync_state_update_service.py +51 -0
  236. roadmap/adapters/sync/sync_cache_orchestrator.py +454 -0
  237. roadmap/adapters/sync/sync_merge_engine.py +416 -0
  238. roadmap/adapters/sync/sync_merge_orchestrator.py +1313 -0
  239. roadmap/adapters/sync/sync_retrieval_orchestrator.py +810 -0
  240. roadmap/application/services/__init__.py +1 -0
  241. roadmap/application/services/deduplicate_service.py +517 -0
  242. roadmap/application/use_cases/__init__.py +1 -0
  243. roadmap/common/__init__.py +308 -0
  244. roadmap/common/cache.py +209 -0
  245. roadmap/common/cli_errors.py +147 -0
  246. roadmap/common/configuration/__init__.py +33 -0
  247. roadmap/common/configuration/config_loader.py +264 -0
  248. roadmap/common/configuration/config_manager.py +164 -0
  249. roadmap/common/configuration/config_schema.py +145 -0
  250. roadmap/common/configuration/github/__init__.py +9 -0
  251. roadmap/common/configuration/github/config_manager.py +154 -0
  252. roadmap/common/configuration/github/token_resolver.py +84 -0
  253. roadmap/common/console.py +184 -0
  254. roadmap/common/constants.py +134 -0
  255. roadmap/common/datetime_parser.py +319 -0
  256. roadmap/common/error_formatter.py +84 -0
  257. roadmap/common/errors/__init__.py +143 -0
  258. roadmap/common/errors/error_base.py +73 -0
  259. roadmap/common/errors/error_file.py +82 -0
  260. roadmap/common/errors/error_git.py +67 -0
  261. roadmap/common/errors/error_handler.py +166 -0
  262. roadmap/common/errors/error_network.py +90 -0
  263. roadmap/common/errors/error_security.py +78 -0
  264. roadmap/common/errors/error_standards.py +561 -0
  265. roadmap/common/errors/error_validation.py +111 -0
  266. roadmap/common/errors/exceptions.py +432 -0
  267. roadmap/common/formatters/__init__.py +29 -0
  268. roadmap/common/formatters/base_table_formatter.py +96 -0
  269. roadmap/common/formatters/export/__init__.py +7 -0
  270. roadmap/common/formatters/export/issue_exporter.py +97 -0
  271. roadmap/common/formatters/helpers.py +28 -0
  272. roadmap/common/formatters/kanban/__init__.py +9 -0
  273. roadmap/common/formatters/kanban/layout.py +48 -0
  274. roadmap/common/formatters/kanban/organizer.py +81 -0
  275. roadmap/common/formatters/output/__init__.py +15 -0
  276. roadmap/common/formatters/tables/__init__.py +11 -0
  277. roadmap/common/formatters/tables/column_factory.py +312 -0
  278. roadmap/common/formatters/tables/issue_table.py +276 -0
  279. roadmap/common/formatters/tables/milestone_table.py +247 -0
  280. roadmap/common/formatters/tables/project_table.py +195 -0
  281. roadmap/common/formatters/text/__init__.py +57 -0
  282. roadmap/common/formatters/text/basic.py +217 -0
  283. roadmap/common/formatters/text/display.py +42 -0
  284. roadmap/common/formatters/text/duration.py +36 -0
  285. roadmap/common/formatters/text/operations.py +325 -0
  286. roadmap/common/formatters/text/status_badges.py +57 -0
  287. roadmap/common/initialization/github/__init__.py +11 -0
  288. roadmap/common/initialization/github/setup_service.py +238 -0
  289. roadmap/common/initialization/github/setup_validator.py +78 -0
  290. roadmap/common/logging/__init__.py +113 -0
  291. roadmap/common/logging/audit_logging.py +5 -0
  292. roadmap/common/logging/correlation.py +45 -0
  293. roadmap/common/logging/decorators.py +267 -0
  294. roadmap/common/logging/error_logging.py +217 -0
  295. roadmap/common/logging/formatters.py +124 -0
  296. roadmap/common/logging/loggers.py +68 -0
  297. roadmap/common/logging/performance_tracking.py +267 -0
  298. roadmap/common/logging/utils.py +335 -0
  299. roadmap/common/models/__init__.py +44 -0
  300. roadmap/common/models/cli_models.py +118 -0
  301. roadmap/common/models/config_models.py +199 -0
  302. roadmap/common/models/output_models.py +381 -0
  303. roadmap/common/observability/__init__.py +28 -0
  304. roadmap/common/observability/instrumentation.py +103 -0
  305. roadmap/common/observability/observability.py +76 -0
  306. roadmap/common/observability/otel_init.py +109 -0
  307. roadmap/common/output_formatter.py +393 -0
  308. roadmap/common/progress.py +379 -0
  309. roadmap/common/result.py +396 -0
  310. roadmap/common/security/__init__.py +48 -0
  311. roadmap/common/security/exceptions.py +13 -0
  312. roadmap/common/security/export_cleanup.py +79 -0
  313. roadmap/common/security/file_operations.py +104 -0
  314. roadmap/common/security/filename_sanitization.py +54 -0
  315. roadmap/common/security/logging.py +27 -0
  316. roadmap/common/security/path_validation.py +137 -0
  317. roadmap/common/security/temp_files.py +41 -0
  318. roadmap/common/services/__init__.py +65 -0
  319. roadmap/common/services/decorators.py +183 -0
  320. roadmap/common/services/logging_utils.py +208 -0
  321. roadmap/common/services/metrics.py +161 -0
  322. roadmap/common/services/performance.py +219 -0
  323. roadmap/common/services/profiling.py +288 -0
  324. roadmap/common/services/retry.py +288 -0
  325. roadmap/common/status_style_manager.py +114 -0
  326. roadmap/common/union_find.py +88 -0
  327. roadmap/common/update_constants.py +13 -0
  328. roadmap/common/utils/__init__.py +65 -0
  329. roadmap/common/utils/cli_helpers.py +381 -0
  330. roadmap/common/utils/file_utils.py +440 -0
  331. roadmap/common/utils/path_utils.py +38 -0
  332. roadmap/common/utils/status_utils.py +130 -0
  333. roadmap/common/utils/timezone_utils.py +480 -0
  334. roadmap/common/validation/__init__.py +37 -0
  335. roadmap/common/validation/field_validator.py +104 -0
  336. roadmap/common/validation/result.py +37 -0
  337. roadmap/common/validation/roadmap_validator.py +310 -0
  338. roadmap/common/validation/schema_validator.py +36 -0
  339. roadmap/common/validation/validators.py +50 -0
  340. roadmap/core/__init__.py +1 -0
  341. roadmap/core/domain/__init__.py +30 -0
  342. roadmap/core/domain/comment.py +24 -0
  343. roadmap/core/domain/health.py +15 -0
  344. roadmap/core/domain/issue.py +274 -0
  345. roadmap/core/domain/milestone.py +173 -0
  346. roadmap/core/domain/ports/__init__.py +1 -0
  347. roadmap/core/domain/ports/baseline_repository.py +24 -0
  348. roadmap/core/domain/ports/issue_repository.py +34 -0
  349. roadmap/core/domain/ports/remote_backend_port.py +31 -0
  350. roadmap/core/domain/project.py +130 -0
  351. roadmap/core/interfaces/__init__.py +109 -0
  352. roadmap/core/interfaces/assignee_validator.py +40 -0
  353. roadmap/core/interfaces/backend_factory.py +175 -0
  354. roadmap/core/interfaces/github.py +102 -0
  355. roadmap/core/interfaces/parsers.py +140 -0
  356. roadmap/core/interfaces/persistence.py +45 -0
  357. roadmap/core/interfaces/repositories.py +174 -0
  358. roadmap/core/interfaces/state_managers.py +111 -0
  359. roadmap/core/interfaces/state_storage.py +64 -0
  360. roadmap/core/interfaces/sync_backend.py +275 -0
  361. roadmap/core/interfaces/sync_services.py +119 -0
  362. roadmap/core/interfaces/sync_validators.py +180 -0
  363. roadmap/core/models/__init__.py +31 -0
  364. roadmap/core/models/sync_models.py +162 -0
  365. roadmap/core/models.py +115 -0
  366. roadmap/core/observability/__init__.py +17 -0
  367. roadmap/core/observability/sync_metrics.py +699 -0
  368. roadmap/core/repositories.py +200 -0
  369. roadmap/core/services/__init__.py +313 -0
  370. roadmap/core/services/baseline/__init__.py +1 -0
  371. roadmap/core/services/baseline/baseline_builder_progress.py +274 -0
  372. roadmap/core/services/baseline/baseline_retriever.py +63 -0
  373. roadmap/core/services/baseline/baseline_selector.py +248 -0
  374. roadmap/core/services/baseline/baseline_state_retriever.py +284 -0
  375. roadmap/core/services/baseline/optimized_baseline_builder.py +425 -0
  376. roadmap/core/services/comment/__init__.py +1 -0
  377. roadmap/core/services/comment/comment_service.py +277 -0
  378. roadmap/core/services/git/__init__.py +1 -0
  379. roadmap/core/services/git/git_hook_auto_sync_service.py +403 -0
  380. roadmap/core/services/github/__init__.py +1 -0
  381. roadmap/core/services/github/github_change_detector.py +162 -0
  382. roadmap/core/services/github/github_config_validator.py +148 -0
  383. roadmap/core/services/github/github_conflict_detector.py +179 -0
  384. roadmap/core/services/github/github_entity_classifier.py +51 -0
  385. roadmap/core/services/github/github_integration_service.py +439 -0
  386. roadmap/core/services/github/github_issue_client.py +346 -0
  387. roadmap/core/services/health/__init__.py +1 -0
  388. roadmap/core/services/health/backup_cleanup_service.py +202 -0
  389. roadmap/core/services/health/data_integrity_validator_service.py +90 -0
  390. roadmap/core/services/health/entity_health_scanner.py +460 -0
  391. roadmap/core/services/health/file_repair_service.py +193 -0
  392. roadmap/core/services/health/health_check_service.py +166 -0
  393. roadmap/core/services/health/health_models.py +80 -0
  394. roadmap/core/services/health/infrastructure_validator_service.py +328 -0
  395. roadmap/core/services/health/issue_health_scanner.py +263 -0
  396. roadmap/core/services/helpers/__init__.py +18 -0
  397. roadmap/core/services/helpers/status_change_helpers.py +88 -0
  398. roadmap/core/services/initialization/__init__.py +19 -0
  399. roadmap/core/services/initialization/utils.py +104 -0
  400. roadmap/core/services/initialization/validator.py +78 -0
  401. roadmap/core/services/initialization/workflow.py +182 -0
  402. roadmap/core/services/initialization_service.py +111 -0
  403. roadmap/core/services/issue/__init__.py +1 -0
  404. roadmap/core/services/issue/assignee_validation_service.py +312 -0
  405. roadmap/core/services/issue/issue_creation_service.py +309 -0
  406. roadmap/core/services/issue/issue_filter_service.py +302 -0
  407. roadmap/core/services/issue/issue_matching_service.py +127 -0
  408. roadmap/core/services/issue/issue_service.py +765 -0
  409. roadmap/core/services/issue/issue_update_service.py +144 -0
  410. roadmap/core/services/issue/start_issue_service.py +174 -0
  411. roadmap/core/services/issue_helpers/__init__.py +18 -0
  412. roadmap/core/services/issue_helpers/issue_filters.py +296 -0
  413. roadmap/core/services/milestone_service.py +438 -0
  414. roadmap/core/services/project/__init__.py +1 -0
  415. roadmap/core/services/project/project_service.py +434 -0
  416. roadmap/core/services/project/project_status_service.py +125 -0
  417. roadmap/core/services/project_init/__init__.py +22 -0
  418. roadmap/core/services/project_init/context_detection.py +146 -0
  419. roadmap/core/services/project_init/creation.py +76 -0
  420. roadmap/core/services/project_init/detection.py +51 -0
  421. roadmap/core/services/project_init/template.py +228 -0
  422. roadmap/core/services/status_change_service.py +88 -0
  423. roadmap/core/services/sync/__init__.py +1 -0
  424. roadmap/core/services/sync/batch_processor.py +290 -0
  425. roadmap/core/services/sync/conflict_resolver.py +154 -0
  426. roadmap/core/services/sync/dependency_resolver.py +367 -0
  427. roadmap/core/services/sync/duplicate_detector.py +771 -0
  428. roadmap/core/services/sync/duplicate_resolver.py +315 -0
  429. roadmap/core/services/sync/error_classification.py +470 -0
  430. roadmap/core/services/sync/performance.py +263 -0
  431. roadmap/core/services/sync/sync_change_computer.py +211 -0
  432. roadmap/core/services/sync/sync_checkpoint.py +348 -0
  433. roadmap/core/services/sync/sync_conflict_detector.py +147 -0
  434. roadmap/core/services/sync/sync_conflict_resolver.py +448 -0
  435. roadmap/core/services/sync/sync_errors.py +383 -0
  436. roadmap/core/services/sync/sync_key_normalizer.py +222 -0
  437. roadmap/core/services/sync/sync_metadata_service.py +361 -0
  438. roadmap/core/services/sync/sync_plan.py +171 -0
  439. roadmap/core/services/sync/sync_plan_executor.py +447 -0
  440. roadmap/core/services/sync/sync_report.py +296 -0
  441. roadmap/core/services/sync/sync_state.py +173 -0
  442. roadmap/core/services/sync/sync_state_comparator.py +690 -0
  443. roadmap/core/services/sync/sync_state_manager.py +431 -0
  444. roadmap/core/services/sync/sync_state_normalizer.py +98 -0
  445. roadmap/core/services/sync/sync_three_way.py +78 -0
  446. roadmap/core/services/sync/three_way_merger.py +178 -0
  447. roadmap/core/services/utils/__init__.py +1 -0
  448. roadmap/core/services/utils/configuration_service.py +113 -0
  449. roadmap/core/services/utils/critical_path_calculator.py +418 -0
  450. roadmap/core/services/utils/dependency_analyzer.py +360 -0
  451. roadmap/core/services/utils/field_conflict_detector.py +126 -0
  452. roadmap/core/services/utils/remote_fetcher.py +202 -0
  453. roadmap/core/services/utils/remote_state_normalizer.py +110 -0
  454. roadmap/core/services/utils/retry_policy.py +51 -0
  455. roadmap/core/services/validator_base.py +130 -0
  456. roadmap/core/services/validators/__init__.py +28 -0
  457. roadmap/core/services/validators/_utils.py +20 -0
  458. roadmap/core/services/validators/archivable_issues_validator.py +71 -0
  459. roadmap/core/services/validators/archivable_milestones_validator.py +69 -0
  460. roadmap/core/services/validators/backup_validator.py +89 -0
  461. roadmap/core/services/validators/data_integrity_validator.py +84 -0
  462. roadmap/core/services/validators/duplicate_issues_validator.py +75 -0
  463. roadmap/core/services/validators/duplicate_milestones_validator.py +141 -0
  464. roadmap/core/services/validators/folder_structure_validator.py +165 -0
  465. roadmap/core/services/validators/health_status_utils.py +28 -0
  466. roadmap/core/services/validators/milestone_naming_validator.py +146 -0
  467. roadmap/core/services/validators/missing_headlines_validator.py +97 -0
  468. roadmap/core/services/validators/orphaned_issues_validator.py +142 -0
  469. roadmap/core/services/validators/orphaned_milestones_validator.py +85 -0
  470. roadmap/core/utils/git_remote_parser.py +83 -0
  471. roadmap/core/utils/github_urls.py +66 -0
  472. roadmap/domain/validation.py +30 -0
  473. roadmap/infrastructure/__init__.py +55 -0
  474. roadmap/infrastructure/coordination/__init__.py +8 -0
  475. roadmap/infrastructure/coordination/coordinator_params.py +82 -0
  476. roadmap/infrastructure/coordination/core.py +446 -0
  477. roadmap/infrastructure/coordination/git_coordinator.py +160 -0
  478. roadmap/infrastructure/coordination/initialization.py +348 -0
  479. roadmap/infrastructure/coordination/issue_coordinator.py +154 -0
  480. roadmap/infrastructure/coordination/issue_operations.py +456 -0
  481. roadmap/infrastructure/coordination/milestone_coordinator.py +135 -0
  482. roadmap/infrastructure/coordination/milestone_operations.py +201 -0
  483. roadmap/infrastructure/coordination/project_coordinator.py +113 -0
  484. roadmap/infrastructure/coordination/project_operations.py +144 -0
  485. roadmap/infrastructure/coordination/team_coordinator.py +107 -0
  486. roadmap/infrastructure/coordination/user_operations.py +150 -0
  487. roadmap/infrastructure/coordination/validation_coordinator.py +249 -0
  488. roadmap/infrastructure/coordination_gateway.py +152 -0
  489. roadmap/infrastructure/git/__init__.py +6 -0
  490. roadmap/infrastructure/git/git_integration_ops.py +234 -0
  491. roadmap/infrastructure/git_gateway.py +35 -0
  492. roadmap/infrastructure/github_gateway.py +52 -0
  493. roadmap/infrastructure/maintenance/__init__.py +5 -0
  494. roadmap/infrastructure/maintenance/cleanup.py +483 -0
  495. roadmap/infrastructure/observability/__init__.py +7 -0
  496. roadmap/infrastructure/observability/health.py +196 -0
  497. roadmap/infrastructure/observability/health_formatter.py +73 -0
  498. roadmap/infrastructure/observability/specialized_health_checkers.py +188 -0
  499. roadmap/infrastructure/persistence_gateway.py +164 -0
  500. roadmap/infrastructure/security/__init__.py +1 -0
  501. roadmap/infrastructure/security/credentials.py +489 -0
  502. roadmap/infrastructure/sync_gateway.py +94 -0
  503. roadmap/infrastructure/validation/__init__.py +7 -0
  504. roadmap/infrastructure/validation/file_enumeration.py +219 -0
  505. roadmap/infrastructure/validation/github_assignee_validator.py +47 -0
  506. roadmap/infrastructure/validation/github_validator.py +101 -0
  507. roadmap/infrastructure/validation/milestone_consistency_validator.py +96 -0
  508. roadmap/infrastructure/validation/vanilla_assignee_validator.py +37 -0
  509. roadmap/infrastructure/validation_gateway.py +96 -0
  510. roadmap/presentation/formatters/sync_metrics_formatter.py +355 -0
  511. roadmap/settings.py +345 -0
  512. roadmap/templates/github_workflows/ci-cd-roadmap.yml +241 -0
  513. roadmap/templates/github_workflows/issue-lifecycle.yml +236 -0
  514. roadmap/templates/github_workflows/roadmap-integration.yml +137 -0
  515. roadmap/templates/github_workflows/roadmap-starter.yml +59 -0
  516. roadmap/version.py +381 -0
  517. roadmap_cli-0.1.1.dist-info/METADATA +448 -0
  518. roadmap_cli-0.1.1.dist-info/RECORD +521 -0
  519. roadmap_cli-0.1.1.dist-info/WHEEL +4 -0
  520. roadmap_cli-0.1.1.dist-info/entry_points.txt +2 -0
  521. roadmap_cli-0.1.1.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,276 @@
1
+ """Issue table formatting and display."""
2
+
3
+ from collections.abc import Sequence
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from rich.text import Text
7
+
8
+ from roadmap.common.console import get_console
9
+ from roadmap.common.formatters.base_table_formatter import BaseTableFormatter
10
+ from roadmap.common.formatters.tables.column_factory import create_issue_columns
11
+ from roadmap.common.models import TableData
12
+ from roadmap.common.status_style_manager import StatusStyleManager
13
+ from roadmap.core.domain import Issue, Priority
14
+
15
+ if TYPE_CHECKING:
16
+ pass
17
+
18
+
19
+ def _get_console():
20
+ """Get a fresh console instance for test compatibility."""
21
+ return get_console()
22
+
23
+
24
+ class IssueTableFormatter(BaseTableFormatter[Issue]):
25
+ """Formats issues for display in rich tables."""
26
+
27
+ def __init__(self):
28
+ """Initialize issue formatter with headers and columns."""
29
+ self.show_github_ids = False
30
+ self.columns_config = [
31
+ {"name": "ID", "style": "cyan", "width": 8},
32
+ {"name": "Title", "style": "white", "width": 25, "no_wrap": True},
33
+ {"name": "Headline", "style": "white", "width": 30},
34
+ {"name": "Priority", "style": "yellow", "width": 10},
35
+ {"name": "Status", "style": "green", "width": 12},
36
+ {"name": "Progress", "style": "blue", "width": 10},
37
+ {"name": "Assignee", "style": "magenta", "width": 12},
38
+ {"name": "Estimate", "style": "green", "width": 10},
39
+ {"name": "Milestone", "style": "blue", "width": 15},
40
+ ]
41
+ # Add GitHub ID column if needed (will be shown if flag is set)
42
+ self.github_id_column = {"name": "GitHub #", "style": "cyan", "width": 10}
43
+
44
+ def create_table(self) -> Any:
45
+ """Create a rich table with issue columns."""
46
+ from rich.table import Table
47
+
48
+ table = Table(show_header=True, header_style="bold magenta")
49
+ for col in self.columns_config:
50
+ table.add_column(
51
+ col["name"],
52
+ style=col["style"],
53
+ width=col["width"],
54
+ no_wrap=col.get("no_wrap", False),
55
+ )
56
+ # Add GitHub ID column if showing them
57
+ if self.show_github_ids:
58
+ table.add_column(
59
+ self.github_id_column["name"],
60
+ style=self.github_id_column["style"],
61
+ width=self.github_id_column["width"],
62
+ )
63
+ return table
64
+
65
+ def add_row(self, table: Any, item: Issue) -> None:
66
+ """Add a single issue row to the table.
67
+
68
+ Args:
69
+ table: Rich Table object
70
+ item: Issue object to add
71
+ """
72
+ priority_style = {
73
+ Priority.CRITICAL: "bold red",
74
+ Priority.HIGH: "red",
75
+ Priority.MEDIUM: "yellow",
76
+ Priority.LOW: "dim",
77
+ }.get(item.priority, "white")
78
+
79
+ # Build row cells
80
+ comment_count = 0
81
+ if hasattr(item, "comments") and item.comments:
82
+ try:
83
+ comment_count = len(item.comments)
84
+ except TypeError:
85
+ # Handle Mock objects or other non-sequence types
86
+ comment_count = 0
87
+
88
+ comment_display = f"💬 {comment_count}" if comment_count > 0 else "-"
89
+
90
+ cells = [
91
+ item.id,
92
+ item.title,
93
+ Text(item.headline or "", style="white"),
94
+ Text(item.priority.value, style=priority_style),
95
+ Text(item.status.value, style=StatusStyleManager.get_style(item.status)),
96
+ Text(
97
+ item.progress_display,
98
+ style="blue" if item.progress_percentage else "dim",
99
+ ),
100
+ Text(
101
+ item.assignee or "Unassigned",
102
+ style="magenta" if item.assignee else "dim",
103
+ ),
104
+ Text(
105
+ item.estimated_time_display,
106
+ style="green" if item.estimated_hours else "dim",
107
+ ),
108
+ Text(item.milestone_name, style="dim" if item.is_backlog else "blue"),
109
+ Text(comment_display, style="cyan" if comment_count > 0 else "dim"),
110
+ ]
111
+
112
+ # Add GitHub ID if showing them
113
+ if self.show_github_ids:
114
+ github_id_text = (
115
+ f"#{item.github_issue}" if item.github_issue else Text("-", style="dim")
116
+ )
117
+ cells.append(github_id_text)
118
+
119
+ table.add_row(*cells)
120
+
121
+ def display_items(self, items: list[Issue], filter_description: str) -> None:
122
+ """Display issues in a formatted table.
123
+
124
+ Args:
125
+ items: List of Issue objects
126
+ filter_description: Description of filter applied
127
+ """
128
+ if not items:
129
+ _get_console().print(
130
+ f"📋 No {filter_description} issues found.", style="yellow"
131
+ )
132
+ _get_console().print(
133
+ "Create one with: roadmap issue create 'Issue title'", style="dim"
134
+ )
135
+ return
136
+
137
+ # Display header with filter info
138
+ header_text = f"📋 {len(items)} {filter_description} issue{'s' if len(items) != 1 else ''}"
139
+ _get_console().print(header_text, style="bold cyan")
140
+ _get_console().print()
141
+
142
+ # Rich table display
143
+ table = self.create_table()
144
+ for item in items:
145
+ self.add_row(table, item)
146
+
147
+ _get_console().print(table)
148
+
149
+ def get_filter_description(self, items: list[Issue]) -> str:
150
+ """Get human-readable description of filtered issues.
151
+
152
+ Args:
153
+ items: List of issues being displayed
154
+
155
+ Returns:
156
+ Description string (e.g., "5 open issues")
157
+ """
158
+ count = len(items)
159
+ return f"📋 {count} issue{'s' if count != 1 else ''}"
160
+
161
+ def items_to_table_data(
162
+ self, items: list[Issue], title: str = "Issues", description: str = ""
163
+ ) -> TableData:
164
+ """Convert Issue list to TableData for structured output.
165
+
166
+ Args:
167
+ items: List of Issue objects.
168
+ title: Optional table title.
169
+ description: Optional filter description.
170
+
171
+ Returns:
172
+ TableData object ready for rendering in any format.
173
+ """
174
+ columns = create_issue_columns()
175
+
176
+ rows = []
177
+ for item in items:
178
+ comment_count = 0
179
+ if hasattr(item, "comments") and item.comments:
180
+ try:
181
+ comment_count = len(item.comments)
182
+ except TypeError:
183
+ # Handle Mock objects or other non-sequence types
184
+ comment_count = 0
185
+
186
+ comment_display = f"💬 {comment_count}" if comment_count > 0 else ""
187
+
188
+ rows.append(
189
+ [
190
+ item.id,
191
+ item.title,
192
+ item.priority.value,
193
+ item.status.value,
194
+ item.progress_display,
195
+ item.assignee or "Unassigned",
196
+ item.estimated_time_display,
197
+ item.milestone_name,
198
+ comment_display,
199
+ ]
200
+ )
201
+
202
+ return TableData(
203
+ columns=columns,
204
+ rows=rows,
205
+ title=title,
206
+ headline=description,
207
+ total_count=len(items),
208
+ returned_count=len(items),
209
+ )
210
+
211
+ # Backward compatibility methods (for existing code that uses static methods)
212
+ @classmethod
213
+ def create_issue_table(cls):
214
+ """Create a rich table with issue columns (backward compatible)."""
215
+ return cls().create_table()
216
+
217
+ @classmethod
218
+ def add_issue_row(cls, table, issue: Issue) -> None:
219
+ """Add a single issue row to the table (backward compatible)."""
220
+ cls().add_row(table, issue)
221
+
222
+ @classmethod
223
+ def display_issues(cls, issues: list[Issue], filter_description: str) -> None:
224
+ """Display issues in a formatted table (backward compatible)."""
225
+ cls().display_items(issues, filter_description)
226
+
227
+ @staticmethod
228
+ def issues_to_table_data(
229
+ issues: Sequence[Issue],
230
+ title: str = "Issues",
231
+ description: str = "",
232
+ show_github_ids: bool = False,
233
+ ) -> TableData:
234
+ """Convert Issue list to TableData for structured output (backward compatible)."""
235
+ formatter = IssueTableFormatter()
236
+ formatter.show_github_ids = show_github_ids
237
+ return formatter.items_to_table_data(list(issues), title, description)
238
+
239
+ @staticmethod
240
+ def display_workload_summary(
241
+ assignee_name: str, total_hours: float, status_breakdown: dict
242
+ ) -> None:
243
+ """Display workload summary for an assignee."""
244
+ if total_hours == 0:
245
+ return
246
+
247
+ # Format total time display
248
+ if total_hours < 1:
249
+ total_display = f"{total_hours * 60:.0f}m"
250
+ elif total_hours <= 24:
251
+ total_display = f"{total_hours:.1f}h"
252
+ else:
253
+ total_display = f"{total_hours / 8:.1f}d"
254
+
255
+ _get_console().print()
256
+ _get_console().print(
257
+ f"Total estimated time for {assignee_name}: {total_display}",
258
+ style="bold blue",
259
+ )
260
+
261
+ # Show status breakdown
262
+ _get_console().print("Workload breakdown:", style="bold")
263
+ for status, data in status_breakdown.items():
264
+ if data["count"] > 0:
265
+ if data["hours"] > 0:
266
+ if data["hours"] < 1:
267
+ time_display = f"{data['hours'] * 60:.0f}m"
268
+ elif data["hours"] <= 24:
269
+ time_display = f"{data['hours']:.1f}h"
270
+ else:
271
+ time_display = f"{data['hours'] / 8:.1f}d"
272
+ _get_console().print(
273
+ f" {status}: {data['count']} issues ({time_display})"
274
+ )
275
+ else:
276
+ _get_console().print(f" {status}: {data['count']} issues")
@@ -0,0 +1,247 @@
1
+ """Milestone table formatting and display."""
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from rich.text import Text
6
+
7
+ from roadmap.common.console import get_console
8
+ from roadmap.common.formatters.base_table_formatter import BaseTableFormatter
9
+ from roadmap.common.models import ColumnDef, ColumnType, TableData
10
+
11
+ if TYPE_CHECKING:
12
+ pass
13
+
14
+
15
+ def _get_console():
16
+ """Get a fresh console instance for test compatibility."""
17
+ return get_console()
18
+
19
+
20
+ class MilestoneTableFormatter(BaseTableFormatter):
21
+ """Formats milestones for display and structured output."""
22
+
23
+ def __init__(self):
24
+ """Initialize milestone formatter with headers and columns."""
25
+ super().__init__()
26
+ self.columns_config = [
27
+ {"name": "Milestone", "style": "cyan", "width": 20},
28
+ {"name": "Headline", "style": "white", "width": 30},
29
+ {"name": "Status", "style": "green", "width": 10},
30
+ {"name": "Due Date", "style": "yellow", "width": 12},
31
+ {"name": "Progress", "style": "blue", "width": 12},
32
+ {"name": "Estimate", "style": "green", "width": 12},
33
+ ]
34
+
35
+ def create_table(self) -> Any:
36
+ """Create a rich table with milestone columns."""
37
+ from rich.table import Table
38
+
39
+ table = Table(show_header=True, header_style="bold magenta")
40
+ for col in self.columns_config:
41
+ table.add_column(col["name"], style=col["style"], width=col["width"])
42
+ return table
43
+
44
+ def add_row(self, table: Any, item, estimate: str = "") -> None:
45
+ """Add a single milestone row to the table.
46
+
47
+ Args:
48
+ table: Rich Table object
49
+ item: Milestone object to add
50
+ estimate: Estimated time string for this milestone
51
+ """
52
+ progress = ""
53
+ if hasattr(item, "calculated_progress") and item.calculated_progress:
54
+ progress = f"{item.calculated_progress:.0f}%"
55
+
56
+ due_date_str = ""
57
+ if hasattr(item, "due_date") and item.due_date:
58
+ due_date_str = item.due_date.strftime("%Y-%m-%d")
59
+
60
+ status_value = (
61
+ item.status.value if hasattr(item.status, "value") else str(item.status)
62
+ )
63
+
64
+ table.add_row(
65
+ Text(item.name, style="cyan"),
66
+ Text(item.headline or "", style="white"),
67
+ Text(status_value, style="green"),
68
+ Text(due_date_str, style="yellow"),
69
+ Text(progress, style="blue"),
70
+ Text(estimate or "", style="green"),
71
+ )
72
+
73
+ def get_filter_description(self, items: list) -> str:
74
+ """Get human-readable description of filtered milestones.
75
+
76
+ Args:
77
+ items: List of milestones being displayed
78
+
79
+ Returns:
80
+ Description string (e.g., "5 open milestones")
81
+ """
82
+ count = len(items)
83
+ return f"🏁 {count} milestone{'s' if count != 1 else ''}"
84
+
85
+ def display_items(self, items: list, filter_description: str = "all") -> None:
86
+ """Display milestones in a formatted table.
87
+
88
+ Args:
89
+ items: List of milestone objects
90
+ filter_description: Description of filter applied
91
+ """
92
+ if not items:
93
+ _get_console().print(
94
+ f"🏁 No {filter_description} milestones found.", style="yellow"
95
+ )
96
+ _get_console().print(
97
+ "Create one with: roadmap milestone create 'Milestone name'",
98
+ style="dim",
99
+ )
100
+ return
101
+
102
+ # Display header with filter info
103
+ header_text = f"🏁 {len(items)} {filter_description} milestone{'s' if len(items) != 1 else ''}"
104
+ _get_console().print(header_text, style="bold cyan")
105
+ _get_console().print()
106
+
107
+ # Rich table display
108
+ table = self.create_table()
109
+ for item in items:
110
+ self.add_row(table, item)
111
+
112
+ _get_console().print(table)
113
+
114
+ def items_to_table_data(
115
+ self,
116
+ items: list,
117
+ title: str = "Milestones",
118
+ description: str = "",
119
+ estimates: dict | None = None,
120
+ ) -> TableData:
121
+ """Convert Milestone list to TableData for structured output.
122
+
123
+ Args:
124
+ items: List of Milestone objects.
125
+ title: Optional table title.
126
+ description: Optional filter description.
127
+ estimates: Optional dict mapping milestone names to estimate strings.
128
+
129
+ Returns:
130
+ TableData object ready for rendering in any format.
131
+ """
132
+ if estimates is None:
133
+ estimates = {}
134
+
135
+ # Create base milestone columns (ID, Name, Status, Progress, Owner)
136
+ # then customize for this table's specific needs
137
+ columns = [
138
+ ColumnDef(
139
+ name="name",
140
+ display_name="Milestone",
141
+ type=ColumnType.STRING,
142
+ width=20,
143
+ display_style="cyan",
144
+ sortable=True,
145
+ filterable=True,
146
+ ),
147
+ ColumnDef(
148
+ name="description",
149
+ display_name="Description",
150
+ type=ColumnType.STRING,
151
+ width=30,
152
+ display_style="white",
153
+ sortable=True,
154
+ filterable=True,
155
+ ),
156
+ ColumnDef(
157
+ name="status",
158
+ display_name="Status",
159
+ type=ColumnType.ENUM,
160
+ width=10,
161
+ display_style="green",
162
+ enum_values=["open", "closed"],
163
+ sortable=True,
164
+ filterable=True,
165
+ ),
166
+ ColumnDef(
167
+ name="due_date",
168
+ display_name="Due Date",
169
+ type=ColumnType.DATE,
170
+ width=12,
171
+ display_style="yellow",
172
+ sortable=True,
173
+ filterable=True,
174
+ ),
175
+ ColumnDef(
176
+ name="progress",
177
+ display_name="Progress",
178
+ type=ColumnType.STRING,
179
+ width=12,
180
+ display_style="blue",
181
+ sortable=False,
182
+ filterable=False,
183
+ ),
184
+ ColumnDef(
185
+ name="estimate",
186
+ display_name="Estimate",
187
+ type=ColumnType.STRING,
188
+ width=12,
189
+ display_style="green",
190
+ sortable=False,
191
+ filterable=False,
192
+ ),
193
+ ]
194
+
195
+ rows = []
196
+ for milestone in items:
197
+ progress = ""
198
+ if (
199
+ hasattr(milestone, "calculated_progress")
200
+ and milestone.calculated_progress
201
+ ):
202
+ progress = f"{milestone.calculated_progress:.0f}%"
203
+
204
+ due_date_str = ""
205
+ if hasattr(milestone, "due_date") and milestone.due_date:
206
+ due_date_str = milestone.due_date.strftime("%Y-%m-%d")
207
+
208
+ # Handle status - could be string or enum
209
+ status_value = milestone.status
210
+ if hasattr(milestone.status, "value"):
211
+ status_value = milestone.status.value
212
+
213
+ # Get estimate for this milestone
214
+ estimate_str = estimates.get(milestone.name, "-")
215
+
216
+ rows.append(
217
+ [
218
+ milestone.name,
219
+ milestone.content or "",
220
+ status_value,
221
+ due_date_str,
222
+ progress,
223
+ estimate_str,
224
+ ]
225
+ )
226
+
227
+ return TableData(
228
+ columns=columns,
229
+ rows=rows,
230
+ title=title,
231
+ headline=description,
232
+ total_count=len(items),
233
+ returned_count=len(items),
234
+ )
235
+
236
+ # Backward compatibility methods (for existing code that uses static methods)
237
+ @staticmethod
238
+ def milestones_to_table_data(
239
+ milestones: list,
240
+ title: str = "Milestones",
241
+ description: str = "",
242
+ estimates: dict | None = None,
243
+ ) -> TableData:
244
+ """Convert Milestone list to TableData for structured output (backward compatible)."""
245
+ return MilestoneTableFormatter().items_to_table_data(
246
+ milestones, title, description, estimates
247
+ )