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,157 @@
1
+ """View project command."""
2
+
3
+ import click
4
+
5
+ from roadmap.adapters.cli.cli_command_helpers import require_initialized
6
+ from roadmap.adapters.cli.mappers import ProjectMapper
7
+ from roadmap.adapters.cli.presentation.project_presenter import ProjectPresenter
8
+ from roadmap.common.console import get_console
9
+
10
+
11
+ def _extract_description_and_objectives(content):
12
+ """Extract description and objectives from project content."""
13
+ if not content:
14
+ return None, None
15
+
16
+ content_lines = content.split("\n")
17
+ description_lines = []
18
+ objectives_lines = []
19
+ in_objectives = False
20
+
21
+ for line in content_lines:
22
+ if "## Objectives" in line or "## objectives" in line.lower():
23
+ in_objectives = True
24
+ continue
25
+ elif in_objectives and line.startswith("## "):
26
+ in_objectives = False
27
+
28
+ if in_objectives:
29
+ objectives_lines.append(line)
30
+ elif not line.startswith("## "):
31
+ description_lines.append(line)
32
+
33
+ description = "\n".join(description_lines).strip() or None
34
+ objectives = "\n".join(objectives_lines).strip() or None
35
+
36
+ return description, objectives
37
+
38
+
39
+ def _get_project_or_exit(ctx: click.Context, project_id: str):
40
+ """Fetch project by ID or exit with a user-facing error message."""
41
+ core = ctx.obj["core"]
42
+ project = core.projects.get(project_id)
43
+ if project:
44
+ return project
45
+
46
+ get_console().print(f"❌ Project '{project_id}' not found.", style="bold red")
47
+ get_console().print(
48
+ "\n💡 Tip: Use 'roadmap project list' to see all available projects.",
49
+ style="dim",
50
+ )
51
+ ctx.exit(1)
52
+
53
+
54
+ def _build_project_milestone_data(core, project) -> tuple[list | None, dict | None]:
55
+ """Build milestone list and progress map for a project."""
56
+ if not project.milestones:
57
+ return None, None
58
+
59
+ all_milestones = core.milestones.list()
60
+ milestones = [m for m in all_milestones if m.name in project.milestones]
61
+ milestone_progress = {
62
+ milestone.name: core.milestones.get_progress(milestone.name)
63
+ for milestone in milestones
64
+ }
65
+ return milestones, milestone_progress
66
+
67
+
68
+ def _build_effort_data(project) -> dict[str, float | int | None] | None:
69
+ """Build effort payload for presenter when estimate/actual values exist."""
70
+ if not (project.estimated_hours or project.actual_hours):
71
+ return None
72
+ return {
73
+ "estimated": project.estimated_hours,
74
+ "actual": project.actual_hours,
75
+ }
76
+
77
+
78
+ def _build_comments_text(project) -> str | None:
79
+ """Build formatted comments text with threaded replies for display."""
80
+ if not project.comments:
81
+ return None
82
+
83
+ from roadmap.core.services.comment.comment_service import CommentService
84
+
85
+ threads = CommentService.build_comment_threads(project.comments)
86
+ chunks: list[str] = []
87
+
88
+ top_level_ids = sorted([key for key in threads.keys() if key is not None])
89
+ for top_level_id in top_level_ids:
90
+ for comment in threads.get(top_level_id, []):
91
+ chunks.append(CommentService.format_comment_for_display(comment, indent=0))
92
+ for reply in threads.get(comment.id, []):
93
+ chunks.append(
94
+ CommentService.format_comment_for_display(reply, indent=1)
95
+ )
96
+ chunks.append("")
97
+
98
+ return "\n".join(chunks).rstrip() if chunks else None
99
+
100
+
101
+ def _render_objectives_panel(objectives: str | None) -> None:
102
+ """Render objectives markdown panel when objectives are available."""
103
+ if not objectives:
104
+ return
105
+
106
+ from rich.markdown import Markdown
107
+ from rich.panel import Panel
108
+
109
+ get_console().print(
110
+ Panel(Markdown(objectives), title="✅ Objectives", border_style="green")
111
+ )
112
+
113
+
114
+ @click.command("view")
115
+ @click.argument("project_id")
116
+ @click.pass_context
117
+ @require_initialized
118
+ def view_project(ctx: click.Context, project_id: str):
119
+ """Display detailed information about a specific project.
120
+
121
+ Shows complete project details including metadata, milestones,
122
+ objectives, and description in a formatted view.
123
+
124
+ Example:
125
+ roadmap project view abc123def
126
+ """
127
+ core = ctx.obj["core"]
128
+ project = _get_project_or_exit(ctx, project_id)
129
+
130
+ # Convert project to DTO
131
+ project_dto = ProjectMapper.domain_to_dto(project)
132
+
133
+ # Get milestones for display
134
+ milestones, milestone_progress = _build_project_milestone_data(core, project)
135
+
136
+ # Build effort data
137
+ effort_data = _build_effort_data(project)
138
+
139
+ # Extract description and objectives
140
+ description, objectives = _extract_description_and_objectives(project.content)
141
+ description_content = description
142
+
143
+ # Prepare comments if any
144
+ comments_text = _build_comments_text(project)
145
+
146
+ # Render using presenter
147
+ presenter = ProjectPresenter()
148
+ presenter.render(
149
+ project_dto,
150
+ milestones=milestones,
151
+ milestone_progress=milestone_progress,
152
+ description_content=description_content,
153
+ comments_text=comments_text,
154
+ effort_data=effort_data,
155
+ )
156
+
157
+ _render_objectives_panel(objectives)
@@ -0,0 +1 @@
1
+ """CLI services package."""
@@ -0,0 +1,313 @@
1
+ """Daily summary service for the 'today' command.
2
+
3
+ Provides business logic for generating daily workflow summaries,
4
+ including user identification, milestone selection, issue categorization,
5
+ and data aggregation for display.
6
+ """
7
+
8
+ import os
9
+ from datetime import UTC, datetime
10
+ from typing import Any
11
+
12
+ from roadmap.common.constants import MilestoneStatus, Status
13
+ from roadmap.common.logging import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class DailySummaryService:
19
+ """Service for generating daily workflow summaries.
20
+
21
+ Handles all business logic for the 'today' command, including:
22
+ - User identity resolution from config or environment
23
+ - Upcoming milestone selection
24
+ - Issue categorization and filtering
25
+ - Data aggregation for display
26
+ """
27
+
28
+ def __init__(self, core):
29
+ """Initialize daily summary service.
30
+
31
+ Args:
32
+ core: RoadmapCore instance for accessing data
33
+ """
34
+ self.core = core
35
+
36
+ def get_current_user(self) -> str | None:
37
+ """Get current user from config or environment.
38
+
39
+ Returns:
40
+ Current user name or None if not found
41
+ """
42
+ # Get user identity from config (single source of truth)
43
+ current_user = self.core.team.get_current_user()
44
+
45
+ if not current_user:
46
+ # Fallback to environment for testing
47
+ current_user = os.getenv("ROADMAP_USER")
48
+
49
+ return current_user
50
+
51
+ def get_upcoming_milestone(self) -> Any | None:
52
+ """Get the next upcoming milestone.
53
+
54
+ Filters open milestones and returns the one with the earliest due date.
55
+
56
+ Returns:
57
+ Milestone object or None if no open milestones exist
58
+ """
59
+ milestones = self.core.milestones.list()
60
+
61
+ # Filter open milestones and sort by due date
62
+ open_milestones = [m for m in milestones if m.status == MilestoneStatus.OPEN]
63
+
64
+ if not open_milestones:
65
+ return None
66
+
67
+ # Sort by due date (None dates last), get the first with a due date
68
+ sorted_milestones = sorted(
69
+ open_milestones,
70
+ key=lambda m: (m.due_date is None, m.due_date or datetime.max),
71
+ )
72
+
73
+ return sorted_milestones[0] if sorted_milestones else None
74
+
75
+ def _get_in_progress_issues(self, issues: list) -> list:
76
+ """Get issues currently in progress.
77
+
78
+ Args:
79
+ issues: List of issues to filter
80
+
81
+ Returns:
82
+ List of in-progress issues
83
+ """
84
+ return [i for i in issues if i.status == Status.IN_PROGRESS]
85
+
86
+ def _get_overdue_issues(self, issues: list) -> list:
87
+ """Get overdue issues that haven't been closed.
88
+
89
+ Args:
90
+ issues: List of issues to filter
91
+
92
+ Returns:
93
+ List of overdue issues
94
+ """
95
+ overdue = []
96
+ now = datetime.now(UTC)
97
+ for i in issues:
98
+ if not i.due_date or i.status == Status.CLOSED:
99
+ continue
100
+
101
+ due = i.due_date
102
+ if isinstance(due, datetime):
103
+ if due.tzinfo:
104
+ due_aware = due.astimezone(UTC)
105
+ else:
106
+ due_aware = due.replace(tzinfo=UTC)
107
+ else:
108
+ due_aware = datetime.fromisoformat(str(due)).replace(tzinfo=UTC)
109
+
110
+ if due_aware < now:
111
+ overdue.append(i)
112
+
113
+ return overdue
114
+
115
+ def _get_blocked_issues(self, issues: list) -> list:
116
+ """Get blocked issues.
117
+
118
+ Args:
119
+ issues: List of issues to filter
120
+
121
+ Returns:
122
+ List of blocked issues
123
+ """
124
+ return [i for i in issues if i.status == Status.BLOCKED]
125
+
126
+ def _get_high_priority_todos(self, issues: list) -> list:
127
+ """Get high-priority TODO issues (top 3).
128
+
129
+ Args:
130
+ issues: List of issues to filter
131
+
132
+ Returns:
133
+ List of up to 3 high-priority TODO issues
134
+ """
135
+ candidates = [
136
+ i
137
+ for i in issues
138
+ if i.status == Status.TODO and i.priority.value in ["critical", "high"]
139
+ ]
140
+
141
+ if not candidates:
142
+ return []
143
+
144
+ # Prioritize issues that unblock the largest downstream dependency chain.
145
+ # This helps "today" surface critical path blockers before standalone work.
146
+ active_issues = [i for i in issues if i.status != Status.CLOSED]
147
+ dependents_map: dict[str, list[str]] = {}
148
+ for issue in active_issues:
149
+ for dep_id in issue.depends_on or []:
150
+ dependents_map.setdefault(dep_id, []).append(issue.id)
151
+
152
+ depth_cache: dict[str, int] = {}
153
+
154
+ def dependency_depth(issue_id: str, visiting: set[str] | None = None) -> int:
155
+ if issue_id in depth_cache:
156
+ return depth_cache[issue_id]
157
+
158
+ visiting = visiting or set()
159
+ if issue_id in visiting:
160
+ # Cycle guard: don't recurse indefinitely; treat as no extra depth.
161
+ return 0
162
+
163
+ visiting.add(issue_id)
164
+ children = dependents_map.get(issue_id, [])
165
+ if not children:
166
+ depth = 0
167
+ else:
168
+ depth = 1 + max(dependency_depth(child, visiting) for child in children)
169
+ visiting.remove(issue_id)
170
+
171
+ depth_cache[issue_id] = depth
172
+ return depth
173
+
174
+ def sort_key(issue):
175
+ depth = dependency_depth(issue.id)
176
+ direct_dependents = len(dependents_map.get(issue.id, []))
177
+ critical_rank = 0 if issue.priority.value == "critical" else 1
178
+ return (-depth, -direct_dependents, critical_rank, issue.id)
179
+
180
+ return sorted(candidates, key=sort_key)[:3]
181
+
182
+ def _get_completed_today_issues(self, issues: list) -> list:
183
+ """Get issues closed today.
184
+
185
+ Args:
186
+ issues: List of issues to filter
187
+
188
+ Returns:
189
+ List of issues closed today
190
+ """
191
+ today = datetime.now(UTC).date()
192
+ return [
193
+ i
194
+ for i in issues
195
+ if i.status == Status.CLOSED
196
+ and i.actual_end_date
197
+ and i.actual_end_date.date() == today
198
+ ]
199
+
200
+ def categorize_issues(self, issues: list, current_user: str) -> dict[str, list]:
201
+ """Categorize issues by status and urgency.
202
+
203
+ Args:
204
+ issues: List of issues to categorize
205
+ current_user: Current user name for filtering
206
+
207
+ Returns:
208
+ Dictionary with keys: in_progress, overdue, blocked, todo_high_priority, completed_today
209
+ """
210
+ return {
211
+ "in_progress": self._get_in_progress_issues(issues),
212
+ "overdue": self._get_overdue_issues(issues),
213
+ "blocked": self._get_blocked_issues(issues),
214
+ "todo_high_priority": self._get_high_priority_todos(issues),
215
+ "completed_today": self._get_completed_today_issues(issues),
216
+ }
217
+
218
+ def get_daily_summary_data(self) -> dict[str, Any]:
219
+ """Get complete daily summary data.
220
+
221
+ Validates user and milestone, filters issues, categorizes them,
222
+ and returns all data needed for display.
223
+
224
+ Returns:
225
+ Dictionary with keys: current_user, milestone, issues (dict of categories)
226
+
227
+ Raises:
228
+ ValueError: If user not found or no upcoming milestones
229
+ """
230
+ # Get user identity
231
+ current_user = self.get_current_user()
232
+ if not current_user:
233
+ raise ValueError(
234
+ "No user configured. Initialize with 'roadmap init' or set ROADMAP_USER."
235
+ )
236
+
237
+ logger.debug("Current user", user=current_user)
238
+
239
+ # Get upcoming milestone
240
+ upcoming_milestone = self.get_upcoming_milestone()
241
+ if not upcoming_milestone:
242
+ raise ValueError("No upcoming milestones found.")
243
+
244
+ logger.debug("Upcoming milestone", milestone=upcoming_milestone.name)
245
+
246
+ # Get all issues
247
+ all_issues = self.core.issues.list()
248
+
249
+ # Filter: assigned to current user AND in upcoming milestone
250
+ my_milestone_issues = [
251
+ i
252
+ for i in all_issues
253
+ if i.assignee == current_user and i.milestone == upcoming_milestone.name
254
+ ]
255
+
256
+ if not my_milestone_issues:
257
+ logger.info(
258
+ "No issues assigned to user in upcoming milestone", user=current_user
259
+ )
260
+ return {
261
+ "current_user": current_user,
262
+ "milestone": upcoming_milestone,
263
+ "issues": {
264
+ "in_progress": [],
265
+ "overdue": [],
266
+ "blocked": [],
267
+ "todo_high_priority": [],
268
+ "completed_today": [],
269
+ },
270
+ "has_issues": False,
271
+ }
272
+
273
+ # Categorize issues
274
+ categorized = self.categorize_issues(my_milestone_issues, current_user)
275
+
276
+ logger.info(
277
+ "Daily summary data prepared",
278
+ user=current_user,
279
+ milestone=upcoming_milestone.name,
280
+ in_progress=len(categorized["in_progress"]),
281
+ overdue=len(categorized["overdue"]),
282
+ blocked=len(categorized["blocked"]),
283
+ todo_high_priority=len(categorized["todo_high_priority"]),
284
+ completed_today=len(categorized["completed_today"]),
285
+ )
286
+
287
+ return {
288
+ "current_user": current_user,
289
+ "milestone": upcoming_milestone,
290
+ "issues": categorized,
291
+ "has_issues": True,
292
+ }
293
+
294
+ def get_next_action_suggestion(self, data: dict[str, Any]) -> str | None:
295
+ """Get helpful suggestion for next action based on data.
296
+
297
+ Args:
298
+ data: Dictionary from get_daily_summary_data()
299
+
300
+ Returns:
301
+ Suggestion string or None if no action recommended
302
+ """
303
+ issues = data["issues"]
304
+
305
+ if not issues["in_progress"] and issues["todo_high_priority"]:
306
+ issue = issues["todo_high_priority"][0]
307
+ return f"Start work on an issue with: roadmap issue start {issue.id}"
308
+
309
+ if issues["overdue"]:
310
+ issue = issues["overdue"][0]
311
+ return f"View overdue issue details with: roadmap issue view {issue.id}"
312
+
313
+ return None