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,74 @@
1
+ """CLI confirmation and cancellation helpers - shared across all command modules.
2
+
3
+ This module provides reusable confirmation and entity-validation patterns for common CLI operations:
4
+ - Entity existence checks with standardized error messages
5
+ - Confirmation prompts with cancellation handling
6
+ - Archive existence validation
7
+ - Entity-not-found error messages
8
+
9
+ Consolidates duplicated confirmation and validation logic across issue, milestone, and project commands.
10
+ """
11
+
12
+ import click # type: ignore[import-not-found]
13
+
14
+ from roadmap.common.console import get_console
15
+
16
+ console = get_console()
17
+
18
+
19
+ # ===== Entity Validation =====
20
+
21
+
22
+ def check_entity_exists(core, entity_type: str, entity_id: str, entity_lookup=None):
23
+ """Check if entity exists, display error and return False if not found.
24
+
25
+ Args:
26
+ core: RoadmapCore instance
27
+ entity_type: Type of entity ('issue', 'milestone', 'project')
28
+ entity_id: ID or name of entity to validate
29
+ entity_lookup: Optional pre-fetched entity to check instead of looking up
30
+
31
+ Returns:
32
+ The entity object if found, False if not found (already displays error message)
33
+ """
34
+ if entity_lookup is not None:
35
+ entity = entity_lookup
36
+ else:
37
+ entity_collection = getattr(core, f"{entity_type}s", None)
38
+ if entity_collection is None:
39
+ console.print(
40
+ f"❌ Invalid entity type: {entity_type}",
41
+ style="bold red",
42
+ )
43
+ return False
44
+ entity = entity_collection.get(entity_id)
45
+
46
+ if not entity:
47
+ console.print(
48
+ f"❌ {entity_type.capitalize()} '{entity_id}' not found.",
49
+ style="bold red",
50
+ )
51
+ return False
52
+
53
+ return entity
54
+
55
+
56
+ # ===== Confirmation Prompts =====
57
+
58
+
59
+ def confirm_action(prompt: str, default: bool = False) -> bool:
60
+ """Show confirmation prompt and handle cancellation.
61
+
62
+ Displays user-friendly cancellation message if user declines.
63
+
64
+ Args:
65
+ prompt: Confirmation prompt text
66
+ default: Default value if user just presses Enter
67
+
68
+ Returns:
69
+ True if confirmed, False if cancelled (message already displayed)
70
+ """
71
+ if not click.confirm(prompt, default=default):
72
+ console.print("❌ Cancelled.", style="yellow")
73
+ return False
74
+ return True
@@ -0,0 +1,146 @@
1
+ """CLI error handling and display helpers - shared across all command modules.
2
+
3
+ This module provides reusable error handling patterns for common CLI operations:
4
+ - Universal error handler with classification and context capture
5
+ - Decorator for automatic error handling in CLI commands
6
+ - Generic exception handling with user-friendly messages
7
+ - Operation failure messages with context
8
+ - Standardized error display formatting
9
+ - Recoverable vs fatal error handling
10
+
11
+ Consolidates duplicated error handling and display logic across all CLI commands.
12
+ """
13
+
14
+ import uuid
15
+ from typing import Any
16
+
17
+ import click
18
+
19
+ from roadmap.common.console import get_console
20
+ from roadmap.common.logging import (
21
+ classify_error,
22
+ get_logger,
23
+ is_error_recoverable,
24
+ suggest_recovery,
25
+ )
26
+
27
+ console = get_console()
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ # ===== Error Message Formatting =====
32
+ # (Legacy formatting functions removed - use infrastructure.logging instead)
33
+
34
+
35
+ # ===== Universal Error Handler (Phase 3b) =====
36
+
37
+
38
+ def generate_correlation_id() -> str:
39
+ """Generate unique correlation ID for tracing errors through system."""
40
+ return str(uuid.uuid4())[:8]
41
+
42
+
43
+ def extract_user_context() -> dict[str, Any]:
44
+ """Extract user/session context from Click context."""
45
+ try:
46
+ ctx = click.get_current_context()
47
+ return {
48
+ "user": ctx.obj.get("user") if ctx.obj else None,
49
+ "command": ctx.invoked_subcommand,
50
+ "params": dict(ctx.params),
51
+ }
52
+ except RuntimeError as e:
53
+ logger.debug(
54
+ "click_context_not_available", error=str(e), action="extract_user_context"
55
+ )
56
+ return {"user": None, "command": None, "params": {}}
57
+
58
+
59
+ def handle_cli_error(
60
+ error: Exception,
61
+ operation: str,
62
+ entity_type: str | None = None,
63
+ entity_id: str | None = None,
64
+ context: dict[str, Any] | None = None,
65
+ fatal: bool = True,
66
+ include_traceback: bool = True, # noqa: ARG001
67
+ ) -> None:
68
+ """Universal CLI error handler with classification, logging, and display.
69
+
70
+ This is the single point of error handling for all CLI operations. It:
71
+ 1. Classifies the error (user/system/external)
72
+ 2. Generates correlation ID for tracing
73
+ 3. Captures user/command context
74
+ 4. Logs with full context to infrastructure logging
75
+ 5. Displays user-friendly message to console
76
+ 6. Suggests recovery action if applicable
77
+
78
+ Args:
79
+ error: The exception that occurred
80
+ operation: Name of operation that failed (e.g., "archive_project")
81
+ entity_type: Type of entity being operated on (e.g., "project")
82
+ entity_id: ID of entity (e.g., project name)
83
+ context: Optional additional context dict
84
+ fatal: If True, error is fatal and command should exit
85
+ include_traceback: If True, include full stack trace in logs
86
+ """
87
+ correlation_id = generate_correlation_id()
88
+ user_context = extract_user_context()
89
+
90
+ # Build comprehensive error context
91
+ error_context = {
92
+ "correlation_id": correlation_id,
93
+ "operation": operation,
94
+ "entity_type": entity_type,
95
+ "entity_id": entity_id,
96
+ "error_class": type(error).__name__,
97
+ "user": user_context.get("user"),
98
+ "command": user_context.get("command"),
99
+ "is_fatal": fatal,
100
+ }
101
+
102
+ if context:
103
+ error_context.update(context)
104
+
105
+ # Classify and log error
106
+ classification = classify_error(error)
107
+ recoverable = is_error_recoverable(error)
108
+ recovery = suggest_recovery(error)
109
+
110
+ error_context.update(
111
+ {
112
+ "classification": classification,
113
+ "recoverable": recoverable,
114
+ "suggested_action": recovery,
115
+ }
116
+ )
117
+
118
+ # Log with full traceback if requested
119
+ logger.error(
120
+ "operation_failed",
121
+ severity="operational",
122
+ exc_info=error,
123
+ **error_context,
124
+ )
125
+
126
+ # Display user-friendly message
127
+ emoji = "❌" if fatal else "⚠️"
128
+ entity_msg = f" {entity_type}" if entity_type else ""
129
+ id_msg = f" '{entity_id}'" if entity_id else ""
130
+
131
+ message = f"{emoji} {operation.replace('_', ' ').title()}{entity_msg}{id_msg} failed: {str(error)}"
132
+ console.print(message, style="bold red")
133
+
134
+ # Add recovery suggestion if applicable
135
+ if recoverable:
136
+ console.print(" 💡 Try again - this error may be temporary", style="cyan")
137
+ elif recovery != "contact_support":
138
+ action_msg = {
139
+ "validate_input": "Check your input and try again",
140
+ "check_connectivity": "Check network connection and try again",
141
+ "manual_intervention": "Manual intervention may be required",
142
+ }.get(recovery, "Contact support")
143
+ console.print(f" 💡 {action_msg}", style="cyan")
144
+
145
+ # Add correlation ID for support
146
+ console.print(f" 📊 Error ID: {correlation_id}", style="dim")
@@ -0,0 +1,39 @@
1
+ """CLI validation helpers - shared across all command modules.
2
+
3
+ This module provides reusable validation functions for common CLI patterns:
4
+ - Priority enum validation
5
+
6
+ Consolidates duplicated validation logic across commands.
7
+ """
8
+
9
+ from roadmap.common.console import get_console
10
+
11
+ console = get_console()
12
+
13
+
14
+ # ===== Priority/Status Validation =====
15
+
16
+
17
+ def validate_priority(priority_str: str, domain_module=None):
18
+ """Validate and convert priority string to Priority enum.
19
+
20
+ Args:
21
+ priority_str: Priority string (critical, high, medium, low)
22
+ domain_module: Optional domain module for custom Priority class
23
+
24
+ Returns:
25
+ Priority enum if valid, None if invalid
26
+ """
27
+ if domain_module is None:
28
+ from roadmap.core.domain import Priority
29
+ else:
30
+ Priority = domain_module.Priority
31
+
32
+ try:
33
+ return Priority(priority_str.upper())
34
+ except ValueError:
35
+ console.print(
36
+ f"❌ Invalid priority: {priority_str}. Use: critical, high, medium, low",
37
+ style="bold red",
38
+ )
39
+ return None
@@ -0,0 +1,308 @@
1
+ """Sync status dashboard - comprehensive sync health reporting."""
2
+
3
+ import click
4
+ from rich.panel import Panel
5
+ from rich.table import Table
6
+ from rich.text import Text
7
+
8
+ from roadmap.common.console import get_console
9
+ from roadmap.core.services.sync.sync_metadata_service import SyncMetadataService
10
+
11
+
12
+ def _build_health_overview_panel(stats: dict, console) -> Panel:
13
+ """Build health overview panel with key metrics."""
14
+ health_table = Table(show_header=False, box=None, padding=(0, 2))
15
+ health_table.add_column(style="bold")
16
+ health_table.add_column(justify="right")
17
+
18
+ # Calculate health score
19
+ total_attempts = stats.get("total_sync_attempts", 0)
20
+ successful = stats.get("successful_syncs", 0)
21
+ conflicts = stats.get("total_conflicts_resolved", 0)
22
+
23
+ if total_attempts > 0:
24
+ success_rate = (successful / total_attempts) * 100
25
+ health_emoji = (
26
+ "🟢" if success_rate >= 90 else "🟡" if success_rate >= 70 else "🔴"
27
+ )
28
+ health_text = (
29
+ "Healthy"
30
+ if success_rate >= 90
31
+ else "Degraded"
32
+ if success_rate >= 70
33
+ else "Unhealthy"
34
+ )
35
+ else:
36
+ success_rate = 0
37
+ health_emoji = "⚪"
38
+ health_text = "No Data"
39
+
40
+ health_table.add_row(
41
+ f"{health_emoji} Overall Health",
42
+ Text(
43
+ health_text,
44
+ style="bold green"
45
+ if success_rate >= 90
46
+ else "bold yellow"
47
+ if success_rate >= 70
48
+ else "bold red",
49
+ ),
50
+ )
51
+ health_table.add_row("Success Rate", f"{success_rate:.1f}%")
52
+ health_table.add_row("Total Syncs", str(total_attempts))
53
+ health_table.add_row("Successful", f"[green]{successful}[/green]")
54
+ health_table.add_row("Conflicts", f"[yellow]{conflicts}[/yellow]")
55
+ health_table.add_row("Never Synced", f"[dim]{stats.get('never_synced', 0)}[/dim]")
56
+
57
+ return Panel(
58
+ health_table,
59
+ title="[bold cyan]📊 Sync Health Overview[/bold cyan]",
60
+ border_style="cyan",
61
+ )
62
+
63
+
64
+ def _build_recent_activity_panel(core, metadata_service, console) -> Panel:
65
+ """Build recent activity panel showing last 5 syncs."""
66
+ all_issues = core.issues.all()
67
+ github_issues = [i for i in all_issues if getattr(i, "github_issue", None)]
68
+
69
+ # Collect all recent sync records
70
+ recent_syncs = []
71
+ for issue in github_issues:
72
+ metadata = metadata_service.get_metadata(issue)
73
+ for record in metadata.sync_history[-5:]: # Last 5 per issue
74
+ recent_syncs.append((issue, record))
75
+
76
+ # Sort by timestamp, most recent first
77
+ recent_syncs.sort(key=lambda x: x[1].sync_timestamp, reverse=True)
78
+ recent_syncs = recent_syncs[:10] # Top 10 overall
79
+
80
+ if not recent_syncs:
81
+ return Panel(
82
+ Text("No recent sync activity", style="dim"),
83
+ title="[bold cyan]🕐 Recent Activity[/bold cyan]",
84
+ border_style="cyan",
85
+ )
86
+
87
+ activity_table = Table(show_header=True, header_style="bold", box=None)
88
+ activity_table.add_column("Time", style="dim", width=12)
89
+ activity_table.add_column("Issue", width=12)
90
+ activity_table.add_column("Status", width=10)
91
+ activity_table.add_column("Details", width=30)
92
+
93
+ for issue, record in recent_syncs:
94
+ time_str = record.sync_timestamp[11:19] # HH:MM:SS
95
+ issue_id = issue.id[:10]
96
+
97
+ if record.success:
98
+ status = "[green]✓ Success[/green]"
99
+ elif record.conflict_resolution:
100
+ status = "[yellow]⚠ Conflict[/yellow]"
101
+ else:
102
+ status = "[red]✗ Error[/red]"
103
+
104
+ details = ""
105
+ if record.conflict_resolution:
106
+ details = f"Resolved: {record.conflict_resolution}"
107
+ elif record.error_message:
108
+ details = record.error_message[:27] + "..."
109
+ elif record.local_changes:
110
+ details = f"{len(record.local_changes)} changes"
111
+
112
+ activity_table.add_row(time_str, issue_id, status, details)
113
+
114
+ return Panel(
115
+ activity_table,
116
+ title="[bold cyan]🕐 Recent Sync Activity (Last 10)[/bold cyan]",
117
+ border_style="cyan",
118
+ )
119
+
120
+
121
+ def _build_error_trends_panel(core, metadata_service, console) -> Panel:
122
+ """Build error trends panel showing common issues."""
123
+ all_issues = core.issues.all()
124
+ github_issues = [i for i in all_issues if getattr(i, "github_issue", None)]
125
+
126
+ # Collect error stats
127
+ error_types = {}
128
+ conflict_types = {}
129
+
130
+ for issue in github_issues:
131
+ metadata = metadata_service.get_metadata(issue)
132
+ for record in metadata.sync_history:
133
+ if record.error_message:
134
+ # Simple categorization
135
+ error_key = _categorize_error(record.error_message)
136
+ error_types[error_key] = error_types.get(error_key, 0) + 1
137
+
138
+ if record.conflict_resolution:
139
+ conflict_types[record.conflict_resolution] = (
140
+ conflict_types.get(record.conflict_resolution, 0) + 1
141
+ )
142
+
143
+ if not error_types and not conflict_types:
144
+ return Panel(
145
+ Text("No errors or conflicts detected 🎉", style="green"),
146
+ title="[bold cyan]📈 Error Trends[/bold cyan]",
147
+ border_style="cyan",
148
+ )
149
+
150
+ trends_table = Table(show_header=True, header_style="bold", box=None)
151
+ trends_table.add_column("Type", style="yellow")
152
+ trends_table.add_column("Category", width=20)
153
+ trends_table.add_column("Count", justify="right", width=8)
154
+
155
+ for error, count in sorted(error_types.items(), key=lambda x: x[1], reverse=True)[
156
+ :5
157
+ ]:
158
+ trends_table.add_row("Error", error, str(count))
159
+
160
+ for resolution, count in sorted(
161
+ conflict_types.items(), key=lambda x: x[1], reverse=True
162
+ )[:3]:
163
+ trends_table.add_row("Conflict", resolution, str(count))
164
+
165
+ return Panel(
166
+ trends_table,
167
+ title="[bold cyan]📈 Error & Conflict Trends[/bold cyan]",
168
+ border_style="cyan",
169
+ )
170
+
171
+
172
+ def _categorize_error(error_message: str) -> str:
173
+ """Categorize error message into a type."""
174
+ error_lower = error_message.lower()
175
+
176
+ if "rate limit" in error_lower or "429" in error_lower:
177
+ return "Rate Limit"
178
+ elif "auth" in error_lower or "401" in error_lower or "403" in error_lower:
179
+ return "Authentication"
180
+ elif (
181
+ "network" in error_lower
182
+ or "connection" in error_lower
183
+ or "timeout" in error_lower
184
+ ):
185
+ return "Network"
186
+ elif "not found" in error_lower or "404" in error_lower:
187
+ return "Not Found"
188
+ elif "validation" in error_lower or "invalid" in error_lower:
189
+ return "Validation"
190
+ else:
191
+ return "Other"
192
+
193
+
194
+ def _build_issue_health_panel(core, metadata_service, console) -> Panel:
195
+ """Build issue health breakdown panel."""
196
+ all_issues = core.issues.all()
197
+ github_issues = [i for i in all_issues if getattr(i, "github_issue", None)]
198
+
199
+ # Categorize issues by sync health
200
+ healthy = []
201
+ at_risk = []
202
+ failing = []
203
+ never_synced = []
204
+
205
+ for issue in github_issues:
206
+ metadata = metadata_service.get_metadata(issue)
207
+
208
+ if metadata.sync_count == 0:
209
+ never_synced.append(issue)
210
+ else:
211
+ success_rate = metadata.get_success_rate()
212
+ if success_rate >= 90:
213
+ healthy.append(issue)
214
+ elif success_rate >= 70:
215
+ at_risk.append(issue)
216
+ else:
217
+ failing.append(issue)
218
+
219
+ health_breakdown = Table(show_header=True, header_style="bold", box=None)
220
+ health_breakdown.add_column("Category", style="bold")
221
+ health_breakdown.add_column("Count", justify="right", width=8)
222
+ health_breakdown.add_column("Percentage", width=12)
223
+
224
+ total = len(github_issues)
225
+ if total > 0:
226
+ health_breakdown.add_row(
227
+ "[green]✓ Healthy (90%+)[/green]",
228
+ str(len(healthy)),
229
+ f"{(len(healthy) / total) * 100:.1f}%",
230
+ )
231
+ health_breakdown.add_row(
232
+ "[yellow]⚠ At Risk (70-89%)[/yellow]",
233
+ str(len(at_risk)),
234
+ f"{(len(at_risk) / total) * 100:.1f}%",
235
+ )
236
+ health_breakdown.add_row(
237
+ "[red]✗ Failing (<70%)[/red]",
238
+ str(len(failing)),
239
+ f"{(len(failing) / total) * 100:.1f}%",
240
+ )
241
+ health_breakdown.add_row(
242
+ "[dim]○ Never Synced[/dim]",
243
+ str(len(never_synced)),
244
+ f"{(len(never_synced) / total) * 100:.1f}%",
245
+ )
246
+
247
+ return Panel(
248
+ health_breakdown,
249
+ title="[bold cyan]💊 Issue Health Breakdown[/bold cyan]",
250
+ border_style="cyan",
251
+ )
252
+
253
+
254
+ @click.command(name="status")
255
+ @click.pass_context
256
+ def sync_status_dashboard(ctx: click.Context) -> None:
257
+ """Display comprehensive sync health dashboard.
258
+
259
+ Shows an overview of sync operations, health metrics, recent activity,
260
+ error trends, and issue-level health breakdown.
261
+
262
+ Examples:
263
+ # Show sync health dashboard
264
+ roadmap sync status
265
+ """
266
+ core = ctx.obj["core"]
267
+ console = get_console()
268
+
269
+ # Initialize metadata service
270
+ metadata_service = SyncMetadataService(core)
271
+
272
+ # Get all GitHub-linked issues
273
+ all_issues = core.issues.all()
274
+ github_issues = [i for i in all_issues if getattr(i, "github_issue", None)]
275
+
276
+ if not github_issues:
277
+ console.print("[yellow]⚠️ No GitHub-linked issues found[/yellow]")
278
+ console.print(
279
+ "\n[dim]Hint: Link issues with: roadmap issue link <issue-id> <github-issue-number>[/dim]"
280
+ )
281
+ return
282
+
283
+ # Get aggregate statistics
284
+ stats = metadata_service.get_statistics(github_issues)
285
+
286
+ # Build dashboard layout
287
+ console.print("\n[bold cyan]════ Sync Health Dashboard ════[/bold cyan]")
288
+ console.print(f"[dim]Tracking {len(github_issues)} GitHub-linked issues[/dim]\n")
289
+
290
+ # Show health overview
291
+ console.print(_build_health_overview_panel(stats, console))
292
+ console.print()
293
+
294
+ # Show issue health breakdown
295
+ console.print(_build_issue_health_panel(core, metadata_service, console))
296
+ console.print()
297
+
298
+ # Show recent activity
299
+ console.print(_build_recent_activity_panel(core, metadata_service, console))
300
+ console.print()
301
+
302
+ # Show error trends
303
+ console.print(_build_error_trends_panel(core, metadata_service, console))
304
+ console.print()
305
+
306
+ console.print(
307
+ "[dim]💡 Tip: Use 'roadmap issue sync-status <id>' for detailed issue-level sync history[/dim]"
308
+ )
@@ -0,0 +1,5 @@
1
+ """Comment management commands."""
2
+
3
+ from .commands import comment
4
+
5
+ __all__ = ["comment"]
@@ -0,0 +1,106 @@
1
+ """Comment management CLI commands."""
2
+
3
+ import click
4
+
5
+ from roadmap.adapters.cli.cli_command_helpers import require_initialized
6
+ from roadmap.adapters.cli.cli_error_handlers import handle_cli_error
7
+ from roadmap.common.console import get_console
8
+
9
+ console = get_console()
10
+
11
+
12
+ @click.group()
13
+ def comment():
14
+ """Manage comments on issues and milestones."""
15
+ pass
16
+
17
+
18
+ @comment.command("create")
19
+ @click.argument("target_id")
20
+ @click.argument("message")
21
+ @click.option("--type", default="issue", help="Type of target (issue, milestone)")
22
+ @click.pass_context
23
+ @require_initialized
24
+ def create_comment(ctx: click.Context, target_id: str, message: str, type: str):
25
+ """Create a comment on an issue or milestone."""
26
+ try:
27
+ console.print(f"💬 Created comment on {type} {target_id}", style="bold green")
28
+ console.print(f" Message: {message}", style="dim")
29
+ except Exception as e:
30
+ handle_cli_error(
31
+ error=e,
32
+ operation="create_comment",
33
+ entity_type=type,
34
+ entity_id=target_id,
35
+ context={"message_length": len(message)},
36
+ fatal=True,
37
+ )
38
+ console.print(f"❌ Failed to create comment: {e}", style="bold red")
39
+ raise click.Abort() from e
40
+
41
+
42
+ @comment.command("list")
43
+ @click.argument("target_id")
44
+ @click.option("--type", default="issue", help="Type of target (issue, milestone)")
45
+ @click.pass_context
46
+ @require_initialized
47
+ def list_comments(ctx: click.Context, target_id: str, type: str):
48
+ """List comments for an issue or milestone."""
49
+ try:
50
+ console.print(f"💬 Comments for {type} {target_id}", style="bold blue")
51
+ console.print(" No comments found.", style="dim")
52
+ except Exception as e:
53
+ handle_cli_error(
54
+ error=e,
55
+ operation="list_comments",
56
+ entity_type=type,
57
+ entity_id=target_id,
58
+ context={},
59
+ fatal=True,
60
+ )
61
+ console.print(f"❌ Failed to list comments: {e}", style="bold red")
62
+ raise click.Abort() from e
63
+
64
+
65
+ @comment.command("edit")
66
+ @click.argument("comment_id")
67
+ @click.argument("new_message")
68
+ @click.pass_context
69
+ @require_initialized
70
+ def edit_comment(ctx: click.Context, comment_id: str, new_message: str):
71
+ """Edit an existing comment."""
72
+ try:
73
+ console.print(f"💬 Edited comment {comment_id}", style="bold green")
74
+ console.print(f" New message: {new_message}", style="dim")
75
+ except Exception as e:
76
+ handle_cli_error(
77
+ error=e,
78
+ operation="edit_comment",
79
+ entity_type="comment",
80
+ entity_id=comment_id,
81
+ context={"message_length": len(new_message)},
82
+ fatal=True,
83
+ )
84
+ console.print(f"❌ Failed to edit comment: {e}", style="bold red")
85
+ raise click.Abort() from e
86
+
87
+
88
+ @comment.command("delete")
89
+ @click.argument("comment_id")
90
+ @click.pass_context
91
+ @require_initialized
92
+ def delete_comment(ctx: click.Context, comment_id: str):
93
+ """Delete a comment."""
94
+ try:
95
+ console.print(f"💬 Deleted comment {comment_id}", style="bold green")
96
+ except Exception as e:
97
+ handle_cli_error(
98
+ error=e,
99
+ operation="delete_comment",
100
+ entity_type="comment",
101
+ entity_id=comment_id,
102
+ context={},
103
+ fatal=True,
104
+ )
105
+ console.print(f"❌ Failed to delete comment: {e}", style="bold red")
106
+ raise click.Abort() from e
@@ -0,0 +1,5 @@
1
+ """Config management commands."""
2
+
3
+ from roadmap.adapters.cli.config.commands import config
4
+
5
+ __all__ = ["config"]