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,288 @@
1
+ """Retry logic with exponential backoff for handling transient failures."""
2
+
3
+ import functools
4
+ import time
5
+ from collections.abc import Callable
6
+ from typing import Any, TypeVar
7
+
8
+ from ..logging import get_logger
9
+
10
+ logger = get_logger(__name__)
11
+
12
+ F = TypeVar("F", bound=Callable[..., Any])
13
+
14
+
15
+ def retry(
16
+ max_attempts: int = 3,
17
+ delay: float = 1.0,
18
+ backoff: float = 2.0,
19
+ exceptions: tuple[type[Exception], ...] = (Exception,),
20
+ on_retry: Callable[[Exception, int], None] | None = None,
21
+ ):
22
+ """Retry decorator with exponential backoff.
23
+
24
+ This decorator automatically retries a function if it raises one of the
25
+ specified exceptions. The delay between retries increases exponentially
26
+ using the backoff factor.
27
+
28
+ Args:
29
+ max_attempts: Maximum number of attempts (including the first try)
30
+ delay: Initial delay in seconds between retries
31
+ backoff: Multiplier for delay after each retry (exponential backoff)
32
+ exceptions: Tuple of exception types to catch and retry on
33
+ on_retry: Optional callback function called before each retry.
34
+ Takes (exception, attempt_number) as arguments.
35
+
36
+ Example:
37
+ @retry(max_attempts=5, delay=1.0, backoff=2.0, exceptions=(ConnectionError, TimeoutError))
38
+ def fetch_data():
39
+ # ... make network request
40
+ pass
41
+
42
+ The retry delays will be: 1s, 2s, 4s, 8s
43
+ """
44
+
45
+ def decorator(func: F) -> F:
46
+ @functools.wraps(func)
47
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
48
+ attempt = 0
49
+ current_delay = delay
50
+ last_exception: Exception | None = None
51
+
52
+ while attempt < max_attempts:
53
+ attempt += 1
54
+
55
+ try:
56
+ result = func(*args, **kwargs)
57
+
58
+ # Log success if we had previous failures
59
+ if attempt > 1:
60
+ logger.info(
61
+ "retry_succeeded",
62
+ function=func.__name__,
63
+ attempt=attempt,
64
+ max_attempts=max_attempts,
65
+ )
66
+
67
+ return result
68
+
69
+ except exceptions as e:
70
+ last_exception = e
71
+
72
+ # Don't retry if we've exhausted attempts
73
+ if attempt >= max_attempts:
74
+ logger.error(
75
+ "retry_exhausted",
76
+ function=func.__name__,
77
+ attempts=attempt,
78
+ error=str(e),
79
+ error_type=type(e).__name__,
80
+ )
81
+ raise
82
+
83
+ # Log retry attempt
84
+ logger.warning(
85
+ "retry_attempt",
86
+ function=func.__name__,
87
+ attempt=attempt,
88
+ max_attempts=max_attempts,
89
+ delay_seconds=current_delay,
90
+ error=str(e),
91
+ error_type=type(e).__name__,
92
+ )
93
+
94
+ # Call on_retry callback if provided
95
+ if on_retry:
96
+ try:
97
+ on_retry(e, attempt)
98
+ except Exception as callback_error:
99
+ logger.error(
100
+ "retry_callback_failed",
101
+ function=func.__name__,
102
+ error=str(callback_error),
103
+ )
104
+
105
+ # Wait before retrying
106
+ time.sleep(current_delay)
107
+
108
+ # Exponential backoff
109
+ current_delay *= backoff
110
+
111
+ # This should never be reached, but just in case
112
+ if last_exception:
113
+ raise last_exception
114
+ raise RuntimeError(f"Retry logic failed for {func.__name__}")
115
+
116
+ return wrapper # type: ignore
117
+
118
+ return decorator
119
+
120
+
121
+ def async_retry(
122
+ max_attempts: int = 3,
123
+ delay: float = 1.0,
124
+ backoff: float = 2.0,
125
+ exceptions: tuple[type[Exception], ...] = (Exception,),
126
+ on_retry: Callable[[Exception, int], None] | None = None,
127
+ ):
128
+ """Async version of retry decorator with exponential backoff.
129
+
130
+ Args:
131
+ max_attempts: Maximum number of attempts (including the first try)
132
+ delay: Initial delay in seconds between retries
133
+ backoff: Multiplier for delay after each retry (exponential backoff)
134
+ exceptions: Tuple of exception types to catch and retry on
135
+ on_retry: Optional callback function called before each retry
136
+
137
+ Example:
138
+ @async_retry(max_attempts=5, delay=1.0, backoff=2.0)
139
+ async def fetch_data():
140
+ # ... make async network request
141
+ pass
142
+ """
143
+
144
+ def decorator(func: F) -> F:
145
+ @functools.wraps(func)
146
+ async def wrapper(*args: Any, **kwargs: Any) -> Any:
147
+ import asyncio
148
+
149
+ attempt = 0
150
+ current_delay = delay
151
+ last_exception: Exception | None = None
152
+
153
+ while attempt < max_attempts:
154
+ attempt += 1
155
+
156
+ try:
157
+ result = await func(*args, **kwargs)
158
+
159
+ # Log success if we had previous failures
160
+ if attempt > 1:
161
+ logger.info(
162
+ "async_retry_succeeded",
163
+ function=func.__name__,
164
+ attempt=attempt,
165
+ max_attempts=max_attempts,
166
+ )
167
+
168
+ return result
169
+
170
+ except exceptions as e:
171
+ last_exception = e
172
+
173
+ # Don't retry if we've exhausted attempts
174
+ if attempt >= max_attempts:
175
+ logger.error(
176
+ "async_retry_exhausted",
177
+ function=func.__name__,
178
+ attempts=attempt,
179
+ error=str(e),
180
+ error_type=type(e).__name__,
181
+ )
182
+ raise
183
+
184
+ # Log retry attempt
185
+ logger.warning(
186
+ "async_retry_attempt",
187
+ function=func.__name__,
188
+ attempt=attempt,
189
+ max_attempts=max_attempts,
190
+ delay_seconds=current_delay,
191
+ error=str(e),
192
+ error_type=type(e).__name__,
193
+ )
194
+
195
+ # Call on_retry callback if provided
196
+ if on_retry:
197
+ try:
198
+ on_retry(e, attempt)
199
+ except Exception as callback_error:
200
+ logger.error(
201
+ "async_retry_callback_failed",
202
+ function=func.__name__,
203
+ error=str(callback_error),
204
+ )
205
+
206
+ # Wait before retrying (async sleep)
207
+ await asyncio.sleep(current_delay)
208
+
209
+ # Exponential backoff
210
+ current_delay *= backoff
211
+
212
+ # This should never be reached, but just in case
213
+ if last_exception:
214
+ raise last_exception
215
+ raise RuntimeError(f"Async retry logic failed for {func.__name__}")
216
+
217
+ return wrapper # type: ignore
218
+
219
+ return decorator
220
+
221
+
222
+ class RetryConfig:
223
+ """Configuration for retry behavior.
224
+
225
+ This class provides a convenient way to share retry configuration
226
+ across multiple operations.
227
+ """
228
+
229
+ def __init__(
230
+ self,
231
+ max_attempts: int = 3,
232
+ delay: float = 1.0,
233
+ backoff: float = 2.0,
234
+ exceptions: tuple[type[Exception], ...] = (Exception,),
235
+ ):
236
+ """Initialize retry configuration.
237
+
238
+ Args:
239
+ max_attempts: Maximum number of attempts
240
+ delay: Initial delay in seconds
241
+ backoff: Exponential backoff multiplier
242
+ exceptions: Exception types to retry on
243
+ """
244
+ self.max_attempts = max_attempts
245
+ self.delay = delay
246
+ self.backoff = backoff
247
+ self.exceptions = exceptions
248
+
249
+ def __call__(self, func: F) -> F:
250
+ """Use config as a decorator."""
251
+ return retry(
252
+ max_attempts=self.max_attempts,
253
+ delay=self.delay,
254
+ backoff=self.backoff,
255
+ exceptions=self.exceptions,
256
+ )(func)
257
+
258
+ def async_decorator(self, func: F) -> F:
259
+ """Use config as an async decorator."""
260
+ return async_retry(
261
+ max_attempts=self.max_attempts,
262
+ delay=self.delay,
263
+ backoff=self.backoff,
264
+ exceptions=self.exceptions,
265
+ )(func)
266
+
267
+
268
+ # Predefined retry configurations for common scenarios
269
+ NETWORK_RETRY = RetryConfig(
270
+ max_attempts=5,
271
+ delay=1.0,
272
+ backoff=2.0,
273
+ exceptions=(ConnectionError, TimeoutError, OSError),
274
+ )
275
+
276
+ API_RETRY = RetryConfig(
277
+ max_attempts=3,
278
+ delay=0.5,
279
+ backoff=1.5,
280
+ exceptions=(ConnectionError, TimeoutError),
281
+ )
282
+
283
+ DATABASE_RETRY = RetryConfig(
284
+ max_attempts=3,
285
+ delay=0.1,
286
+ backoff=2.0,
287
+ exceptions=(Exception,), # Database-specific exceptions would go here
288
+ )
@@ -0,0 +1,114 @@
1
+ """Centralized status styling for consistent UI across application.
2
+
3
+ This module consolidates all status-to-style mappings to eliminate DRY violations
4
+ and ensure consistent status rendering everywhere.
5
+ """
6
+
7
+ from enum import Enum
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ if TYPE_CHECKING:
11
+ pass
12
+
13
+
14
+ class StatusStyle(Enum):
15
+ """Enum for common status values."""
16
+
17
+ TODO = "TODO"
18
+ IN_PROGRESS = "IN_PROGRESS"
19
+ BLOCKED = "BLOCKED"
20
+ REVIEW = "REVIEW"
21
+ CLOSED = "CLOSED"
22
+ OPEN = "OPEN"
23
+ COMPLETED = "COMPLETED"
24
+ ARCHIVED = "ARCHIVED"
25
+
26
+
27
+ class StatusStyleManager:
28
+ """Centralized manager for status styling across application."""
29
+
30
+ # Rich style mappings for status values
31
+ STATUS_STYLES: dict[str, str] = {
32
+ # Issue/Task statuses
33
+ "TODO": "white",
34
+ "IN_PROGRESS": "yellow",
35
+ "BLOCKED": "red",
36
+ "REVIEW": "blue",
37
+ "CLOSED": "green",
38
+ # Project/Milestone statuses
39
+ "OPEN": "cyan",
40
+ "COMPLETED": "green",
41
+ "ARCHIVED": "dim",
42
+ }
43
+
44
+ # Emoji mapping for status
45
+ STATUS_EMOJIS: dict[str, str] = {
46
+ "TODO": "📝",
47
+ "IN_PROGRESS": "🔄",
48
+ "BLOCKED": "🚫",
49
+ "REVIEW": "👀",
50
+ "CLOSED": "✅",
51
+ "OPEN": "📂",
52
+ "COMPLETED": "🎉",
53
+ "ARCHIVED": "📦",
54
+ }
55
+
56
+ @classmethod
57
+ def get_style(cls, status: str | Enum) -> str:
58
+ """Get Rich style string for a status.
59
+
60
+ Args:
61
+ status: Status value (string or Enum)
62
+
63
+ Returns:
64
+ Rich style string (e.g., "bold red")
65
+ """
66
+ status_str = status.value if isinstance(status, Enum) else str(status).upper()
67
+ return cls.STATUS_STYLES.get(status_str, "white")
68
+
69
+ @classmethod
70
+ def get_emoji(cls, status: str | Enum) -> str:
71
+ """Get emoji for a status.
72
+
73
+ Args:
74
+ status: Status value (string or Enum)
75
+
76
+ Returns:
77
+ Emoji character
78
+ """
79
+ status_str = status.value if isinstance(status, Enum) else str(status).upper()
80
+ return cls.STATUS_EMOJIS.get(status_str, "•")
81
+
82
+ @classmethod
83
+ def get_rich_text(cls, status: str | Enum, text: str | None = None) -> Any:
84
+ """Create Rich Text object with proper style and emoji.
85
+
86
+ Args:
87
+ status: Status value
88
+ text: Optional custom text (defaults to status string)
89
+
90
+ Returns:
91
+ Rich Text object ready for rendering
92
+ """
93
+ from rich.text import Text
94
+
95
+ display_text = text or str(status)
96
+ return Text(display_text, style=cls.get_style(status))
97
+
98
+ @classmethod
99
+ def all_styles(cls) -> dict[str, str]:
100
+ """Get all available status styles.
101
+
102
+ Returns:
103
+ Dictionary mapping status -> style
104
+ """
105
+ return cls.STATUS_STYLES.copy()
106
+
107
+ @classmethod
108
+ def all_emojis(cls) -> dict[str, str]:
109
+ """Get all available status emojis.
110
+
111
+ Returns:
112
+ Dictionary mapping status -> emoji
113
+ """
114
+ return cls.STATUS_EMOJIS.copy()
@@ -0,0 +1,88 @@
1
+ """Union-Find (Disjoint Set Union) data structure with path compression.
2
+
3
+ Provides O(α(n)) ≈ O(1) operations for union and find operations,
4
+ where α is the inverse Ackermann function (effectively constant).
5
+ """
6
+
7
+ from typing import Any
8
+
9
+
10
+ class UnionFind:
11
+ """Efficient disjoint set data structure with path compression and union by rank."""
12
+
13
+ def __init__(self, items: list[Any]) -> None:
14
+ """Initialize union-find with given items.
15
+
16
+ Args:
17
+ items: List of hashable items to track
18
+ """
19
+ self.parent: dict[Any, Any] = {item: item for item in items}
20
+ self.rank: dict[Any, int] = dict.fromkeys(items, 0)
21
+
22
+ def find(self, item: Any) -> Any:
23
+ """Find the canonical representative of item's set with path compression.
24
+
25
+ Args:
26
+ item: Item to find representative for
27
+
28
+ Returns:
29
+ Canonical representative of item's set
30
+ """
31
+ if self.parent[item] != item:
32
+ # Path compression: point directly to root
33
+ self.parent[item] = self.find(self.parent[item])
34
+ return self.parent[item]
35
+
36
+ def union(self, item1: Any, item2: Any) -> bool:
37
+ """Union the sets containing item1 and item2.
38
+
39
+ Args:
40
+ item1: First item
41
+ item2: Second item
42
+
43
+ Returns:
44
+ True if union occurred, False if already in same set
45
+ """
46
+ root1 = self.find(item1)
47
+ root2 = self.find(item2)
48
+
49
+ if root1 == root2:
50
+ return False # Already in same set
51
+
52
+ # Union by rank: attach smaller tree under larger
53
+ if self.rank[root1] < self.rank[root2]:
54
+ self.parent[root1] = root2
55
+ elif self.rank[root1] > self.rank[root2]:
56
+ self.parent[root2] = root1
57
+ else:
58
+ # Same rank: pick one and increment its rank
59
+ self.parent[root2] = root1
60
+ self.rank[root1] += 1
61
+
62
+ return True
63
+
64
+ def get_canonical(self, item: Any) -> Any:
65
+ """Get canonical representative (alias for find)."""
66
+ return self.find(item)
67
+
68
+ def get_representatives(self) -> set[Any]:
69
+ """Get all canonical representatives (roots of each set).
70
+
71
+ Returns:
72
+ Set of canonical representatives
73
+ """
74
+ return {self.find(item) for item in self.parent.keys()}
75
+
76
+ def get_groups(self) -> dict[Any, list[Any]]:
77
+ """Get mapping of representative -> list of items in that group.
78
+
79
+ Returns:
80
+ Dict mapping canonical representative to list of items
81
+ """
82
+ groups: dict[Any, list[Any]] = {}
83
+ for item in self.parent.keys():
84
+ rep = self.find(item)
85
+ if rep not in groups:
86
+ groups[rep] = []
87
+ groups[rep].append(item)
88
+ return groups
@@ -0,0 +1,13 @@
1
+ """Shared constants for update operations."""
2
+
3
+ # Fields that are displayed when showing update results
4
+ DISPLAYABLE_UPDATE_FIELDS = [
5
+ "title",
6
+ "priority",
7
+ "status",
8
+ "assignee",
9
+ "milestone",
10
+ "description",
11
+ ]
12
+
13
+ __all__ = ["DISPLAYABLE_UPDATE_FIELDS"]
@@ -0,0 +1,65 @@
1
+ """Common utility functions for CLI operations, file handling, and data processing.
2
+
3
+ This package provides low-level utilities used across the application:
4
+ - CLI helpers: Output formatting, decorators for command functions
5
+ - File utilities: File operations and secure file handling
6
+ - Path utilities: Path checking and validation
7
+ - Status utilities: Status-related helpers
8
+ - Timezone utilities: Timezone-aware date/time operations
9
+
10
+ Note: These are utility functions with minimal dependencies - they should not
11
+ import from higher-level modules (services, domain, adapters) to avoid
12
+ layer violations and circular dependencies.
13
+ """
14
+
15
+ from .cli_helpers import OutputFormatHandler, format_output
16
+ from .file_utils import (
17
+ SecureFileManager,
18
+ backup_file,
19
+ cleanup_temp_files,
20
+ ensure_directory_exists,
21
+ file_exists_check,
22
+ get_file_size,
23
+ safe_read_file,
24
+ safe_write_file,
25
+ )
26
+ from .path_utils import build_roadmap_paths
27
+ from .status_utils import StatusSummary
28
+ from .timezone_utils import (
29
+ TimezoneManager,
30
+ ensure_timezone_aware,
31
+ format_datetime,
32
+ format_relative_time,
33
+ get_timezone_manager,
34
+ migrate_naive_datetime,
35
+ now_local,
36
+ now_utc,
37
+ )
38
+
39
+ __all__ = [
40
+ # CLI helpers
41
+ "OutputFormatHandler",
42
+ "format_output",
43
+ # File utilities
44
+ "SecureFileManager",
45
+ "backup_file",
46
+ "cleanup_temp_files",
47
+ "ensure_directory_exists",
48
+ "file_exists_check",
49
+ "get_file_size",
50
+ "safe_read_file",
51
+ "safe_write_file",
52
+ # Path utilities
53
+ "build_roadmap_paths",
54
+ # Status utilities
55
+ "StatusSummary",
56
+ # Timezone utilities
57
+ "TimezoneManager",
58
+ "ensure_timezone_aware",
59
+ "format_datetime",
60
+ "format_relative_time",
61
+ "get_timezone_manager",
62
+ "migrate_naive_datetime",
63
+ "now_local",
64
+ "now_utc",
65
+ ]