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.
- {titan_cli-0.2.0 → titan_cli-0.3.2}/PKG-INFO +1 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/git_client.py +20 -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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/diff_service.py +16 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/__init__.py +2 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/diff_operations.py +29 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/commit_step.py +6 -1
- titan_cli-0.3.2/plugins/titan-plugin-git/titan_plugin_git/steps/create_branch_step.py +166 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/diff_summary_step.py +43 -13
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/__init__.py +2 -1
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/agents/code_review_agent.py +168 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/pr_agent.py +14 -8
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/checklists/__init__.py +5 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/checklists/defaults.py +100 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/github_client.py +65 -9
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/pr_service.py +138 -18
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/review_service.py +27 -3
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/managers/__init__.py +15 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/managers/checklist_manager.py +23 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/managers/diff_context_manager.py +572 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/__init__.py +2 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/diff_models.py +130 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/__init__.py +3 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/comment_mapper.py +3 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/pr_mapper.py +63 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/__init__.py +3 -1
- {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
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/review_enums.py +109 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/review_models.py +306 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/models/validators.py +172 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/view.py +46 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/__init__.py +31 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/code_review_operations.py +607 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/comment_operations.py +4 -4
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/context_resolution_operations.py +300 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/findings_operations.py +280 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/manifest_operations.py +191 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/plan_prompt_operations.py +234 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/review_action_operations.py +145 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/operations/thread_resolution_operations.py +337 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/plugin.py +69 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/ai_pr_step.py +2 -3
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/steps/code_review_steps.py +1784 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/create_pr_step.py +2 -2
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/steps/select_cli_step.py +58 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/worktree_steps.py +2 -4
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/__init__.py +2 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/code_block.py +0 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_thread.py +4 -4
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_utils.py +201 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_view.py +360 -0
- 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
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/workflows/review-pr-new-findings.yaml.disabled +91 -0
- titan_cli-0.3.2/plugins/titan-plugin-github/titan_plugin_github/workflows/review-pr-thread-resolution.yaml.disabled +56 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/jira_agent.py +2 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/prompts.py +2 -6
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/jira_client.py +58 -81
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/network/jira_network.py +9 -12
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/issue_service.py +153 -13
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/metadata_service.py +297 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/config/templates/generic_issue.md.j2 +34 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/__init__.py +34 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/defaults.py +18 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/messages.py +161 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants/templates.py +69 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/constants.py +266 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/formatters/markdown_formatter.py +3 -8
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/__init__.py +22 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/enums.py +194 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/formatting.py +3 -16
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/__init__.py +10 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/issue_type_mapper.py +36 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/priority_mapper.py +33 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/status_mapper.py +37 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/user_mapper.py +29 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/version_mapper.py +33 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/__init__.py +2 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/version.py +18 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/view.py +74 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/operations/__init__.py +8 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/operations/issue_formatting_operations.py +7 -8
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/operations/issue_operations.py +142 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/plugin.py +55 -20
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/ai_enhance_issue_description_step.py +233 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/confirm_auto_assign_step.py +67 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/create_generic_issue_step.py +143 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/list_versions_step.py +5 -7
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/prompt_issue_description_step.py +52 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/review_issue_description_step.py +83 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/select_issue_priority_step.py +99 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/steps/select_issue_type_step.py +120 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/utils/__init__.py +3 -0
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/utils/input_validation.py +54 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/utils/saved_queries.py +4 -5
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/utils.py +86 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/workflows/analyze-jira-issues.yaml +2 -10
- titan_cli-0.3.2/plugins/titan-plugin-jira/titan_plugin_jira/workflows/create-generic-issue.yaml +56 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/pyproject.toml +1 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/cli.py +19 -4
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/config.py +18 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/logging/config.py +17 -7
- titan_cli-0.2.0/titan_cli/core/models.py → titan_cli-0.3.2/titan_cli/core/models/__init__.py +2 -2
- titan_cli-0.3.2/titan_cli/core/models/code_review.py +122 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/community.py +250 -22
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/models.py +8 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/plugin_base.py +16 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/plugin_registry.py +87 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/models.py +4 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_registry.py +55 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_sources.py +76 -57
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/builder.py +18 -3
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/context.py +1 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/workflow_executor.py +1 -1
- titan_cli-0.3.2/titan_cli/external_cli/adapters/__init__.py +9 -0
- titan_cli-0.3.2/titan_cli/external_cli/adapters/base.py +78 -0
- titan_cli-0.3.2/titan_cli/external_cli/adapters/claude.py +67 -0
- titan_cli-0.3.2/titan_cli/external_cli/adapters/codex.py +104 -0
- titan_cli-0.3.2/titan_cli/external_cli/adapters/gemini.py +68 -0
- titan_cli-0.3.2/titan_cli/external_cli/adapters/registry.py +46 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/external_cli/configs.py +5 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/__init__.py +11 -7
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/global_setup_wizard.py +2 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/install_plugin_screen.py +115 -59
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/plugin_management.py +153 -40
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/workflow_execution.py +11 -2
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/workflows.py +2 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/textual_workflow_executor.py +1 -1
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_option_list.py +1 -1
- titan_cli-0.3.2/titan_cli/utils/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/utils/autoupdate.py +22 -2
- titan_cli-0.2.0/plugins/titan-plugin-git/titan_plugin_git/steps/create_branch_step.py +0 -141
- titan_cli-0.2.0/plugins/titan-plugin-github/titan_plugin_github/widgets/comment.py +0 -150
- titan_cli-0.2.0/plugins/titan-plugin-github/titan_plugin_github/widgets/comment_utils.py +0 -361
- titan_cli-0.2.0/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/metadata_service.py +0 -172
- {titan_cli-0.2.0 → titan_cli-0.3.2}/LICENSE +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/README.md +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/network/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/network/git_network.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/branch_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/remote_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/stash_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/status_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/tag_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/services/worktree_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/exceptions.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/messages.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/branch_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/commit_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/status_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/tag_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/mappers/worktree_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/branch.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/commit.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/status.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/tag.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/network/worktree.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/branch.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/commit.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/status.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/tag.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/models/view/worktree.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/branch_operations.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/commit_operations.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/plugin.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/__init__.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/branch_steps.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/checkout_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/create_worktree_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/pull_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/push_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/remove_worktree_step.py +0 -0
- {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
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/status_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/worktree_command_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/workflows/__previews__/__init__.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/workflows/commit-ai.yaml +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/config_loader.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/agents/issue_generator.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/gh_network.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/graphql_network.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/network/graphql_queries.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/protocols.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/issue_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/clients/services/team_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/config/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/config/pr_agent.toml +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/exceptions.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/messages.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/formatting.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/issue_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/review_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/mappers/thread_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/__init__.py +0 -0
- {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
- {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
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/graphql/user.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/issue.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/review.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/models/network/rest/user.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/issue_operations.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/pr_creation_operations.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/pr_operations.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/operations/worktree_operations.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/github_prompt_steps.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/issue_steps.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/pr_review_steps.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/steps/preview_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/utils.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/widgets/reply_comment.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/__previews__/__init__.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/create-issue-ai.yaml +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-github/titan_plugin_github/workflows/create-pr-ai.yaml +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/config_loader.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/response_parser.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/token_tracker.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/agents/validators.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/network/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/comment_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/link_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/project_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/clients/services/transition_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/config/jira_agent.toml +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/exceptions.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/formatters/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/messages.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/comment_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/issue_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/project_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/mappers/transition_mapper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/comment.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/issue.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/priority.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/project.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/status.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/transition.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/models/network/rest/user.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/operations/jql_operations.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/get_issue_step.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/steps/search_jql_step.py +0 -0
- {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
- {titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-jira/titan_plugin_jira/utils/issue_sorter.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/__main__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/agents/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/agents/base.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/client.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/constants.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/exceptions.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/llm_tools.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/models.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/oauth_helper.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/anthropic.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/base.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ai/providers/gemini.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/clients/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/clients/gcloud_client.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/discovery.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/errors.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/logging/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/logging/decorators.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/plugins/available.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/result.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/secrets.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/utils.py +0 -0
- {titan_cli-0.2.0/titan_cli/external_cli → titan_cli-0.3.2/titan_cli/core/validators}/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/project_step_source.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_exceptions.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/core/workflows/workflow_filter_service.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/mock_context.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/results.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/steps/ai_assistant_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/steps/command_step.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/utils/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/engine/utils/venv.py +0 -0
- {titan_cli-0.2.0/titan_cli/utils → titan_cli-0.3.2/titan_cli/external_cli}/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/external_cli/launcher.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/messages.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/__previews__/statusbar_preview.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/app.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/colors.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/icons.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/ai_config.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/ai_config_wizard.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/base.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/cli_launcher.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/main_menu.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/plugin_config_wizard.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/screens/project_setup_wizard.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/textual_components.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/theme.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/__init__.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/button.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/decision_badge.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/header.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/multiline_input.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/panel.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/panel_container.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_choice.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_input.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_selection_list.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/prompt_textarea.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/status_bar.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/step_container.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/styled_option_list.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/table.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/text.py +0 -0
- {titan_cli-0.2.0 → titan_cli-0.3.2}/titan_cli/ui/tui/widgets/wizard.py +0 -0
{titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/clients/git_client.py
RENAMED
|
@@ -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
|
-
"""
|
|
308
|
-
|
|
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
|
-
|
|
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"{
|
|
171
|
+
["git", "diff", f"-U{context_lines}", f"{base_ref}...{head_ref}"],
|
|
158
172
|
check=False
|
|
159
173
|
)
|
|
160
174
|
return ClientSuccess(
|
{titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/operations/__init__.py
RENAMED
|
@@ -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",
|
{titan_cli-0.2.0 → titan_cli-0.3.2}/plugins/titan-plugin-git/titan_plugin_git/steps/commit_step.py
RENAMED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
13
|
-
before generating commit messages.
|
|
14
|
+
Saves selected file paths to ctx.data["selected_files"].
|
|
14
15
|
|
|
15
16
|
Returns:
|
|
16
|
-
Success:
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
|
@@ -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
|