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,96 @@
1
+ """Lookup issue by GitHub ID command - find internal issue by GitHub issue number."""
2
+
3
+ import click
4
+
5
+ from roadmap.adapters.cli.cli_command_helpers import require_initialized
6
+ from roadmap.common.console import get_console
7
+ from roadmap.common.formatters.text.operations import (
8
+ format_operation_failure,
9
+ )
10
+ from roadmap.common.logging import (
11
+ log_command,
12
+ )
13
+
14
+ console = get_console()
15
+
16
+
17
+ @click.command("lookup-github")
18
+ @click.argument("github_id", type=int)
19
+ @click.pass_context
20
+ @log_command("issue_lookup_github", entity_type="issue", track_duration=True)
21
+ @require_initialized
22
+ def lookup_github_issue(ctx: click.Context, github_id: int) -> None:
23
+ """Look up an internal issue by its GitHub issue number.
24
+
25
+ Searches for an internal issue linked to the provided GitHub issue number
26
+ and displays its details.
27
+
28
+ Example:
29
+ roadmap issue lookup-github 456
30
+ """
31
+ core = ctx.obj["core"]
32
+
33
+ # Validate GitHub ID is positive
34
+ if github_id <= 0:
35
+ lines = format_operation_failure(
36
+ "lookup GitHub issue", None, "Invalid GitHub issue number"
37
+ )
38
+ for line in lines:
39
+ # Use click.echo for proper output capture in Click's CliRunner
40
+ click.echo(line)
41
+ ctx.exit(1)
42
+
43
+ # Get all issues and search for one with matching github_issue
44
+ all_issues = core.issues.get_all()
45
+ matching_issue = None
46
+
47
+ for issue in all_issues:
48
+ if issue.github_issue == github_id:
49
+ matching_issue = issue
50
+ break
51
+
52
+ if not matching_issue:
53
+ lines = format_operation_failure(
54
+ "lookup GitHub issue",
55
+ None,
56
+ f"No issue found linked to GitHub issue #{github_id}",
57
+ )
58
+ for line in lines:
59
+ # Use click.echo for proper output capture in Click's CliRunner
60
+ click.echo(line)
61
+ ctx.exit(1)
62
+
63
+ # Display issue details
64
+ console.print(
65
+ f"✅ Found issue linked to GitHub issue #{github_id}", style="bold green"
66
+ )
67
+ console.print()
68
+ console.print(f" ID: {matching_issue.id}", style="cyan")
69
+ console.print(f" Title: {matching_issue.title}", style="bold")
70
+ console.print(f" Status: {matching_issue.status.value}", style="cyan")
71
+ console.print(f" Priority: {matching_issue.priority.value}", style="cyan")
72
+
73
+ if matching_issue.assignee:
74
+ console.print(f" Assigned to: {matching_issue.assignee}", style="cyan")
75
+
76
+ if matching_issue.milestone:
77
+ console.print(f" Milestone: {matching_issue.milestone}", style="cyan")
78
+
79
+ if matching_issue.labels:
80
+ console.print(f" Labels: {', '.join(matching_issue.labels)}", style="cyan")
81
+
82
+ if matching_issue.estimated_hours:
83
+ console.print(
84
+ f" Estimated: {matching_issue.estimated_time_display}", style="cyan"
85
+ )
86
+
87
+ if matching_issue.content:
88
+ console.print()
89
+ console.print("Description:", style="bold cyan")
90
+ console.print(matching_issue.content, style="dim")
91
+
92
+ console.print()
93
+ console.print(
94
+ f" Use 'roadmap issue view {matching_issue.id}' for full details",
95
+ style="dim",
96
+ )
@@ -0,0 +1,102 @@
1
+ """Update progress command - thin wrapper around update.
2
+
3
+ This command is syntactic sugar for: roadmap issue update <ID> --progress <PERCENT>
4
+ """
5
+
6
+ import click
7
+
8
+ from roadmap.adapters.cli.cli_command_helpers import (
9
+ ensure_entity_exists,
10
+ require_initialized,
11
+ )
12
+ from roadmap.adapters.cli.cli_error_handlers import handle_cli_error
13
+ from roadmap.common.console import get_console
14
+ from roadmap.common.formatters.text.operations import (
15
+ format_operation_failure,
16
+ format_operation_success,
17
+ )
18
+ from roadmap.common.logging import (
19
+ log_command,
20
+ track_database_operation,
21
+ )
22
+ from roadmap.core.domain import Status
23
+
24
+ console = get_console()
25
+
26
+
27
+ @click.command("progress")
28
+ @click.argument("issue_id")
29
+ @click.argument("percentage", type=float)
30
+ @click.pass_context
31
+ @log_command("issue_progress", entity_type="issue", track_duration=True)
32
+ @require_initialized
33
+ def update_progress(ctx: click.Context, issue_id: str, percentage: float):
34
+ """Update the progress percentage for an issue (0-100).
35
+
36
+ Syntactic sugar for: roadmap issue update <ID> --progress <PERCENT>
37
+ """
38
+ core = ctx.obj["core"]
39
+
40
+ if not 0 <= percentage <= 100:
41
+ console.print(
42
+ "❌ Progress percentage must be between 0 and 100", style="bold red"
43
+ )
44
+ return
45
+
46
+ try:
47
+ # Get the issue
48
+ issue = ensure_entity_exists(core, "issue", issue_id)
49
+
50
+ # Update progress via core.update_issue
51
+ with track_database_operation("update", "issue", entity_id=issue_id):
52
+ updated = core.issues.update(issue_id, progress_percentage=percentage)
53
+
54
+ if updated:
55
+ # Build extra details for display
56
+ extra_details = {"Progress": f"{percentage:.0f}%"}
57
+
58
+ # Auto-update status based on progress
59
+ if percentage == 0:
60
+ extra_details["Note"] = "Resetting to todo"
61
+ elif percentage == 100:
62
+ extra_details["Tip"] = "roadmap issue close to mark complete"
63
+ else:
64
+ if issue.status == Status.TODO:
65
+ core.issues.update(issue_id, status=Status.IN_PROGRESS)
66
+ extra_details["Status"] = "Auto-updated to In Progress"
67
+
68
+ # Display success with formatter
69
+ lines = format_operation_success(
70
+ emoji="📊",
71
+ action="Updated progress",
72
+ entity_title=issue.title,
73
+ entity_id=issue_id,
74
+ extra_details=extra_details,
75
+ )
76
+ for line in lines:
77
+ console.print(line, style="bold green" if "Updated" in line else "cyan")
78
+ else:
79
+ lines = format_operation_failure(
80
+ action="update progress",
81
+ entity_id=issue_id,
82
+ error="No changes made",
83
+ )
84
+ for line in lines:
85
+ console.print(line, style="bold red")
86
+
87
+ except Exception as e:
88
+ handle_cli_error(
89
+ error=e,
90
+ operation="update_issue_progress",
91
+ entity_type="issue",
92
+ entity_id=issue_id,
93
+ context={"percentage": percentage},
94
+ fatal=True,
95
+ )
96
+ lines = format_operation_failure(
97
+ action="update progress",
98
+ entity_id=issue_id,
99
+ error=str(e),
100
+ )
101
+ for line in lines:
102
+ console.print(line, style="bold red")
@@ -0,0 +1,96 @@
1
+ """Restore issue command - move archived issues back to active."""
2
+
3
+ import click
4
+
5
+ from roadmap.adapters.cli.cli_command_helpers import require_initialized
6
+ from roadmap.adapters.cli.issues.restore_class import IssueRestore
7
+ from roadmap.common.console import get_console
8
+ from roadmap.common.logging import (
9
+ log_command,
10
+ verbose_output,
11
+ )
12
+
13
+
14
+ @click.command()
15
+ @click.argument("issue_id", required=False)
16
+ @click.option(
17
+ "--all",
18
+ is_flag=True,
19
+ help="Restore all archived issues",
20
+ )
21
+ @click.option(
22
+ "--status",
23
+ type=click.Choice(["todo", "in-progress", "blocked", "review", "closed"]),
24
+ help="Set status when restoring (default: keep current status)",
25
+ )
26
+ @click.option(
27
+ "--dry-run",
28
+ is_flag=True,
29
+ help="Preview what would be restored without actually doing it",
30
+ )
31
+ @click.option(
32
+ "--force",
33
+ is_flag=True,
34
+ help="Skip confirmation prompt",
35
+ )
36
+ @click.option(
37
+ "--verbose",
38
+ "-v",
39
+ is_flag=True,
40
+ help="Show detailed debug information",
41
+ )
42
+ @click.pass_context
43
+ @verbose_output
44
+ @log_command("issue_restore", entity_type="issue", track_duration=True)
45
+ @require_initialized
46
+ def restore_issue(
47
+ ctx: click.Context,
48
+ issue_id: str | None,
49
+ all: bool,
50
+ status: str | None,
51
+ dry_run: bool,
52
+ force: bool,
53
+ verbose: bool, # noqa: F841
54
+ ):
55
+ """Restore an archived issue back to active issues.
56
+
57
+ This moves an issue from .roadmap/archive/issues/ back to
58
+ .roadmap/issues/, making it active again. Optionally update
59
+ the status when restoring.
60
+
61
+ Examples:
62
+ roadmap issue restore 8a00a17e
63
+ roadmap issue restore 8a00a17e --status todo
64
+ roadmap issue restore --all
65
+ roadmap issue restore 8a00a17e --dry-run
66
+ """
67
+ core = ctx.obj["core"]
68
+ console = get_console()
69
+
70
+ restore = IssueRestore(core, console)
71
+
72
+ if not issue_id and not all:
73
+ console.print(
74
+ "❌ Error: Specify an issue ID or use --all",
75
+ style="bold red",
76
+ )
77
+ ctx.exit(1)
78
+
79
+ if issue_id and all:
80
+ console.print(
81
+ "❌ Error: Cannot specify issue ID with --all",
82
+ style="bold red",
83
+ )
84
+ ctx.exit(1)
85
+
86
+ try:
87
+ restore.execute(
88
+ entity_id=issue_id,
89
+ all=all,
90
+ status=status,
91
+ dry_run=dry_run,
92
+ force=force,
93
+ )
94
+ except Exception as e:
95
+ console.print(f"❌ Restore operation failed: {str(e)}", style="bold red")
96
+ ctx.exit(1)
@@ -0,0 +1,57 @@
1
+ """IssueRestore command implementation using base class."""
2
+
3
+ from pathlib import Path
4
+
5
+ from roadmap.adapters.cli.crud import BaseRestore, EntityType
6
+
7
+
8
+ class IssueRestore(BaseRestore):
9
+ """Restore issue command implementation."""
10
+
11
+ entity_type = EntityType.ISSUE
12
+
13
+ def get_archived_files_to_restore(
14
+ self, entity_id: str | None = None, **filters
15
+ ) -> list[Path]:
16
+ """Get archived issue files to restore.
17
+
18
+ Args:
19
+ entity_id: Specific issue ID to restore
20
+ **filters: Additional filter criteria
21
+
22
+ Returns:
23
+ List of archived file paths
24
+ """
25
+ from roadmap.adapters.cli.crud.crud_helpers import get_archive_dir
26
+
27
+ archive_dir = get_archive_dir(self.entity_type)
28
+
29
+ if not archive_dir.exists():
30
+ return []
31
+
32
+ if entity_id:
33
+ # Find specific issue file by ID prefix
34
+ matching = list(archive_dir.rglob(f"{entity_id[:8]}*.md"))
35
+ return matching if matching else []
36
+ else:
37
+ # Return all archived issues
38
+ return list(archive_dir.rglob("*.md"))
39
+
40
+ def post_restore_hook(self, restored_files: list[Path], **kwargs) -> None:
41
+ """Handle post-restore state updates.
42
+
43
+ Args:
44
+ restored_files: Files that were restored
45
+ **kwargs: Additional arguments
46
+ """
47
+ # Mark issues as restored in database
48
+ for file_path in restored_files:
49
+ try:
50
+ # Extract issue ID from filename
51
+ issue_id = file_path.stem.split("-")[0]
52
+ self.core.db.mark_issue_archived(issue_id, archived=False)
53
+ except Exception as e:
54
+ self.console.print(
55
+ f"⚠️ Warning: Failed to update restoration status for {file_path.name}: {e}",
56
+ style="yellow",
57
+ )
@@ -0,0 +1,165 @@
1
+ """Start issue command - thin wrapper around update.
2
+
3
+ This command is syntactic sugar for: roadmap issue update <ID> --status in-progress
4
+ with optional Git branch creation.
5
+ """
6
+
7
+ import click
8
+
9
+ from roadmap.adapters.cli.cli_command_helpers import require_initialized
10
+ from roadmap.adapters.cli.cli_error_handlers import handle_cli_error
11
+ from roadmap.common.console import get_console
12
+ from roadmap.common.formatters.text.operations import (
13
+ format_operation_failure,
14
+ format_operation_success,
15
+ )
16
+ from roadmap.common.logging import (
17
+ log_command,
18
+ track_database_operation,
19
+ )
20
+ from roadmap.core.services import StartIssueService
21
+
22
+ console = get_console()
23
+
24
+
25
+ @click.command("start")
26
+ @click.argument("issue_id")
27
+ @click.option("--date", help="Start date (YYYY-MM-DD HH:MM, defaults to now)")
28
+ @click.option(
29
+ "--git-branch/--no-git-branch",
30
+ default=False,
31
+ help="Create a Git branch for this issue when starting",
32
+ )
33
+ @click.option(
34
+ "--checkout/--no-checkout",
35
+ default=True,
36
+ help="Checkout the created branch (when --git-branch is used)",
37
+ )
38
+ @click.option("--branch-name", default=None, help="Override suggested branch name")
39
+ @click.option(
40
+ "--force", is_flag=True, help="Force branch creation even if working tree is dirty"
41
+ )
42
+ @click.pass_context
43
+ @log_command("issue_start", entity_type="issue", track_duration=True)
44
+ @require_initialized
45
+ def start_issue(
46
+ ctx: click.Context,
47
+ issue_id: str,
48
+ date: str,
49
+ git_branch: bool,
50
+ checkout: bool,
51
+ branch_name: str,
52
+ force: bool,
53
+ ):
54
+ """Start work on an issue (sets status to in-progress and records start date).
55
+
56
+ Syntactic sugar for: roadmap issue update <ID> --status in-progress
57
+ """
58
+ core = ctx.obj["core"]
59
+
60
+ try:
61
+ # Create start issue service
62
+ service = StartIssueService(core)
63
+
64
+ # Parse start date
65
+ try:
66
+ start_date = service.parse_start_date(date)
67
+ except ValueError:
68
+ console.print(
69
+ "❌ Invalid date format. Use YYYY-MM-DD or YYYY-MM-DD HH:MM",
70
+ style="bold red",
71
+ )
72
+ return
73
+
74
+ # Get the issue
75
+ issue = core.issues.get(issue_id)
76
+ if not issue:
77
+ console.print(f"❌ Issue not found: {issue_id}", style="bold red")
78
+ return
79
+
80
+ # Start work on issue via core.update_issue
81
+ with track_database_operation("update", "issue", entity_id=issue_id):
82
+ success = service.start_work(issue_id, start_date)
83
+
84
+ if success:
85
+ # Build extra details
86
+ extra_details = {
87
+ "Status": "🚀 In Progress",
88
+ "Started": start_date.strftime("%Y-%m-%d %H:%M"),
89
+ }
90
+
91
+ # Display success with formatter
92
+ lines = format_operation_success(
93
+ emoji="🚀",
94
+ action="Started",
95
+ entity_title=issue.title,
96
+ entity_id=issue_id,
97
+ extra_details=extra_details,
98
+ )
99
+ for line in lines:
100
+ console.print(line, style="bold green" if "Started" in line else "cyan")
101
+
102
+ # Handle git branch creation
103
+ if service.should_create_branch(git_branch):
104
+ _handle_git_branch_creation(
105
+ core, service, issue, branch_name, checkout, force
106
+ )
107
+ else:
108
+ lines = format_operation_failure(
109
+ action="start",
110
+ entity_id=issue_id,
111
+ error="Failed to update status",
112
+ )
113
+ for line in lines:
114
+ console.print(line, style="bold red")
115
+
116
+ except Exception as e:
117
+ handle_cli_error(
118
+ error=e,
119
+ operation="start_issue",
120
+ entity_type="issue",
121
+ entity_id=issue_id,
122
+ context={
123
+ "git_branch": git_branch,
124
+ "checkout": checkout,
125
+ "branch_name": branch_name,
126
+ },
127
+ fatal=True,
128
+ )
129
+ lines = format_operation_failure(
130
+ action="start",
131
+ entity_id=issue_id,
132
+ error=str(e),
133
+ )
134
+ for line in lines:
135
+ console.print(line, style="bold red")
136
+
137
+
138
+ def _handle_git_branch_creation(core, service, issue, branch_name, checkout, force):
139
+ """Handle git branch creation for started issue."""
140
+ try:
141
+ if hasattr(core, "git") and core.git.is_git_repository():
142
+ success, resolved_branch_name = service.core.git.create_branch_for_issue(
143
+ issue, checkout=checkout, force=force
144
+ )
145
+ if success and resolved_branch_name:
146
+ service.display_branch_created(resolved_branch_name, checkout)
147
+ else:
148
+ service.display_branch_warning()
149
+ else:
150
+ console.print(
151
+ "⚠️ Not in a Git repository, skipping branch creation",
152
+ style="yellow",
153
+ )
154
+ except Exception as e:
155
+ handle_cli_error(
156
+ error=e,
157
+ operation="create_git_branch",
158
+ entity_type="issue",
159
+ entity_id=issue.id,
160
+ context={"branch_name": branch_name},
161
+ fatal=False,
162
+ )
163
+ console.print(
164
+ f"⚠️ Git branch creation skipped due to error: {e}", style="yellow"
165
+ )