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,78 @@
1
+ """GitHub setup validation utilities."""
2
+
3
+ from roadmap.common.console import get_console
4
+
5
+ console = get_console()
6
+
7
+
8
+ class GitHubSetupValidator:
9
+ """Validates GitHub connectivity and permissions during setup."""
10
+
11
+ def __init__(self, github_client): # type: ignore
12
+ """Initialize GitHubSetupValidator.
13
+
14
+ Args:
15
+ github_client: GitHub client instance.
16
+ """
17
+ self.client = github_client
18
+
19
+ def validate_authentication(self) -> tuple[bool, str | None]:
20
+ """Validate user authentication.
21
+
22
+ Returns:
23
+ Tuple of (success, username or error)
24
+ """
25
+ try:
26
+ user_response = self.client._make_request("GET", "/user")
27
+ user_info = user_response.json()
28
+ username = user_info.get("login", "unknown")
29
+ console.print(f"✅ Authenticated as: {username}")
30
+ return True, username
31
+ except Exception as e:
32
+ console.print(f"❌ Authentication failed: {e}", style="red")
33
+ return False, str(e)
34
+
35
+ def validate_repository_access(self, github_repo: str) -> tuple[bool, dict | None]:
36
+ """Validate repository access and permissions.
37
+
38
+ Returns:
39
+ Tuple of (success, repo_info or error_message)
40
+ """
41
+ try:
42
+ owner, repo = github_repo.split("/")
43
+ self.client.set_repository(owner, repo)
44
+ repo_info = self.client.test_repository_access()
45
+
46
+ repo_name = repo_info.get("full_name", github_repo)
47
+ console.print(f"✅ Repository access: {repo_name}")
48
+
49
+ # Check permissions
50
+ permissions = repo_info.get("permissions", {})
51
+ if permissions.get("admin") or permissions.get("push"):
52
+ console.print("✅ Write access: Available")
53
+ elif permissions.get("pull"):
54
+ console.print(
55
+ "⚠️ Read-only access: Limited sync capabilities", style="yellow"
56
+ )
57
+ else:
58
+ console.print("❌ No repository access detected", style="red")
59
+
60
+ return True, repo_info
61
+ except Exception as e:
62
+ console.print(f"⚠️ Repository validation warning: {e}", style="yellow")
63
+ return False, {"error": str(e)}
64
+
65
+ def test_api_access(self, github_repo: str) -> bool:
66
+ """Test basic API calls."""
67
+ try:
68
+ issues_response = self.client._make_request(
69
+ "GET",
70
+ f"/repos/{github_repo}/issues",
71
+ params={"state": "open", "per_page": 1},
72
+ )
73
+ issues = issues_response.json()
74
+ console.print(f"✅ API test successful ({len(issues)} issue(s) found)")
75
+ return True
76
+ except Exception as e:
77
+ console.print(f"⚠️ API test warning: {e}", style="yellow")
78
+ return False
@@ -0,0 +1,113 @@
1
+ """Structured logging for roadmap CLI application."""
2
+
3
+ import structlog # noqa: F401
4
+
5
+ from roadmap.common.logging.correlation import (
6
+ add_correlation_id,
7
+ clear_correlation_id,
8
+ correlation_id_var,
9
+ get_correlation_id,
10
+ set_correlation_id,
11
+ )
12
+ from roadmap.common.logging.decorators import (
13
+ get_current_user,
14
+ log_audit_event,
15
+ log_command,
16
+ log_operation_duration,
17
+ verbose_output,
18
+ )
19
+ from roadmap.common.logging.error_logging import (
20
+ ErrorClassification,
21
+ classify_error,
22
+ is_error_recoverable,
23
+ log_database_error,
24
+ log_error_with_context,
25
+ log_external_service_error,
26
+ log_validation_error,
27
+ suggest_recovery,
28
+ )
29
+ from roadmap.common.logging.formatters import (
30
+ SENSITIVE_KEYS,
31
+ StructuredFormatter,
32
+ include_structured_fields_in_message,
33
+ scrub_sensitive_data,
34
+ )
35
+ from roadmap.common.logging.loggers import (
36
+ get_application_logger,
37
+ get_domain_logger,
38
+ get_infrastructure_logger,
39
+ get_logger,
40
+ get_presentation_logger,
41
+ get_security_logger,
42
+ )
43
+ from roadmap.common.logging.performance_tracking import (
44
+ OperationTimer,
45
+ track_database_operation,
46
+ track_file_operation,
47
+ track_operation_time,
48
+ track_sync_operation,
49
+ )
50
+ from roadmap.common.logging.utils import (
51
+ configure_for_testing,
52
+ get_stack_trace,
53
+ log_operation,
54
+ log_operation_timing,
55
+ setup_logging,
56
+ should_sample,
57
+ )
58
+
59
+ __all__ = [
60
+ # Formatters and scrubbing
61
+ "StructuredFormatter",
62
+ "scrub_sensitive_data",
63
+ "include_structured_fields_in_message",
64
+ "SENSITIVE_KEYS",
65
+ # Correlation ID
66
+ "correlation_id_var",
67
+ "set_correlation_id",
68
+ "get_correlation_id",
69
+ "clear_correlation_id",
70
+ "add_correlation_id",
71
+ # Logger factories
72
+ "get_logger",
73
+ "get_domain_logger",
74
+ "get_application_logger",
75
+ "get_infrastructure_logger",
76
+ "get_presentation_logger",
77
+ "get_security_logger",
78
+ # Setup and utilities
79
+ "setup_logging",
80
+ "get_stack_trace",
81
+ "log_operation_timing",
82
+ "log_operation",
83
+ "should_sample",
84
+ "configure_for_testing",
85
+ # Decorators
86
+ "log_command",
87
+ "verbose_output",
88
+ "get_current_user",
89
+ "log_audit_event",
90
+ "log_operation_duration",
91
+ # Error logging
92
+ "ErrorClassification",
93
+ "classify_error",
94
+ "is_error_recoverable",
95
+ "log_database_error",
96
+ "log_error_with_context",
97
+ "log_external_service_error",
98
+ "log_validation_error",
99
+ "suggest_recovery",
100
+ # Performance tracking
101
+ "OperationTimer",
102
+ "track_database_operation",
103
+ "track_file_operation",
104
+ "track_operation_time",
105
+ "track_sync_operation",
106
+ ]
107
+
108
+ # Initialize logging at module load time
109
+ # This is the single source of truth for production logging configuration
110
+ setup_logging(log_level="INFO", debug_mode=False, log_to_file=True)
111
+
112
+ # Get default logger instance
113
+ logger = get_logger("roadmap")
@@ -0,0 +1,5 @@
1
+ """Audit logging utilities for tracking user actions and data changes.
2
+
3
+ Placeholder for future audit logging implementation.
4
+ Currently audit logging functionality is not active in v1.0.
5
+ """
@@ -0,0 +1,45 @@
1
+ """Correlation ID tracking for distributed tracing across operations."""
2
+
3
+ import contextvars
4
+ import uuid
5
+
6
+ # Context variable for correlation ID tracking across async operations
7
+ correlation_id_var: contextvars.ContextVar[str | None] = contextvars.ContextVar(
8
+ "correlation_id", default=None
9
+ )
10
+
11
+
12
+ def add_correlation_id(logger, _method_name, event_dict):
13
+ """Structlog processor to add correlation ID to all log entries."""
14
+ cid = correlation_id_var.get()
15
+ if cid:
16
+ event_dict["correlation_id"] = cid
17
+ return event_dict
18
+
19
+
20
+ def set_correlation_id(correlation_id: str | None = None) -> str:
21
+ """Set correlation ID for current context.
22
+
23
+ Args:
24
+ correlation_id: Optional correlation ID (generates UUID if None)
25
+
26
+ Returns:
27
+ The correlation ID that was set
28
+ """
29
+ cid = correlation_id or str(uuid.uuid4())
30
+ correlation_id_var.set(cid)
31
+ return cid
32
+
33
+
34
+ def get_correlation_id() -> str | None:
35
+ """Get correlation ID from current context.
36
+
37
+ Returns:
38
+ Current correlation ID or None
39
+ """
40
+ return correlation_id_var.get()
41
+
42
+
43
+ def clear_correlation_id() -> None:
44
+ """Clear correlation ID from current context."""
45
+ correlation_id_var.set(None)
@@ -0,0 +1,267 @@
1
+ """CLI command logging decorators for audit trail and observability.
2
+
3
+ Provides decorators to automatically log CLI command execution, timing,
4
+ user actions, and outcomes for comprehensive audit trail and debugging.
5
+ """
6
+
7
+ import functools
8
+ import os
9
+ import sys
10
+ import time
11
+ from collections.abc import Callable
12
+ from typing import Any
13
+
14
+ import click # type: ignore[import-not-found]
15
+
16
+ from roadmap.common.logging.loggers import get_logger
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ def get_current_user() -> str:
22
+ """Get current user from environment."""
23
+ user = os.environ.get("USER") or os.environ.get("USERNAME")
24
+ return user if user else "unknown"
25
+
26
+
27
+ def log_command(
28
+ command_name: str,
29
+ entity_type: str | None = None,
30
+ track_duration: bool = True,
31
+ log_args: bool = False,
32
+ ) -> Callable:
33
+ """Log CLI command execution with audit trail.
34
+
35
+ Args:
36
+ command_name: Name of the command (e.g., "issue_create")
37
+ entity_type: Type of entity affected (e.g., "issue", "milestone")
38
+ track_duration: Whether to track and log command execution time
39
+ log_args: Whether to log command arguments (use with caution for sensitive data)
40
+
41
+ Example:
42
+ @log_command("issue_create", entity_type="issue")
43
+ @click.command()
44
+ def create_issue(title, priority):
45
+ ...
46
+ """
47
+
48
+ def decorator(func: Callable) -> Callable:
49
+ @functools.wraps(func)
50
+ def wrapper(*args, **kwargs) -> Any:
51
+ user = get_current_user()
52
+ start_time = time.time()
53
+
54
+ # Log command initiation
55
+ logger.info(
56
+ "command_initiated",
57
+ command_name=command_name,
58
+ user=user,
59
+ entity_type=entity_type,
60
+ args_logged=log_args,
61
+ )
62
+
63
+ if log_args:
64
+ logger.debug(
65
+ "command_received_with_arguments",
66
+ command=command_name,
67
+ kwargs=kwargs,
68
+ )
69
+
70
+ try:
71
+ result = func(*args, **kwargs)
72
+
73
+ # Log successful completion
74
+ duration_ms = (time.time() - start_time) * 1000
75
+ logger.info(
76
+ "command_completed",
77
+ command_name=command_name,
78
+ user=user,
79
+ entity_type=entity_type,
80
+ duration_ms=duration_ms if track_duration else None,
81
+ status="success",
82
+ )
83
+
84
+ return result
85
+
86
+ except click.Abort:
87
+ # User cancelled (Ctrl+C or declined prompt)
88
+ duration_ms = (time.time() - start_time) * 1000
89
+ logger.info(
90
+ "command_cancelled",
91
+ command_name=command_name,
92
+ user=user,
93
+ entity_type=entity_type,
94
+ duration_ms=duration_ms if track_duration else None,
95
+ )
96
+ raise
97
+
98
+ except Exception as e:
99
+ # Log error with context
100
+ duration_ms = (time.time() - start_time) * 1000
101
+ logger.error(
102
+ "command_failed",
103
+ command_name=command_name,
104
+ user=user,
105
+ entity_type=entity_type,
106
+ error_type=type(e).__name__,
107
+ error_message=str(e),
108
+ duration_ms=duration_ms if track_duration else None,
109
+ is_user_error=isinstance(e, click.BadParameter | ValueError),
110
+ )
111
+ raise
112
+
113
+ return wrapper
114
+
115
+ return decorator
116
+
117
+
118
+ def verbose_output(func: Callable) -> Callable:
119
+ """Add --verbose flag for controlling debug output visibility.
120
+
121
+ Suppresses debug logs by default for clean output.
122
+ When --verbose/-v is passed, all debug information is shown.
123
+
124
+ Works by disabling the console handler unless verbose is True.
125
+
126
+ Requires the decorated function to have a 'verbose' parameter.
127
+ Works with Click commands using @click.pass_context.
128
+
129
+ The decorator should be placed BEFORE @click.pass_context in the decorator stack.
130
+
131
+ Example:
132
+ @verbose_output
133
+ @click.pass_context
134
+ @click.command()
135
+ @click.option("--verbose", "-v", is_flag=True, ...)
136
+ def my_command(ctx, verbose):
137
+ # debug logs output suppressed unless verbose=True
138
+ ...
139
+ """
140
+ import logging
141
+
142
+ @functools.wraps(func)
143
+ def wrapper(*args, **kwargs) -> Any:
144
+ # Extract verbose flag from kwargs (it's passed as a Click option)
145
+ # Click passes options as keyword arguments after ctx
146
+ verbose = kwargs.get("verbose", False)
147
+
148
+ # Adjust console logging based on verbose flag
149
+ # Handler management requires standard logging API
150
+ # nosemgrep
151
+ roadmap_logger = logging.getLogger("roadmap")
152
+ original_levels = {}
153
+
154
+ # Find and adjust the console handler
155
+ for handler in roadmap_logger.handlers[:]:
156
+ if (
157
+ isinstance(handler, logging.StreamHandler)
158
+ and handler.stream == sys.stderr
159
+ ):
160
+ # Store original level for restoration later
161
+ original_levels[id(handler)] = handler.level
162
+
163
+ if verbose:
164
+ # With --verbose, show INFO and above
165
+ handler.setLevel(logging.INFO)
166
+ else:
167
+ # Without --verbose, suppress to CRITICAL (effectively disable console output)
168
+ handler.setLevel(logging.CRITICAL)
169
+
170
+ try:
171
+ return func(*args, **kwargs)
172
+ finally:
173
+ # Restore handler levels
174
+ for handler in roadmap_logger.handlers[:]:
175
+ if id(handler) in original_levels:
176
+ handler.setLevel(original_levels[id(handler)])
177
+
178
+ return wrapper
179
+
180
+
181
+ def log_audit_event(
182
+ action: str,
183
+ entity_type: str,
184
+ entity_id: str | None = None,
185
+ before: dict | None = None,
186
+ after: dict | None = None,
187
+ reason: str | None = None,
188
+ ) -> None:
189
+ """Log an auditable user action with before/after state.
190
+
191
+ Args:
192
+ action: Action performed (create, update, delete, archive, restore)
193
+ entity_type: Type of entity (issue, milestone, project)
194
+ entity_id: ID of the entity
195
+ before: Entity state before the action
196
+ after: Entity state after the action
197
+ reason: Reason for the action (if applicable)
198
+ """
199
+ user = get_current_user()
200
+ logger.info(
201
+ "audit_event",
202
+ action=action,
203
+ entity_type=entity_type,
204
+ entity_id=entity_id,
205
+ user=user,
206
+ before=before,
207
+ after=after,
208
+ reason=reason,
209
+ )
210
+
211
+
212
+ def log_operation_duration(
213
+ operation_name: str,
214
+ warn_threshold_ms: int = 5000,
215
+ ) -> Callable:
216
+ """Log operation duration and identify slow operations.
217
+
218
+ Args:
219
+ operation_name: Name of the operation
220
+ warn_threshold_ms: Threshold in milliseconds to warn about slow ops
221
+
222
+ Example:
223
+ @log_operation_duration("sync_issues", warn_threshold_ms=5000)
224
+ def sync_to_github():
225
+ ...
226
+ """
227
+
228
+ def decorator(func: Callable) -> Callable:
229
+ @functools.wraps(func)
230
+ def wrapper(*args, **kwargs) -> Any:
231
+ start_time = time.time()
232
+
233
+ try:
234
+ result = func(*args, **kwargs)
235
+ duration_ms = (time.time() - start_time) * 1000
236
+
237
+ # Log at appropriate level based on duration
238
+ if duration_ms > warn_threshold_ms:
239
+ logger.warning(
240
+ "operation_slow",
241
+ operation_name=operation_name,
242
+ duration_ms=duration_ms,
243
+ threshold_ms=warn_threshold_ms,
244
+ )
245
+ else:
246
+ logger.debug(
247
+ "operation_completed",
248
+ operation_name=operation_name,
249
+ duration_ms=duration_ms,
250
+ )
251
+
252
+ return result
253
+
254
+ except Exception as e:
255
+ duration_ms = (time.time() - start_time) * 1000
256
+ logger.error(
257
+ "operation_failed",
258
+ operation_name=operation_name,
259
+ error_type=type(e).__name__,
260
+ error_message=str(e),
261
+ duration_ms=duration_ms,
262
+ )
263
+ raise
264
+
265
+ return wrapper
266
+
267
+ return decorator