titan-cli 0.2.0__tar.gz → 0.3.2__tar.gz

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 (339) hide show
  1. {titan_cli-0.2.0 → titan_cli-0.3.2}/PKG-INFO +1 -1
  2. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/git_client.py +20 -3
  3. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/commit_service.py +59 -1
  4. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/diff_service.py +16 -2
  5. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/__init__.py +2 -0
  6. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/diff_operations.py +29 -0
  7. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/commit_step.py +6 -1
  8. titan_cli-0.3.2/plugins/titan-plugin-git/titan_plugin_git/steps/create_branch_step.py +166 -0
  9. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/diff_summary_step.py +43 -13
  10. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/__init__.py +2 -1
  11. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/agents/code_review_agent.py +168 -0
  12. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/pr_agent.py +14 -8
  13. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/checklists/__init__.py +5 -0
  14. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/checklists/defaults.py +100 -0
  15. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/github_client.py +65 -9
  16. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/pr_service.py +138 -18
  17. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/review_service.py +27 -3
  18. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/managers/__init__.py +15 -0
  19. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/managers/checklist_manager.py +23 -0
  20. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/managers/diff_context_manager.py +572 -0
  21. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/__init__.py +2 -0
  22. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/diff_models.py +130 -0
  23. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/__init__.py +3 -1
  24. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/comment_mapper.py +3 -1
  25. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/pr_mapper.py +63 -2
  26. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/__init__.py +3 -1
  27. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/pull_request.py +41 -0
  28. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/review_enums.py +109 -0
  29. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/review_models.py +306 -0
  30. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/validators.py +172 -0
  31. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/view.py +46 -0
  32. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/__init__.py +31 -0
  33. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/code_review_operations.py +607 -0
  34. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/comment_operations.py +4 -4
  35. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/context_resolution_operations.py +300 -0
  36. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/findings_operations.py +280 -0
  37. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/manifest_operations.py +191 -0
  38. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/plan_prompt_operations.py +234 -0
  39. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/review_action_operations.py +145 -0
  40. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/thread_resolution_operations.py +337 -0
  41. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/plugin.py +69 -2
  42. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/ai_pr_step.py +2 -3
  43. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/steps/code_review_steps.py +1784 -0
  44. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/create_pr_step.py +2 -2
  45. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/steps/select_cli_step.py +58 -0
  46. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/worktree_steps.py +2 -4
  47. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/__init__.py +2 -2
  48. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/code_block.py +0 -1
  49. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_thread.py +4 -4
  50. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_utils.py +201 -0
  51. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_view.py +360 -0
  52. titan_cli-0.2.0/plugins/titan-plugin-github/titan_plugin_github/workflows/review-pr-comments.yaml → titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/workflows/respond-pr-comments.yaml +1 -1
  53. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/workflows/review-pr-new-findings.yaml.disabled +91 -0
  54. titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/workflows/review-pr-thread-resolution.yaml.disabled +56 -0
  55. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/jira_agent.py +2 -2
  56. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/prompts.py +2 -6
  57. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/jira_client.py +58 -81
  58. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/network/jira_network.py +9 -12
  59. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/issue_service.py +153 -13
  60. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/metadata_service.py +297 -0
  61. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/config/templates/generic_issue.md.j2 +34 -0
  62. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/__init__.py +34 -0
  63. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/defaults.py +18 -0
  64. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/messages.py +161 -0
  65. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/templates.py +69 -0
  66. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants.py +266 -0
  67. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/formatters/markdown_formatter.py +3 -8
  68. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/__init__.py +22 -0
  69. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/enums.py +194 -0
  70. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/formatting.py +3 -16
  71. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/__init__.py +10 -0
  72. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/issue_type_mapper.py +36 -0
  73. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/priority_mapper.py +33 -0
  74. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/status_mapper.py +37 -0
  75. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/user_mapper.py +29 -0
  76. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/version_mapper.py +33 -0
  77. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/__init__.py +2 -0
  78. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/version.py +18 -0
  79. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/view.py +74 -0
  80. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/operations/__init__.py +8 -1
  81. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/operations/issue_formatting_operations.py +7 -8
  82. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/operations/issue_operations.py +142 -0
  83. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/plugin.py +55 -20
  84. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/ai_enhance_issue_description_step.py +233 -0
  85. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/confirm_auto_assign_step.py +67 -0
  86. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/create_generic_issue_step.py +143 -0
  87. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/list_versions_step.py +5 -7
  88. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/prompt_issue_description_step.py +52 -0
  89. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/review_issue_description_step.py +83 -0
  90. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/select_issue_priority_step.py +99 -0
  91. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/select_issue_type_step.py +120 -0
  92. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/utils/__init__.py +3 -0
  93. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/utils/input_validation.py +54 -0
  94. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/utils/saved_queries.py +4 -5
  95. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/utils.py +86 -0
  96. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/workflows/analyze-jira-issues.yaml +2 -10
  97. titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/workflows/create-generic-issue.yaml +56 -0
  98. {titan_cli-0.2.0 → titan_cli-0.3.2}/pyproject.toml +1 -1
  99. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/cli.py +19 -4
  100. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/config.py +18 -1
  101. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/logging/config.py +17 -7
  102. titan_cli-0.2.0/titan_cli/core/models.py → titan_cli-0.3.2/titan_cli/core/models/__init__.py +2 -2
  103. titan_cli-0.3.2/titan_cli/core/models/code_review.py +122 -0
  104. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/community.py +250 -22
  105. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/models.py +8 -0
  106. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/plugin_base.py +16 -1
  107. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/plugin_registry.py +87 -0
  108. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/models.py +4 -0
  109. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_registry.py +55 -0
  110. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_sources.py +76 -57
  111. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/builder.py +18 -3
  112. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/context.py +1 -0
  113. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/workflow_executor.py +1 -1
  114. titan_cli-0.3.2/titan_cli/external_cli/adapters/__init__.py +9 -0
  115. titan_cli-0.3.2/titan_cli/external_cli/adapters/base.py +78 -0
  116. titan_cli-0.3.2/titan_cli/external_cli/adapters/claude.py +67 -0
  117. titan_cli-0.3.2/titan_cli/external_cli/adapters/codex.py +104 -0
  118. titan_cli-0.3.2/titan_cli/external_cli/adapters/gemini.py +68 -0
  119. titan_cli-0.3.2/titan_cli/external_cli/adapters/registry.py +46 -0
  120. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/external_cli/configs.py +5 -0
  121. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/__init__.py +11 -7
  122. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/global_setup_wizard.py +2 -2
  123. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/install_plugin_screen.py +115 -59
  124. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/plugin_management.py +153 -40
  125. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/workflow_execution.py +11 -2
  126. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/workflows.py +2 -1
  127. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/textual_workflow_executor.py +1 -1
  128. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_option_list.py +1 -1
  129. titan_cli-0.3.2/titan_cli/utils/__init__.py +0 -0
  130. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/utils/autoupdate.py +22 -2
  131. titan_cli-0.2.0/plugins/titan-plugin-git/titan_plugin_git/steps/create_branch_step.py +0 -141
  132. titan_cli-0.2.0/plugins/titan-plugin-github/titan_plugin_github/widgets/comment.py +0 -150
  133. titan_cli-0.2.0/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_utils.py +0 -361
  134. titan_cli-0.2.0/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/metadata_service.py +0 -172
  135. {titan_cli-0.2.0 → titan_cli-0.3.2}/LICENSE +0 -0
  136. {titan_cli-0.2.0 → titan_cli-0.3.2}/README.md +0 -0
  137. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/__init__.py +0 -0
  138. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/__init__.py +0 -0
  139. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/network/__init__.py +0 -0
  140. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/network/git_network.py +0 -0
  141. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/__init__.py +0 -0
  142. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/branch_service.py +0 -0
  143. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/remote_service.py +0 -0
  144. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/stash_service.py +0 -0
  145. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/status_service.py +0 -0
  146. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/tag_service.py +0 -0
  147. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/worktree_service.py +0 -0
  148. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/exceptions.py +0 -0
  149. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/messages.py +0 -0
  150. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/__init__.py +0 -0
  151. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/__init__.py +0 -0
  152. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/branch_mapper.py +0 -0
  153. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/commit_mapper.py +0 -0
  154. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/status_mapper.py +0 -0
  155. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/tag_mapper.py +0 -0
  156. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/worktree_mapper.py +0 -0
  157. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/__init__.py +0 -0
  158. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/branch.py +0 -0
  159. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/commit.py +0 -0
  160. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/status.py +0 -0
  161. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/tag.py +0 -0
  162. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/worktree.py +0 -0
  163. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/__init__.py +0 -0
  164. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/branch.py +0 -0
  165. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/commit.py +0 -0
  166. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/status.py +0 -0
  167. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/tag.py +0 -0
  168. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/worktree.py +0 -0
  169. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/branch_operations.py +0 -0
  170. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/commit_operations.py +0 -0
  171. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/plugin.py +0 -0
  172. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/__init__.py +0 -0
  173. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/ai_commit_message_step.py +0 -0
  174. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/branch_steps.py +0 -0
  175. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/checkout_step.py +0 -0
  176. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/create_worktree_step.py +0 -0
  177. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/pull_step.py +0 -0
  178. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/push_step.py +0 -0
  179. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/remove_worktree_step.py +0 -0
  180. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/restore_original_branch_step.py +0 -0
  181. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/save_current_branch_step.py +0 -0
  182. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/status_step.py +0 -0
  183. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/worktree_command_step.py +0 -0
  184. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/workflows/__previews__/__init__.py +0 -0
  185. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/workflows/__previews__/commit_ai_preview.py +0 -0
  186. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/workflows/commit-ai.yaml +0 -0
  187. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/__init__.py +0 -0
  188. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/config_loader.py +0 -0
  189. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/issue_generator.py +0 -0
  190. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/__init__.py +0 -0
  191. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/__init__.py +0 -0
  192. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/gh_network.py +0 -0
  193. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/graphql_network.py +0 -0
  194. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/graphql_queries.py +0 -0
  195. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/protocols.py +0 -0
  196. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/__init__.py +0 -0
  197. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/issue_service.py +0 -0
  198. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/team_service.py +0 -0
  199. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/config/__init__.py +0 -0
  200. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/config/pr_agent.toml +0 -0
  201. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/exceptions.py +0 -0
  202. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/messages.py +0 -0
  203. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/formatting.py +0 -0
  204. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/issue_mapper.py +0 -0
  205. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/review_mapper.py +0 -0
  206. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/thread_mapper.py +0 -0
  207. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/__init__.py +0 -0
  208. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/__init__.py +0 -0
  209. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/issue_comment.py +0 -0
  210. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/review_comment.py +0 -0
  211. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/review_thread.py +0 -0
  212. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/user.py +0 -0
  213. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/issue.py +0 -0
  214. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/review.py +0 -0
  215. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/user.py +0 -0
  216. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/issue_operations.py +0 -0
  217. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/pr_creation_operations.py +0 -0
  218. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/pr_operations.py +0 -0
  219. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/worktree_operations.py +0 -0
  220. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/__init__.py +0 -0
  221. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/github_prompt_steps.py +0 -0
  222. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/issue_steps.py +0 -0
  223. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/pr_review_steps.py +0 -0
  224. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/preview_step.py +0 -0
  225. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/utils.py +0 -0
  226. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/reply_comment.py +0 -0
  227. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/__previews__/__init__.py +0 -0
  228. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/__previews__/create_pr_ai_preview.py +0 -0
  229. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/create-issue-ai.yaml +0 -0
  230. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/create-pr-ai.yaml +0 -0
  231. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/__init__.py +0 -0
  232. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/__init__.py +0 -0
  233. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/config_loader.py +0 -0
  234. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/response_parser.py +0 -0
  235. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/token_tracker.py +0 -0
  236. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/validators.py +0 -0
  237. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/__init__.py +0 -0
  238. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/network/__init__.py +0 -0
  239. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/__init__.py +0 -0
  240. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/comment_service.py +0 -0
  241. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/link_service.py +0 -0
  242. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/project_service.py +0 -0
  243. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/transition_service.py +0 -0
  244. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/config/jira_agent.toml +0 -0
  245. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/config/templates/issue_analysis.md.j2 +0 -0
  246. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/exceptions.py +0 -0
  247. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/formatters/__init__.py +0 -0
  248. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/messages.py +0 -0
  249. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/comment_mapper.py +0 -0
  250. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/issue_mapper.py +0 -0
  251. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/project_mapper.py +0 -0
  252. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/transition_mapper.py +0 -0
  253. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/comment.py +0 -0
  254. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/issue.py +0 -0
  255. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/issue_type.py +0 -0
  256. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/priority.py +0 -0
  257. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/project.py +0 -0
  258. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/status.py +0 -0
  259. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/transition.py +0 -0
  260. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/user.py +0 -0
  261. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/operations/jql_operations.py +0 -0
  262. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/ai_analyze_issue_step.py +0 -0
  263. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/get_issue_step.py +0 -0
  264. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/prompt_select_issue_step.py +0 -0
  265. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/search_jql_step.py +0 -0
  266. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/search_saved_query_step.py +0 -0
  267. {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/utils/issue_sorter.py +0 -0
  268. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/__init__.py +0 -0
  269. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/__main__.py +0 -0
  270. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/__init__.py +0 -0
  271. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/agents/__init__.py +0 -0
  272. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/agents/base.py +0 -0
  273. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/client.py +0 -0
  274. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/constants.py +0 -0
  275. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/exceptions.py +0 -0
  276. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/llm_tools.py +0 -0
  277. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/models.py +0 -0
  278. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/oauth_helper.py +0 -0
  279. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/__init__.py +0 -0
  280. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/anthropic.py +0 -0
  281. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/base.py +0 -0
  282. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/gemini.py +0 -0
  283. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/clients/__init__.py +0 -0
  284. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/clients/gcloud_client.py +0 -0
  285. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/__init__.py +0 -0
  286. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/discovery.py +0 -0
  287. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/errors.py +0 -0
  288. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/logging/__init__.py +0 -0
  289. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/logging/decorators.py +0 -0
  290. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/available.py +0 -0
  291. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/result.py +0 -0
  292. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/secrets.py +0 -0
  293. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/utils.py +0 -0
  294. {titan_cli-0.2.0/titan_cli/external_cli → titan_cli-0.3.2/titan_cli/core/validators}/__init__.py +0 -0
  295. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/__init__.py +0 -0
  296. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/project_step_source.py +0 -0
  297. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_exceptions.py +0 -0
  298. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_filter_service.py +0 -0
  299. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/__init__.py +0 -0
  300. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/mock_context.py +0 -0
  301. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/results.py +0 -0
  302. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/steps/ai_assistant_step.py +0 -0
  303. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/steps/command_step.py +0 -0
  304. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/utils/__init__.py +0 -0
  305. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/utils/venv.py +0 -0
  306. {titan_cli-0.2.0/titan_cli/utils → titan_cli-0.3.2/titan_cli/external_cli}/__init__.py +0 -0
  307. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/external_cli/launcher.py +0 -0
  308. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/messages.py +0 -0
  309. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/__previews__/statusbar_preview.py +0 -0
  310. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/app.py +0 -0
  311. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/colors.py +0 -0
  312. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/icons.py +0 -0
  313. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/__init__.py +0 -0
  314. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/ai_config.py +0 -0
  315. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/ai_config_wizard.py +0 -0
  316. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/base.py +0 -0
  317. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/cli_launcher.py +0 -0
  318. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/main_menu.py +0 -0
  319. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/plugin_config_wizard.py +0 -0
  320. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/project_setup_wizard.py +0 -0
  321. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/textual_components.py +0 -0
  322. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/theme.py +0 -0
  323. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/__init__.py +0 -0
  324. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/button.py +0 -0
  325. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/decision_badge.py +0 -0
  326. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/header.py +0 -0
  327. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/multiline_input.py +0 -0
  328. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/panel.py +0 -0
  329. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/panel_container.py +0 -0
  330. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_choice.py +0 -0
  331. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_input.py +0 -0
  332. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_selection_list.py +0 -0
  333. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_textarea.py +0 -0
  334. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/status_bar.py +0 -0
  335. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/step_container.py +0 -0
  336. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/styled_option_list.py +0 -0
  337. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/table.py +0 -0
  338. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/text.py +0 -0
  339. {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/wizard.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: titan-cli
3
- Version: 0.2.0
3
+ Version: 0.3.2
4
4
  Summary: Modular development tools orchestrator - Streamline your workflows with AI integration and intuitive terminal UI
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -243,6 +243,12 @@ class GitClient:
243
243
  """Create a commit."""
244
244
  return self.commit_service.commit(message, all, no_verify)
245
245
 
246
+ def commit_files(
247
+ self, files: list, message: str, no_verify: bool = True
248
+ ) -> ClientResult[str]:
249
+ """Create a commit with specific files only."""
250
+ return self.commit_service.commit_files(files, message, no_verify)
251
+
246
252
  def get_current_commit(self) -> ClientResult[str]:
247
253
  """Get current commit SHA (HEAD)."""
248
254
  return self.commit_service.get_current_commit()
@@ -303,9 +309,20 @@ class GitClient:
303
309
  """Get diff for a specific file."""
304
310
  return self.diff_service.get_file_diff(file_path)
305
311
 
306
- def get_branch_diff(self, base_branch: str, head_branch: str) -> ClientResult[str]:
307
- """Get diff between two branches."""
308
- return self.diff_service.get_branch_diff(base_branch, head_branch)
312
+ def get_branch_diff(self, base_branch: str, head_branch: str, context_lines: int = 3, use_remote: bool = False) -> ClientResult[str]:
313
+ """
314
+ Get diff between two branches.
315
+
316
+ Args:
317
+ base_branch: Base branch name
318
+ head_branch: Head branch name
319
+ context_lines: Number of context lines (default: 3)
320
+ use_remote: If True, both branches are treated as remote refs (default: False)
321
+
322
+ Returns:
323
+ ClientResult[str] with diff output
324
+ """
325
+ return self.diff_service.get_branch_diff(base_branch, head_branch, context_lines, use_remote)
309
326
 
310
327
  def get_diff_stat(self, base_ref: str, head_ref: str = "HEAD") -> ClientResult[str]:
311
328
  """Get diff stat summary."""
@@ -5,7 +5,8 @@ Commit Service
5
5
  Business logic for Git commit operations.
6
6
  Uses network layer to execute commands, parses to network models, maps to view models.
7
7
  """
8
- from typing import List, Optional
8
+ import os
9
+ from typing import List, Optional, Sequence
9
10
 
10
11
  from titan_cli.core.result import ClientResult, ClientSuccess, ClientError
11
12
  from titan_cli.core.logging import log_client_operation
@@ -70,6 +71,63 @@ class CommitService:
70
71
  except GitCommandError as e:
71
72
  return ClientError(error_message=str(e), error_code="COMMIT_ERROR")
72
73
 
74
+ @log_client_operation()
75
+ def commit_files(
76
+ self, files: Sequence[str], message: str, no_verify: bool = True
77
+ ) -> ClientResult[str]:
78
+ """
79
+ Create a commit with specific files only.
80
+
81
+ Args:
82
+ files: File paths to stage and commit
83
+ message: Commit message
84
+ no_verify: Skip pre-commit and commit-msg hooks
85
+
86
+ Returns:
87
+ ClientResult[str] with commit hash
88
+ """
89
+ try:
90
+ # Separate existing files from deleted ones
91
+ # Only include files that exist in the filesystem OR are tracked in git
92
+ existing_files = []
93
+ deleted_files = []
94
+
95
+ for f in files:
96
+ if os.path.exists(f):
97
+ # File exists in filesystem
98
+ existing_files.append(f)
99
+ else:
100
+ # File doesn't exist - check if it's tracked in git
101
+ # If it's tracked, we can use git rm; if not, skip it
102
+ try:
103
+ self.git.run_command(["git", "ls-files", "--error-unmatch", f])
104
+ # File is tracked, mark for deletion
105
+ deleted_files.append(f)
106
+ except GitCommandError:
107
+ # File not tracked in git, skip it
108
+ pass
109
+
110
+ # Stage existing files with git add
111
+ if existing_files:
112
+ self.git.run_command(["git", "add", "--"] + existing_files)
113
+
114
+ # Stage deleted files with git rm
115
+ if deleted_files:
116
+ self.git.run_command(["git", "rm", "--"] + deleted_files)
117
+
118
+ args = ["git", "commit", "-m", message]
119
+ if no_verify:
120
+ args.append("--no-verify")
121
+ self.git.run_command(args)
122
+
123
+ commit_hash = self.git.run_command(["git", "rev-parse", "HEAD"])
124
+ return ClientSuccess(
125
+ data=commit_hash,
126
+ message=f"Commit created: {commit_hash[:7]}"
127
+ )
128
+ except GitCommandError as e:
129
+ return ClientError(error_message=str(e), error_code="COMMIT_ERROR")
130
+
73
131
  @log_client_operation()
74
132
  def get_current_commit(self) -> ClientResult[str]:
75
133
  """
@@ -141,20 +141,34 @@ class DiffService:
141
141
  return ClientError(error_message=str(e), error_code="DIFF_ERROR")
142
142
 
143
143
  @log_client_operation()
144
- def get_branch_diff(self, base_branch: str, head_branch: str) -> ClientResult[str]:
144
+ def get_branch_diff(self, base_branch: str, head_branch: str, context_lines: int = 3, use_remote: bool = False) -> ClientResult[str]:
145
145
  """
146
146
  Get diff between two branches.
147
147
 
148
148
  Args:
149
149
  base_branch: Base branch name
150
150
  head_branch: Head branch name
151
+ context_lines: Number of unchanged context lines around each change (default: 3).
152
+ When called from code review with context_lines=20, provides extended context
153
+ for AI analysis. The higher value gives better code understanding for review
154
+ quality, while still keeping token usage reasonable compared to reading entire files.
155
+ use_remote: If True, both branches are prefixed with the configured default_remote.
156
+ Used for PR reviews where branches are remote refs only (not checked out locally).
151
157
 
152
158
  Returns:
153
159
  ClientResult[str] with diff output
154
160
  """
155
161
  try:
162
+ # Build branch references using configured default_remote if use_remote=True
163
+ if use_remote:
164
+ base_ref = f"{self.default_remote}/{base_branch}"
165
+ head_ref = f"{self.default_remote}/{head_branch}"
166
+ else:
167
+ base_ref = f"{self.default_remote}/{base_branch}"
168
+ head_ref = head_branch
169
+
156
170
  diff = self.git.run_command(
157
- ["git", "diff", f"{self.default_remote}/{base_branch}...{head_branch}"],
171
+ ["git", "diff", f"-U{context_lines}", f"{base_ref}...{head_ref}"],
158
172
  check=False
159
173
  )
160
174
  return ClientSuccess(
@@ -20,6 +20,7 @@ from .commit_operations import (
20
20
 
21
21
  from .diff_operations import (
22
22
  parse_diff_stat_output,
23
+ expand_rename_path,
23
24
  get_max_filename_length,
24
25
  colorize_diff_stats,
25
26
  colorize_diff_summary,
@@ -42,6 +43,7 @@ __all__ = [
42
43
 
43
44
  # Diff operations
44
45
  "parse_diff_stat_output",
46
+ "expand_rename_path",
45
47
  "get_max_filename_length",
46
48
  "colorize_diff_stats",
47
49
  "colorize_diff_summary",
@@ -5,8 +5,36 @@ Pure business logic for Git diff parsing and formatting.
5
5
  These functions can be used by any step and are easily testable.
6
6
  """
7
7
 
8
+ import re
8
9
  from typing import List, Tuple
9
10
 
11
+ # Matches git rename notation: prefix{old => new}suffix
12
+ # Examples:
13
+ # titan_cli/core/{models.py => models/__init__.py} → titan_cli/core/models/__init__.py
14
+ # {old_dir => new_dir}/file.py → new_dir/file.py
15
+ _RENAME_PATTERN = re.compile(r'^(.*?)\{[^}]*\s*=>\s*([^}]*)\}(.*)$')
16
+
17
+
18
+ def expand_rename_path(path: str) -> str:
19
+ """
20
+ Expand a git rename notation path to the actual new file path.
21
+
22
+ Git diff --stat uses {old => new} notation for renames.
23
+ This function converts it to a real file path usable by git add.
24
+
25
+ Args:
26
+ path: A file path, possibly containing git rename notation.
27
+
28
+ Returns:
29
+ Expanded path with the rename resolved to the new name.
30
+ If no rename notation is present, returns the path unchanged.
31
+ """
32
+ match = _RENAME_PATTERN.match(path)
33
+ if not match:
34
+ return path
35
+ prefix, new_part, suffix = match.groups()
36
+ return prefix + new_part.strip() + suffix
37
+
10
38
 
11
39
  def parse_diff_stat_output(stat_output: str) -> Tuple[List[Tuple[str, str]], List[str]]:
12
40
  """
@@ -155,6 +183,7 @@ def format_diff_stat_display(stat_output: str) -> Tuple[List[str], List[str]]:
155
183
 
156
184
  __all__ = [
157
185
  "parse_diff_stat_output",
186
+ "expand_rename_path",
158
187
  "get_max_filename_length",
159
188
  "colorize_diff_stats",
160
189
  "colorize_diff_summary",
@@ -53,9 +53,14 @@ def create_git_commit_step(ctx: WorkflowContext) -> WorkflowResult:
53
53
 
54
54
  all_files = ctx.get('all_files', True)
55
55
  no_verify = ctx.get('no_verify', False)
56
+ selected_files = ctx.data.get("selected_files")
56
57
 
57
58
  # Create commit using ClientResult pattern
58
- result = ctx.git.commit(message=commit_message, all=all_files, no_verify=no_verify)
59
+ # If the user picked a specific subset of files, stage only those
60
+ if selected_files is not None:
61
+ result = ctx.git.commit_files(files=selected_files, message=commit_message, no_verify=no_verify)
62
+ else:
63
+ result = ctx.git.commit(message=commit_message, all=all_files, no_verify=no_verify)
59
64
 
60
65
  match result:
61
66
  case ClientSuccess(data=commit_hash):
@@ -0,0 +1,166 @@
1
+ """
2
+ Create a new Git branch.
3
+ """
4
+
5
+ import traceback
6
+
7
+ from titan_cli.engine import WorkflowContext, WorkflowResult, Success, Error
8
+ from titan_cli.core.result import ClientSuccess, ClientError
9
+ from ..operations import (
10
+ check_branch_exists,
11
+ determine_safe_checkout_target,
12
+ should_delete_before_create,
13
+ )
14
+
15
+
16
+ def create_branch_step(ctx: WorkflowContext) -> WorkflowResult:
17
+ """
18
+ Create a new Git branch.
19
+
20
+ Inputs (from ctx.data):
21
+ new_branch (str): Name of the branch to create
22
+ start_point (str, optional): Starting point for the branch (defaults to HEAD)
23
+ delete_if_exists (bool, optional): Delete the branch if it already exists (default: False)
24
+ checkout (bool, optional): Checkout the new branch after creation (default: True)
25
+
26
+ Returns:
27
+ Success: Branch created successfully
28
+ Error: Git operation failed
29
+ """
30
+ if ctx.textual:
31
+ ctx.textual.begin_step("Create Branch")
32
+
33
+ if not ctx.textual:
34
+ return Error("Textual UI context is not available for this step.")
35
+
36
+ if not ctx.git:
37
+ ctx.textual.error_text("Git client not available in context")
38
+ ctx.textual.end_step("error")
39
+ return Error("Git client not available in context")
40
+
41
+ try:
42
+ # Get params from context
43
+ new_branch = ctx.get("new_branch")
44
+ if not new_branch:
45
+ ctx.textual.error_text("No branch name specified")
46
+ ctx.textual.dim_text("Set 'new_branch' in workflow params or previous step")
47
+ ctx.textual.end_step("error")
48
+ return Error("No branch name specified")
49
+
50
+ start_point = ctx.get("start_point", "HEAD")
51
+ delete_if_exists = ctx.get("delete_if_exists", False)
52
+ checkout = ctx.get("checkout", True)
53
+
54
+ ctx.textual.text("")
55
+ ctx.textual.dim_text(f"Creating branch: {new_branch}")
56
+ ctx.textual.dim_text(f"From: {start_point}")
57
+
58
+ # Check if branch exists using operations
59
+ branches_result = ctx.git.get_branches()
60
+
61
+ match branches_result:
62
+ case ClientSuccess(data=all_branches):
63
+ branch_names = [b.name for b in all_branches]
64
+ branch_exists = check_branch_exists(new_branch, branch_names)
65
+ case ClientError(error_message=err):
66
+ ctx.textual.error_text(f"Failed to get branches: {err}")
67
+ ctx.textual.end_step("error")
68
+ return Error(f"Failed to get branches: {err}")
69
+
70
+ # Delete if exists and requested using operations
71
+ if should_delete_before_create(branch_exists, delete_if_exists):
72
+ ctx.textual.text("")
73
+ ctx.textual.warning_text(f"Branch {new_branch} exists, deleting...")
74
+
75
+ # If we're on the branch, checkout another one first using operations
76
+ current_branch_result = ctx.git.get_current_branch()
77
+
78
+ match current_branch_result:
79
+ case ClientSuccess(data=current_branch):
80
+ safe_target = determine_safe_checkout_target(
81
+ current_branch=current_branch,
82
+ branch_to_delete=new_branch,
83
+ main_branch=ctx.git.main_branch,
84
+ all_branches=branch_names
85
+ )
86
+
87
+ if safe_target:
88
+ checkout_result = ctx.git.checkout(safe_target)
89
+ match checkout_result:
90
+ case ClientSuccess():
91
+ ctx.textual.dim_text(f"Switched to {safe_target}")
92
+ case ClientError(error_message=err):
93
+ ctx.textual.error_text(f"Failed to checkout {safe_target}: {err}")
94
+ ctx.textual.end_step("error")
95
+ return Error(f"Cannot checkout {safe_target}: {err}")
96
+ elif current_branch == new_branch:
97
+ # Cannot delete current branch and no safe target available
98
+ ctx.textual.error_text(f"Cannot delete current branch {new_branch}")
99
+ ctx.textual.end_step("error")
100
+ return Error("Cannot delete current branch")
101
+
102
+ # Delete the branch
103
+ delete_result = ctx.git.safe_delete_branch(new_branch, force=True)
104
+ match delete_result:
105
+ case ClientSuccess():
106
+ ctx.textual.success_text(f"✓ Deleted existing branch {new_branch}")
107
+ case ClientError(error_message=err):
108
+ ctx.textual.error_text(f"Failed to delete {new_branch}: {err}")
109
+ ctx.textual.end_step("error")
110
+ return Error(f"Failed to delete branch: {err}")
111
+
112
+ case ClientError(error_message=err):
113
+ ctx.textual.error_text(f"Failed to get current branch: {err}")
114
+ ctx.textual.end_step("error")
115
+ return Error(f"Failed to get current branch: {err}")
116
+
117
+ elif branch_exists:
118
+ ctx.textual.error_text(f"Branch {new_branch} already exists")
119
+ ctx.textual.dim_text("Set 'delete_if_exists: true' to recreate it")
120
+ ctx.textual.end_step("error")
121
+ return Error(f"Branch {new_branch} already exists")
122
+
123
+ # Create the branch
124
+ ctx.textual.text("")
125
+ create_result = ctx.git.create_branch(new_branch, start_point=start_point)
126
+ match create_result:
127
+ case ClientSuccess():
128
+ ctx.textual.success_text(f"✓ Created branch {new_branch}")
129
+ case ClientError(error_message=err):
130
+ ctx.textual.error_text(f"Failed to create {new_branch}: {err}")
131
+ ctx.textual.end_step("error")
132
+ return Error(f"Failed to create branch: {err}")
133
+
134
+ # Checkout if requested
135
+ if checkout:
136
+ checkout_result = ctx.git.checkout(new_branch)
137
+ match checkout_result:
138
+ case ClientSuccess():
139
+ ctx.textual.success_text(f"✓ Checked out {new_branch}")
140
+ case ClientError(error_message=err):
141
+ ctx.textual.warning_text(f"Branch created but failed to checkout: {err}")
142
+
143
+ ctx.textual.text("")
144
+ ctx.textual.end_step("success")
145
+ return Success(
146
+ f"Created branch {new_branch}",
147
+ metadata={
148
+ "new_branch": new_branch,
149
+ "start_point": start_point,
150
+ "checked_out": checkout
151
+ }
152
+ )
153
+
154
+ except Exception as e:
155
+ tb = traceback.format_exc()
156
+ ctx.textual.text("")
157
+ ctx.textual.error_text(f"Failed to create branch: {str(e)}")
158
+ ctx.textual.text("")
159
+ ctx.textual.dim_text("Full traceback:")
160
+ for line in tb.split('\n'):
161
+ ctx.textual.dim_text(line)
162
+ ctx.textual.end_step("error")
163
+ return Error(f"Failed to create branch: {str(e)}")
164
+
165
+
166
+ __all__ = ["create_branch_step"]
@@ -1,19 +1,22 @@
1
1
  # plugins/titan-plugin-git/titan_plugin_git/steps/diff_summary_step.py
2
- from titan_cli.engine import WorkflowContext, WorkflowResult, Success, Error, Skip
2
+ from titan_cli.engine import WorkflowContext, WorkflowResult, Success, Error, Skip, Exit
3
3
  from titan_cli.core.result import ClientSuccess, ClientError
4
+ from titan_cli.ui.tui.widgets import SelectionOption
4
5
  from titan_plugin_git.messages import msg
5
- from ..operations import format_diff_stat_display
6
+ from ..operations import parse_diff_stat_output, expand_rename_path, colorize_diff_stats, colorize_diff_summary, format_diff_stat_display
6
7
 
7
8
 
8
9
  def show_uncommitted_diff_summary(ctx: WorkflowContext) -> WorkflowResult:
9
10
  """
10
- Show summary of uncommitted changes (git diff --stat).
11
+ Show uncommitted changes and let the user select which files to include
12
+ in the commit. Each checkbox shows the filename and its diff stats inline.
11
13
 
12
- Provides a visual overview of files changed and lines modified
13
- before generating commit messages.
14
+ Saves selected file paths to ctx.data["selected_files"].
14
15
 
15
16
  Returns:
16
- Success: Always (even if no changes, for workflow continuity)
17
+ Success: Files selected and saved to context
18
+ Exit: No files selected by the user
19
+ Skip: Could not retrieve diff stat
17
20
  """
18
21
  if not ctx.textual:
19
22
  return Error("Textual UI context is not available for this step.")
@@ -24,7 +27,6 @@ def show_uncommitted_diff_summary(ctx: WorkflowContext) -> WorkflowResult:
24
27
  # Begin step container
25
28
  ctx.textual.begin_step("Show Changes Summary")
26
29
 
27
- # Get diff stat for uncommitted changes using ClientResult pattern
28
30
  result = ctx.git.get_uncommitted_diff_stat()
29
31
 
30
32
  match result:
@@ -34,17 +36,45 @@ def show_uncommitted_diff_summary(ctx: WorkflowContext) -> WorkflowResult:
34
36
  ctx.textual.end_step("success")
35
37
  return Success("No changes")
36
38
 
37
- # Format and render diff stat
38
- formatted_files, formatted_summary = format_diff_stat_display(stat_output)
39
- ctx.textual.show_diff_stat(formatted_files, formatted_summary, "Changes summary:")
39
+ file_lines, summary_lines = parse_diff_stat_output(stat_output)
40
+
41
+ if file_lines:
42
+ max_len = max(len(filename) for filename, _ in file_lines)
43
+ options = [
44
+ SelectionOption(
45
+ value=expand_rename_path(filename),
46
+ label=f"{filename.ljust(max_len)} |{colorize_diff_stats(stats)}",
47
+ selected=True,
48
+ )
49
+ for filename, stats in file_lines
50
+ ]
51
+
52
+ summary_text = colorize_diff_summary(summary_lines[0].strip()) if summary_lines else ""
53
+ question = f"Select files to include in the commit: {summary_text}"
54
+
55
+ selected = ctx.textual.ask_multiselect(question, options)
56
+
57
+ if not selected:
58
+ ctx.textual.warning_text("No files selected. Select at least one file to commit.")
59
+ ctx.textual.end_step("skip")
60
+ return Exit("No files selected for commit")
61
+
62
+ ctx.data["selected_files"] = selected
63
+
64
+ # Show what was selected
65
+ selected_set = set(selected)
66
+ selected_lines = [(f, s) for f, s in file_lines if f in selected_set]
67
+ formatted_selected = [
68
+ f"{f.ljust(max_len)} |{colorize_diff_stats(s)}"
69
+ for f, s in selected_lines
70
+ ]
71
+ formatted_summary = [colorize_diff_summary(summary_lines[0].strip())] if summary_lines else []
72
+ ctx.textual.show_diff_stat(formatted_selected, formatted_summary, "Files to commit:")
40
73
 
41
- # End step container with success
42
74
  ctx.textual.end_step("success")
43
-
44
75
  return Success("Diff summary displayed")
45
76
 
46
77
  case ClientError(error_message=err):
47
- # Don't fail the workflow, just skip
48
78
  ctx.textual.end_step("skip")
49
79
  return Skip(f"Could not show diff summary: {err}")
50
80
 
@@ -2,5 +2,6 @@
2
2
  """AI agents for GitHub plugin."""
3
3
 
4
4
  from .pr_agent import PRAgent, PRAnalysis
5
+ from .code_review_agent import CodeReviewAgent
5
6
 
6
- __all__ = ["PRAgent", "PRAnalysis"]
7
+ __all__ = ["PRAgent", "PRAnalysis", "CodeReviewAgent"]
@@ -0,0 +1,168 @@
1
+ # plugins/titan-plugin-github/titan_plugin_github/agents/code_review_agent.py
2
+ """
3
+ CodeReviewAgent - AI agent for reviewing pull requests.
4
+
5
+ Analyzes PR diffs and project skills to generate structured review comments.
6
+ """
7
+
8
+ import json
9
+ from typing import List
10
+
11
+ from titan_cli.core.logging import get_logger
12
+ from titan_cli.ai.agents.base import BaseAIAgent, AgentRequest
13
+ from ..models.review_enums import FindingSeverity
14
+ from ..models.view import UIReviewSuggestion
15
+
16
+ logger = get_logger(__name__)
17
+
18
+
19
+ def _normalize_suggestion_severity(raw_severity: str) -> FindingSeverity:
20
+ """Normalize legacy and current AI severity labels into FindingSeverity."""
21
+ mapping = {
22
+ "blocking": FindingSeverity.BLOCKING,
23
+ "critical": FindingSeverity.BLOCKING,
24
+ "important": FindingSeverity.IMPORTANT,
25
+ "improvement": FindingSeverity.IMPORTANT,
26
+ "nit": FindingSeverity.NIT,
27
+ "suggestion": FindingSeverity.NIT,
28
+ }
29
+ return mapping.get(raw_severity.lower(), FindingSeverity.NIT)
30
+
31
+ _SYSTEM_PROMPT = """You are an expert code reviewer. Your task is to review pull request diffs
32
+ and identify problems, bugs, and improvements.
33
+
34
+ When reviewing code, focus ONLY on:
35
+ - Correctness: bugs, logic errors, edge cases
36
+ - Security: vulnerabilities, unsafe patterns
37
+ - Performance: inefficiencies, unnecessary complexity
38
+ - Maintainability: readability, naming, structure
39
+ - Project conventions: follow any project-specific skills/guidelines provided
40
+
41
+ IMPORTANT rules:
42
+ - ONLY comment when you have something to improve or fix. Never praise, compliment, or validate changes.
43
+ - Do NOT say things like "Good cleanup", "Excellent improvement", "Nice refactor", etc.
44
+ - If a change looks correct and has no issues, skip it entirely — return nothing for that file/line.
45
+ - Every comment must propose a concrete change or flag a real problem.
46
+ - If the code looks good overall, return an empty array [].
47
+
48
+ If "Existing Open Review Comments" are provided:
49
+ - Check each thread before suggesting changes — do NOT duplicate an issue already in the conversation.
50
+ - If the author/reviewer has already responded (even with a short note), and the issue seems addressed, do NOT suggest it again.
51
+ - Example: If someone says "This variable exists as an org secret", don't suggest validating it.
52
+ - Example: If someone says "Already fixed in commit X", don't repeat the same issue.
53
+ - Only reply to a thread (using `reply_to_comment_id`) if needed to continue the conversation:
54
+ - If author says it's fixed and they're RIGHT → skip, don't reply
55
+ - If author disagrees and they're RIGHT → skip, don't reply
56
+ - If author is WRONG or hasn't addressed it yet → reply with clarification, evidence, or escalation
57
+ - Never suggest a reply just to repeat the original comment. Replies must add new context or refute the author's reasoning.
58
+
59
+ Output your review as a JSON array of comment objects. Each comment must have:
60
+ - "file": the file path (string). Use empty string "" when replying to a thread.
61
+ - "snippet": the exact line of code where the problem is (copy-paste the line verbatim from the diff, without the leading + or - character). Use null for general file-level comments or replies.
62
+ - "body": the review comment text (string, be concise and actionable)
63
+ - "severity": one of "blocking", "important", or "nit"
64
+ - "reply_to_comment_id": (optional) the integer comment ID from `[comment_id:N]` if this is a follow-up reply to an existing thread. Omit or use null for new comments.
65
+
66
+ Severity guide:
67
+ - "blocking": bugs, security issues, broken logic that must be fixed
68
+ - "important": code quality issues that should be addressed
69
+ - "nit": minor style, naming, or optional improvements
70
+
71
+ Respond with ONLY the JSON array, no other text.
72
+ """
73
+
74
+
75
+ class CodeReviewAgent(BaseAIAgent):
76
+ """
77
+ AI agent for reviewing pull requests using project skills as context.
78
+
79
+ Generates structured UIReviewSuggestion objects from PR diffs.
80
+ """
81
+
82
+ def get_system_prompt(self) -> str:
83
+ """System prompt for code review expertise."""
84
+ return _SYSTEM_PROMPT
85
+
86
+ def review(self, context: str) -> List[UIReviewSuggestion]:
87
+ """
88
+ Generate review comments for a PR.
89
+
90
+ Args:
91
+ context: Formatted string with PR info, diff, and project skills
92
+
93
+ Returns:
94
+ List of UIReviewSuggestion objects
95
+ """
96
+ request = AgentRequest(
97
+ context=context,
98
+ max_tokens=4000,
99
+ temperature=0.3,
100
+ operation="code_review",
101
+ )
102
+
103
+ try:
104
+ response = self.generate(request)
105
+ except Exception as e:
106
+ logger.error(f"AI code review failed: {e}")
107
+ return []
108
+
109
+ return self._parse_suggestions(response.content)
110
+
111
+ def _parse_suggestions(self, content: str) -> List[UIReviewSuggestion]:
112
+ """
113
+ Parse AI JSON response into UIReviewSuggestion objects.
114
+
115
+ Args:
116
+ content: Raw AI response string
117
+
118
+ Returns:
119
+ List of UIReviewSuggestion objects (empty list on parse failure)
120
+ """
121
+ # Strip markdown code fences if present
122
+ text = content.strip()
123
+ if text.startswith("```"):
124
+ lines = text.split("\n")
125
+ text = "\n".join(lines[1:-1]) if len(lines) > 2 else text
126
+
127
+ try:
128
+ data = json.loads(text)
129
+ except json.JSONDecodeError:
130
+ logger.warning(f"Failed to parse AI review response as JSON: {content[:200]}")
131
+ return []
132
+
133
+ if not isinstance(data, list):
134
+ logger.warning(f"AI review response is not a list: {type(data)}")
135
+ return []
136
+
137
+ suggestions = []
138
+
139
+ for item in data:
140
+ if not isinstance(item, dict):
141
+ continue
142
+
143
+ file_path = item.get("file", "")
144
+ if not file_path:
145
+ continue
146
+
147
+ severity = _normalize_suggestion_severity(str(item.get("severity", "nit")))
148
+
149
+ snippet_raw = item.get("snippet")
150
+ snippet = snippet_raw.strip() if isinstance(snippet_raw, str) and snippet_raw else None
151
+
152
+ body = item.get("body", "").strip()
153
+ if not body:
154
+ continue
155
+
156
+ reply_to_raw = item.get("reply_to_comment_id")
157
+ reply_to_comment_id = int(reply_to_raw) if isinstance(reply_to_raw, (int, float)) and reply_to_raw else None
158
+
159
+ suggestions.append(UIReviewSuggestion(
160
+ file_path=file_path,
161
+ line=None, # Will be resolved deterministically from snippet
162
+ body=body,
163
+ severity=severity,
164
+ snippet=snippet,
165
+ reply_to_comment_id=reply_to_comment_id,
166
+ ))
167
+
168
+ return suggestions