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,154 @@
1
+ """GitHub configuration management utilities."""
2
+
3
+ import yaml
4
+ from structlog import get_logger
5
+
6
+ from roadmap.common.console import get_console
7
+ from roadmap.common.constants import SyncBackend
8
+ from roadmap.core.utils.git_remote_parser import get_github_from_git_remote
9
+ from roadmap.infrastructure.coordination.core import RoadmapCore
10
+
11
+ logger = get_logger()
12
+ console = get_console()
13
+
14
+
15
+ class GitHubConfigManager:
16
+ """Manages GitHub configuration in roadmap config file."""
17
+
18
+ def __init__(self, core: RoadmapCore):
19
+ """Initialize GitHubConfigManager.
20
+
21
+ Args:
22
+ core: Core roadmap instance.
23
+ """
24
+ self.core = core
25
+ self.config_file = core.roadmap_dir / "config.yaml"
26
+
27
+ def save_github_config(
28
+ self, github_repo: str, sync_backend: SyncBackend = SyncBackend.GITHUB
29
+ ) -> None:
30
+ """Save GitHub repository configuration.
31
+
32
+ Args:
33
+ github_repo: GitHub repository (owner/repo)
34
+ sync_backend: Backend to use (SyncBackend.GITHUB or SyncBackend.GIT)
35
+
36
+ Raises:
37
+ ValueError: If github_repo is invalid format
38
+ """
39
+ # Validate repository format
40
+ if not github_repo or "/" not in github_repo:
41
+ log = logger.bind(github_repo=github_repo, operation="save_github_config")
42
+ log.error("invalid_github_repo_format")
43
+ raise ValueError(
44
+ f"Invalid GitHub repository format: '{github_repo}'. "
45
+ "Expected format: 'owner/repo'"
46
+ )
47
+
48
+ try:
49
+ if self.config_file.exists():
50
+ with open(self.config_file) as f:
51
+ loaded = yaml.safe_load(f)
52
+ config = loaded if isinstance(loaded, dict) else {}
53
+ else:
54
+ config: dict = {}
55
+
56
+ config["github"] = {
57
+ "repository": github_repo,
58
+ "enabled": True,
59
+ "sync_enabled": True,
60
+ "sync_backend": sync_backend.value,
61
+ "webhook_secret": None,
62
+ "sync_settings": {
63
+ "bidirectional": True,
64
+ "auto_close": True,
65
+ "sync_labels": True,
66
+ "sync_milestones": True,
67
+ },
68
+ }
69
+
70
+ with open(self.config_file, "w") as f:
71
+ yaml.dump(config, f, default_flow_style=False, sort_keys=False)
72
+
73
+ log = logger.bind(
74
+ github_repo=github_repo,
75
+ sync_backend=sync_backend.value,
76
+ operation="save_github_config",
77
+ )
78
+ log.info("github_config_saved")
79
+ get_console().print("⚙️ Configuration saved")
80
+
81
+ except ValueError:
82
+ # Re-raise validation errors
83
+ raise
84
+ except Exception as e:
85
+ log = logger.bind(
86
+ github_repo=github_repo,
87
+ sync_backend=sync_backend.value,
88
+ error=str(e),
89
+ operation="save_github_config",
90
+ )
91
+ log.error("github_config_save_failed")
92
+ raise
93
+
94
+ def auto_detect_and_update(self) -> tuple[str | None, str | None]:
95
+ """Auto-detect GitHub owner/repo from git remote and update config if needed.
96
+
97
+ Returns:
98
+ Tuple of (owner, repo) or (None, None) if not detected or disabled
99
+ """
100
+ # Check if auto-detection is enabled in config
101
+ if self.config_file.exists():
102
+ try:
103
+ with open(self.config_file) as f:
104
+ loaded = yaml.safe_load(f)
105
+ config = loaded if isinstance(loaded, dict) else {}
106
+ github_config = config.get("github", {})
107
+ sync_settings = github_config.get("sync_settings", {})
108
+
109
+ # Check if auto-detection is disabled
110
+ if not sync_settings.get("auto_detect_from_git", True):
111
+ return None, None
112
+
113
+ # If owner/repo already set, don't override
114
+ if github_config.get("repository"):
115
+ return None, None
116
+ except Exception as e:
117
+ logger.debug("config_read_failed", error=str(e))
118
+
119
+ # Try to auto-detect from git remote
120
+ owner, repo = get_github_from_git_remote(self.core.root_path)
121
+
122
+ if owner and repo:
123
+ try:
124
+ github_repo = f"{owner}/{repo}"
125
+ logger.info(
126
+ "github_auto_detected",
127
+ owner=owner,
128
+ repo=repo,
129
+ repository=github_repo,
130
+ )
131
+
132
+ # Update config with detected values
133
+ if self.config_file.exists():
134
+ with open(self.config_file) as f:
135
+ loaded = yaml.safe_load(f)
136
+ config = loaded if isinstance(loaded, dict) else {}
137
+ else:
138
+ config = {}
139
+
140
+ if "github" not in config:
141
+ config["github"] = {}
142
+
143
+ config["github"]["repository"] = github_repo
144
+ config["github"]["enabled"] = True
145
+
146
+ with open(self.config_file, "w") as f:
147
+ yaml.dump(config, f, default_flow_style=False, sort_keys=False)
148
+
149
+ return owner, repo
150
+
151
+ except Exception as e:
152
+ logger.debug("github_auto_config_failed", error=str(e))
153
+
154
+ return None, None
@@ -0,0 +1,84 @@
1
+ """GitHub token resolution and management utilities."""
2
+
3
+ import os
4
+
5
+ import click
6
+ from structlog import get_logger
7
+
8
+ from roadmap.common.console import get_console
9
+
10
+ console = get_console()
11
+ logger = get_logger()
12
+
13
+
14
+ class GitHubTokenResolver:
15
+ """Resolves GitHub tokens from multiple sources."""
16
+
17
+ def __init__(self, cred_manager=None): # type: ignore
18
+ """Initialize GitHubTokenResolver.
19
+
20
+ Args:
21
+ cred_manager: Optional credential manager instance.
22
+ """
23
+ self.cred_manager = cred_manager
24
+
25
+ def get_existing_token(self) -> str | None:
26
+ """Get existing stored token."""
27
+ if not self.cred_manager:
28
+ return None
29
+ try:
30
+ return self.cred_manager.get_token()
31
+ except Exception as e:
32
+ logger.debug("stored_token_retrieval_failed", error=str(e))
33
+ return None
34
+
35
+ def resolve_token(
36
+ self,
37
+ cli_token: str | None,
38
+ interactive: bool,
39
+ yes: bool,
40
+ existing_token: str | None,
41
+ ) -> tuple[str | None, bool]:
42
+ """Resolve which token to use.
43
+
44
+ Returns:
45
+ Tuple of (token, should_continue)
46
+ """
47
+ # Priority: CLI arg > environment > stored > prompt
48
+ env_token = os.environ.get("ROADMAP_GITHUB_TOKEN")
49
+
50
+ if cli_token:
51
+ return cli_token, True
52
+
53
+ if env_token:
54
+ console.print(
55
+ "ℹ️ Using GitHub token from environment variable ROADMAP_GITHUB_TOKEN",
56
+ style="dim",
57
+ )
58
+ return env_token, True
59
+
60
+ if existing_token:
61
+ if interactive and not yes:
62
+ console.print("🔍 Found existing GitHub credentials")
63
+ if click.confirm("Use existing GitHub credentials?"):
64
+ console.print("✅ Using existing GitHub credentials")
65
+ return existing_token, True
66
+ else:
67
+ return existing_token, True
68
+
69
+ # Need to get token from user
70
+ if interactive and not yes:
71
+ console.print(
72
+ "To integrate with GitHub you'll need a personal access token with 'repo' scope."
73
+ )
74
+ console.print("→ Create one: https://github.com/settings/tokens")
75
+ token = click.prompt("Paste your GitHub token", hide_input=True)
76
+ return token, True
77
+
78
+ # Non-interactive without token
79
+ console.print(
80
+ "❌ Non-interactive mode requires providing a token via --github-token "
81
+ "or setting ROADMAP_GITHUB_TOKEN, or use --skip-github to skip integration.",
82
+ style="bold red",
83
+ )
84
+ return None, False
@@ -0,0 +1,184 @@
1
+ """Console utilities for CLI operations.
2
+
3
+ Provides centralized console instances configured for the current environment:
4
+ - get_console() → Rich console for successful output (stdout)
5
+ - get_console_stderr() → Console for errors/warnings (stderr)
6
+ - is_plain_mode() → Auto-detect plain text mode for POSIX compliance
7
+
8
+ Plain mode is auto-detected based on:
9
+ - Output is not a terminal (piped/redirected)
10
+ - ROADMAP_OUTPUT=plain environment variable
11
+ - NO_COLOR=1 environment variable
12
+ - Running in CI/CD environment
13
+
14
+ This separation ensures:
15
+ - Success output to stdout (can be piped, has colors)
16
+ - Errors to stderr (never interferes with data)
17
+ - POSIX compliance (no ANSI codes when piped)
18
+ - Machine-readable output (can parse stdout, ignore stderr)
19
+ """
20
+
21
+ import os
22
+ import sys
23
+
24
+ from rich.console import Console
25
+
26
+
27
+ def is_plain_mode() -> bool:
28
+ """Detect if we should use plain text output (no ANSI codes).
29
+
30
+ Returns True if any of:
31
+ - Output is redirected/piped (not a terminal)
32
+ - ROADMAP_OUTPUT=plain environment variable set
33
+ - NO_COLOR=1 for POSIX compliance
34
+ - Running in CI/CD environment
35
+ - In testing environment
36
+
37
+ Returns:
38
+ bool: True if plain mode should be used
39
+ """
40
+ return any(
41
+ [
42
+ # Explicit plain mode request
43
+ os.environ.get("ROADMAP_OUTPUT") == "plain",
44
+ # POSIX NO_COLOR standard
45
+ os.environ.get("NO_COLOR") in ("1", "true", "True", "TRUE"),
46
+ # User forced no colors
47
+ os.environ.get("FORCE_COLOR") == "0",
48
+ # Output is piped/redirected (not interactive)
49
+ not sys.stdout.isatty(),
50
+ not sys.stderr.isatty(),
51
+ # CI/CD environments
52
+ any(
53
+ ci_var in os.environ
54
+ for ci_var in [
55
+ "CI",
56
+ "CONTINUOUS_INTEGRATION",
57
+ "GITHUB_ACTIONS",
58
+ "TRAVIS",
59
+ "CIRCLECI",
60
+ "JENKINS_URL",
61
+ "GITLAB_CI",
62
+ ]
63
+ ),
64
+ # Testing environment
65
+ any(
66
+ test_var in os.environ
67
+ for test_var in [
68
+ "PYTEST_CURRENT_TEST",
69
+ "_PYTEST_RAISE",
70
+ "UNITTEST_MODE",
71
+ ]
72
+ ),
73
+ ]
74
+ )
75
+
76
+
77
+ def is_testing_environment() -> bool:
78
+ """Detect if we're running in a testing environment.
79
+
80
+ Returns True if any of the following conditions are met:
81
+ - pytest is running
82
+ - NO_COLOR environment variable is set
83
+ - TERM is set to 'dumb'
84
+ - Output is not a terminal
85
+ - Running under CI/CD
86
+ """
87
+ return any(
88
+ [
89
+ # Pytest detection
90
+ "PYTEST_CURRENT_TEST" in os.environ,
91
+ "pytest" in sys.modules,
92
+ hasattr(sys, "_called_from_test"),
93
+ # Explicit color disabling
94
+ os.environ.get("NO_COLOR") in ("1", "true", "True", "TRUE"),
95
+ os.environ.get("FORCE_COLOR") == "0",
96
+ # Terminal detection
97
+ os.environ.get("TERM") in ("dumb", ""),
98
+ not sys.stdout.isatty(),
99
+ not sys.stderr.isatty(),
100
+ # CI/CD environments
101
+ any(
102
+ ci_var in os.environ
103
+ for ci_var in [
104
+ "CI",
105
+ "CONTINUOUS_INTEGRATION",
106
+ "GITHUB_ACTIONS",
107
+ "TRAVIS",
108
+ "CIRCLECI",
109
+ "JENKINS_URL",
110
+ "GITLAB_CI",
111
+ ]
112
+ ),
113
+ # Test frameworks
114
+ any(
115
+ test_var in os.environ
116
+ for test_var in [
117
+ "PYTEST_CURRENT_TEST",
118
+ "_PYTEST_RAISE",
119
+ "UNITTEST_MODE",
120
+ ]
121
+ ),
122
+ ]
123
+ )
124
+
125
+
126
+ def get_console() -> Console:
127
+ """Get a console instance configured for successful output (stdout).
128
+
129
+ Returns a console configured for:
130
+ - Rich output when in interactive terminal (colors, tables, styles)
131
+ - Plain text output when piped/testing (POSIX compliance)
132
+ - No ANSI codes when plain mode is detected
133
+
134
+ Returns a fresh instance each time to ensure file handle is current.
135
+
136
+ Returns:
137
+ Console: Configured Rich Console instance
138
+ """
139
+ plain = is_plain_mode()
140
+
141
+ # Use fresh instance each time to ensure file handle is correct
142
+ # This is critical for testing with CliRunner which replaces sys.stdout
143
+ if plain:
144
+ return Console(
145
+ file=sys.stdout,
146
+ force_terminal=False,
147
+ no_color=True,
148
+ width=80,
149
+ legacy_windows=False,
150
+ force_interactive=False,
151
+ force_jupyter=False,
152
+ )
153
+
154
+ # Interactive mode: full Rich features
155
+ return Console(file=sys.stdout)
156
+
157
+
158
+ def get_console_stderr() -> Console:
159
+ """Get a console instance configured for error output (stderr).
160
+
161
+ Returns a console that outputs to stderr for:
162
+ - Error messages
163
+ - Warnings
164
+ - Diagnostic information
165
+
166
+ This ensures errors don't interfere with stdout data.
167
+
168
+ Returns:
169
+ Console: Console instance writing to stderr
170
+ """
171
+ plain = is_plain_mode()
172
+
173
+ # In testing/plain mode: no terminal, no colors
174
+ if plain:
175
+ return Console(
176
+ file=sys.stderr,
177
+ force_terminal=False,
178
+ no_color=True,
179
+ width=80,
180
+ legacy_windows=False,
181
+ )
182
+
183
+ # Interactive mode: use stderr with colors
184
+ return Console(file=sys.stderr)
@@ -0,0 +1,134 @@
1
+ """Application-wide constants and enums."""
2
+
3
+ from enum import StrEnum
4
+
5
+
6
+ class Priority(StrEnum):
7
+ """Issue priority levels."""
8
+
9
+ CRITICAL = "critical"
10
+ HIGH = "high"
11
+ MEDIUM = "medium"
12
+ LOW = "low"
13
+
14
+
15
+ class Status(StrEnum):
16
+ """Issue status values."""
17
+
18
+ TODO = "todo"
19
+ IN_PROGRESS = "in-progress"
20
+ BLOCKED = "blocked"
21
+ REVIEW = "review"
22
+ CLOSED = "closed"
23
+ ARCHIVED = "archived" # Soft-deleted (duplicate or obsolete)
24
+
25
+
26
+ class MilestoneStatus(StrEnum):
27
+ """Milestone status values."""
28
+
29
+ OPEN = "open"
30
+ CLOSED = "closed"
31
+
32
+
33
+ class ProjectStatus(StrEnum):
34
+ """Project status values."""
35
+
36
+ PLANNING = "planning"
37
+ ACTIVE = "active"
38
+ ON_HOLD = "on-hold"
39
+ COMPLETED = "completed"
40
+ CANCELLED = "cancelled"
41
+
42
+
43
+ class RiskLevel(StrEnum):
44
+ """Risk level values for projects and milestones."""
45
+
46
+ LOW = "low"
47
+ MEDIUM = "medium"
48
+ HIGH = "high"
49
+
50
+
51
+ class IssueType(StrEnum):
52
+ """Issue type categories."""
53
+
54
+ FEATURE = "feature"
55
+ BUG = "bug"
56
+ OTHER = "other"
57
+
58
+
59
+ class SyncBackend(StrEnum):
60
+ """Sync backend types."""
61
+
62
+ GITHUB = "github"
63
+ GIT = "git"
64
+
65
+
66
+ # Application Configuration Defaults
67
+ # ============================================================================
68
+
69
+ # File and path defaults
70
+ DEFAULT_ROADMAP_FILE = "ROADMAP.md"
71
+ DEFAULT_CONFIG_FILE = ".roadmaprc"
72
+ DEFAULT_DATA_DIR = ".roadmap"
73
+ DEFAULT_CACHE_FILE = ".roadmap_cache.json"
74
+
75
+ # GitHub API defaults
76
+ GITHUB_API_BASE = "https://api.github.com"
77
+ GITHUB_GRAPHQL_ENDPOINT = "https://api.github.com/graphql"
78
+ GITHUB_API_TIMEOUT = 30 # seconds
79
+ GITHUB_RATE_LIMIT_THRESHOLD = 10 # remaining requests before warning
80
+
81
+ # Display defaults
82
+ DEFAULT_TABLE_WIDTH = 80
83
+ DEFAULT_MAX_ITEMS_DISPLAY = 20
84
+ DEFAULT_DATE_FORMAT = "%Y-%m-%d"
85
+ DEFAULT_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
86
+
87
+ # Caching defaults
88
+ CACHE_TTL_DEFAULT = 3600 # 1 hour in seconds
89
+ CACHE_TTL_LONG = 86400 # 24 hours in seconds
90
+ CACHE_TTL_SHORT = 300 # 5 minutes in seconds
91
+
92
+ # Batch operation defaults
93
+ DEFAULT_BATCH_SIZE = 50
94
+ DEFAULT_MAX_RETRIES = 3
95
+ DEFAULT_RETRY_DELAY = 1 # seconds
96
+ DEFAULT_BACKOFF_FACTOR = 2
97
+
98
+ # Progress tracking defaults
99
+ PROGRESS_REFRESH_INTERVAL = 0.1 # seconds
100
+ PROGRESS_BAR_LENGTH = 30
101
+
102
+ # Logging defaults
103
+ LOG_LEVEL_DEFAULT = "INFO"
104
+ LOG_FORMAT_DEFAULT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
105
+
106
+ # Error handling defaults
107
+ ERROR_MESSAGE_MAX_LENGTH = 500
108
+ VALIDATION_ERROR_MAX_FIELDS = 10
109
+
110
+ # Authentication defaults
111
+ AUTH_TOKEN_ENV_VAR = "GITHUB_TOKEN"
112
+ AUTH_TIMEOUT = 30 # seconds
113
+
114
+ # Git defaults
115
+ GIT_TIMEOUT = 60 # seconds
116
+ GIT_MAX_OUTPUT_LINES = 1000
117
+ GIT_COMMIT_MESSAGE_MAX_LENGTH = 72
118
+
119
+ # Project analysis defaults
120
+ ANALYSIS_MIN_SAMPLE_SIZE = 5
121
+ ANALYSIS_MAX_HISTORICAL_DAYS = 365
122
+ ANALYSIS_TREND_WINDOW = 7 # days
123
+
124
+ # Performance defaults
125
+ PERFORMANCE_ENABLE_CACHE = True
126
+ PERFORMANCE_ENABLE_ASYNC = True
127
+ PERFORMANCE_THREAD_POOL_SIZE = 4
128
+ PERFORMANCE_CONNECTION_POOL_SIZE = 10
129
+
130
+ # Validation defaults
131
+ VALIDATION_TITLE_MIN_LENGTH = 1
132
+ VALIDATION_TITLE_MAX_LENGTH = 500
133
+ VALIDATION_DESCRIPTION_MAX_LENGTH = 5000
134
+ VALIDATION_NAME_PATTERN = r"^[a-zA-Z0-9_-]+$"