mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Merge branch 'main' into will/edit-w-checkpoints
This commit is contained in:
commit
6657a7d894
57 changed files with 1504 additions and 148 deletions
142
.roo/rules-merge-resolver/1_workflow.xml
Normal file
142
.roo/rules-merge-resolver/1_workflow.xml
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<merge_resolver_workflow>
|
||||
<mode_overview>
|
||||
This mode resolves merge conflicts for a specific pull request by analyzing git history,
|
||||
commit messages, and code changes to make intelligent resolution decisions. It receives
|
||||
a PR number (e.g., "#123") and handles the entire conflict resolution process.
|
||||
</mode_overview>
|
||||
|
||||
<initialization_steps>
|
||||
<step number="1">
|
||||
<action>Parse PR number from user input</action>
|
||||
<details>
|
||||
Extract the PR number from input like "#123" or "PR #123"
|
||||
Validate that a PR number was provided
|
||||
</details>
|
||||
</step>
|
||||
|
||||
<step number="2">
|
||||
<action>Fetch PR information</action>
|
||||
<tools>
|
||||
<tool>gh pr view [PR_NUMBER] --json title,body,headRefName,baseRefName</tool>
|
||||
</tools>
|
||||
<details>
|
||||
Get PR title and description to understand the intent
|
||||
Identify the source and target branches
|
||||
</details>
|
||||
</step>
|
||||
|
||||
<step number="3">
|
||||
<action>Checkout PR branch and prepare for rebase</action>
|
||||
<tools>
|
||||
<tool>gh pr checkout [PR_NUMBER] --force</tool>
|
||||
<tool>git fetch origin main</tool>
|
||||
<tool>git rebase origin/main</tool>
|
||||
</tools>
|
||||
<details>
|
||||
Force checkout the PR branch to ensure clean state
|
||||
Fetch the latest main branch
|
||||
Attempt to rebase onto main to reveal conflicts
|
||||
</details>
|
||||
</step>
|
||||
|
||||
<step number="4">
|
||||
<action>Check for merge conflicts</action>
|
||||
<tools>
|
||||
<tool>git status --porcelain</tool>
|
||||
<tool>git diff --name-only --diff-filter=U</tool>
|
||||
</tools>
|
||||
<details>
|
||||
Identify files with merge conflicts (marked with 'UU')
|
||||
Create a list of files that need resolution
|
||||
</details>
|
||||
</step>
|
||||
</initialization_steps>
|
||||
|
||||
<main_workflow>
|
||||
<phase name="conflict_analysis">
|
||||
<description>Analyze each conflicted file to understand the changes</description>
|
||||
<steps>
|
||||
<step>Read the conflicted file to identify conflict markers</step>
|
||||
<step>Extract the conflicting sections between <<<<<<< and >>>>>>></step>
|
||||
<step>Run git blame on both sides of the conflict</step>
|
||||
<step>Fetch commit messages and diffs for relevant commits</step>
|
||||
<step>Analyze the intent behind each change</step>
|
||||
</steps>
|
||||
</phase>
|
||||
|
||||
<phase name="resolution_strategy">
|
||||
<description>Determine the best resolution strategy for each conflict</description>
|
||||
<steps>
|
||||
<step>Categorize changes by intent (bugfix, feature, refactor, etc.)</step>
|
||||
<step>Evaluate recency and relevance of changes</step>
|
||||
<step>Check for structural overlap vs formatting differences</step>
|
||||
<step>Identify if changes can be combined or if one should override</step>
|
||||
<step>Consider test updates and related changes</step>
|
||||
</steps>
|
||||
</phase>
|
||||
|
||||
<phase name="conflict_resolution">
|
||||
<description>Apply the resolution strategy to resolve conflicts</description>
|
||||
<steps>
|
||||
<step>For each conflict, apply the chosen resolution</step>
|
||||
<step>Ensure proper escaping of conflict markers in diffs</step>
|
||||
<step>Validate that resolved code is syntactically correct</step>
|
||||
<step>Stage resolved files with git add</step>
|
||||
</steps>
|
||||
</phase>
|
||||
|
||||
<phase name="validation">
|
||||
<description>Verify the resolution and prepare for commit</description>
|
||||
<steps>
|
||||
<step>Run git status to confirm all conflicts are resolved</step>
|
||||
<step>Check for any compilation or syntax errors</step>
|
||||
<step>Review the final diff to ensure sensible resolutions</step>
|
||||
<step>Prepare a summary of resolution decisions</step>
|
||||
</steps>
|
||||
</phase>
|
||||
</main_workflow>
|
||||
|
||||
<git_commands>
|
||||
<command name="checkout_pr">
|
||||
<syntax>gh pr checkout [PR_NUMBER] --force</syntax>
|
||||
<purpose>Force checkout the PR branch to ensure clean state</purpose>
|
||||
</command>
|
||||
|
||||
<command name="fetch_main">
|
||||
<syntax>git fetch origin main</syntax>
|
||||
<purpose>Get the latest main branch from origin</purpose>
|
||||
</command>
|
||||
|
||||
<command name="rebase_main">
|
||||
<syntax>git rebase origin/main</syntax>
|
||||
<purpose>Rebase current branch onto main to reveal conflicts</purpose>
|
||||
</command>
|
||||
|
||||
<command name="get_blame_info">
|
||||
<syntax>git blame -L [start_line],[end_line] [commit_sha] -- [file_path]</syntax>
|
||||
<purpose>Get commit information for specific lines</purpose>
|
||||
</command>
|
||||
|
||||
<command name="get_commit_details">
|
||||
<syntax>git show --format="%H%n%an%n%ae%n%ad%n%s%n%b" --no-patch [commit_sha]</syntax>
|
||||
<purpose>Get commit metadata including message</purpose>
|
||||
</command>
|
||||
|
||||
<command name="get_commit_diff">
|
||||
<syntax>git show [commit_sha] -- [file_path]</syntax>
|
||||
<purpose>Get the actual changes made in a commit</purpose>
|
||||
</command>
|
||||
|
||||
<command name="check_merge_status">
|
||||
<syntax>git ls-files -u</syntax>
|
||||
<purpose>List unmerged files with stage information</purpose>
|
||||
</command>
|
||||
</git_commands>
|
||||
|
||||
<completion_criteria>
|
||||
<criterion>All merge conflicts have been resolved</criterion>
|
||||
<criterion>Resolved files have been staged</criterion>
|
||||
<criterion>No syntax errors in resolved code</criterion>
|
||||
<criterion>Resolution decisions are documented</criterion>
|
||||
</completion_criteria>
|
||||
</merge_resolver_workflow>
|
||||
165
.roo/rules-merge-resolver/2_best_practices.xml
Normal file
165
.roo/rules-merge-resolver/2_best_practices.xml
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<merge_resolver_best_practices>
|
||||
<general_principles>
|
||||
<principle priority="high">
|
||||
<name>Intent-Based Resolution</name>
|
||||
<description>
|
||||
Always prioritize understanding the intent behind changes rather than
|
||||
just looking at the code differences. Commit messages, PR descriptions,
|
||||
and issue references provide crucial context.
|
||||
</description>
|
||||
<rationale>
|
||||
Code changes have purpose - bugfixes should be preserved, features
|
||||
should be integrated properly, and refactors should maintain consistency.
|
||||
</rationale>
|
||||
<example>
|
||||
<scenario>Conflict between a bugfix and a refactor</scenario>
|
||||
<good>Apply the bugfix logic within the refactored structure</good>
|
||||
<bad>Simply choose one side without considering both intents</bad>
|
||||
</example>
|
||||
</principle>
|
||||
|
||||
<principle priority="high">
|
||||
<name>Preserve All Valuable Changes</name>
|
||||
<description>
|
||||
When possible, combine non-conflicting changes from both sides rather
|
||||
than discarding one side entirely.
|
||||
</description>
|
||||
<rationale>
|
||||
Both sides of a conflict often contain valuable changes that can coexist
|
||||
if properly integrated.
|
||||
</rationale>
|
||||
</principle>
|
||||
|
||||
<principle priority="high">
|
||||
<name>Escape Conflict Markers</name>
|
||||
<description>
|
||||
When using apply_diff or search_and_replace tools, always escape merge
|
||||
conflict markers with backslashes to prevent parsing errors.
|
||||
</description>
|
||||
<example><![CDATA[
|
||||
Correct: \<<<<<<< HEAD
|
||||
Wrong: <<<<<<< HEAD
|
||||
]]></example>
|
||||
</principle>
|
||||
|
||||
<principle priority="medium">
|
||||
<name>Consider Related Changes</name>
|
||||
<description>
|
||||
Look beyond the immediate conflict to understand related changes in
|
||||
tests, documentation, or dependent code.
|
||||
</description>
|
||||
<rationale>
|
||||
A change might seem isolated but could be part of a larger feature
|
||||
or fix that spans multiple files.
|
||||
</rationale>
|
||||
</principle>
|
||||
</general_principles>
|
||||
|
||||
<resolution_heuristics>
|
||||
<heuristic category="bugfix_vs_feature">
|
||||
<rule>Bugfixes generally take precedence over features</rule>
|
||||
<reasoning>
|
||||
Bugfixes address existing problems and should be preserved,
|
||||
while features can be reintegrated around the fix.
|
||||
</reasoning>
|
||||
</heuristic>
|
||||
|
||||
<heuristic category="recent_vs_old">
|
||||
<rule>More recent changes are often more relevant</rule>
|
||||
<reasoning>
|
||||
Recent changes likely reflect the current understanding of
|
||||
requirements and may supersede older implementations.
|
||||
</reasoning>
|
||||
<exception>
|
||||
When older changes are bugfixes or security patches that
|
||||
haven't been addressed in newer code.
|
||||
</exception>
|
||||
</heuristic>
|
||||
|
||||
<heuristic category="test_updates">
|
||||
<rule>Changes that include test updates are likely more complete</rule>
|
||||
<reasoning>
|
||||
Developers who update tests alongside code changes demonstrate
|
||||
thoroughness and understanding of the impact.
|
||||
</reasoning>
|
||||
</heuristic>
|
||||
|
||||
<heuristic category="formatting_vs_logic">
|
||||
<rule>Logic changes take precedence over formatting changes</rule>
|
||||
<reasoning>
|
||||
Formatting can be reapplied, but logic changes represent
|
||||
functional improvements or fixes.
|
||||
</reasoning>
|
||||
</heuristic>
|
||||
</resolution_heuristics>
|
||||
|
||||
<common_pitfalls>
|
||||
<pitfall>
|
||||
<description>Blindly choosing one side without analysis</description>
|
||||
<why_problematic>
|
||||
You might lose important changes or introduce regressions
|
||||
</why_problematic>
|
||||
<correct_approach>
|
||||
Always analyze both sides using git blame and commit history
|
||||
</correct_approach>
|
||||
</pitfall>
|
||||
|
||||
<pitfall>
|
||||
<description>Ignoring the PR description and context</description>
|
||||
<why_problematic>
|
||||
The PR description often explains the why behind changes,
|
||||
which is crucial for proper resolution
|
||||
</why_problematic>
|
||||
<correct_approach>
|
||||
Always fetch and read the PR information before resolving
|
||||
</correct_approach>
|
||||
</pitfall>
|
||||
|
||||
<pitfall>
|
||||
<description>Not validating the resolved code</description>
|
||||
<why_problematic>
|
||||
Merged code might be syntactically incorrect or introduce
|
||||
logical errors
|
||||
</why_problematic>
|
||||
<correct_approach>
|
||||
Always check for syntax errors and review the final diff
|
||||
</correct_approach>
|
||||
</pitfall>
|
||||
|
||||
<pitfall>
|
||||
<description>Not escaping conflict markers in diffs</description>
|
||||
<why_problematic>
|
||||
Unescaped conflict markers (<<<<<<, =======, >>>>>>) in SEARCH
|
||||
or REPLACE sections will be interpreted as actual diff syntax,
|
||||
causing the apply_diff tool to fail or produce incorrect results
|
||||
</why_problematic>
|
||||
<correct_approach>
|
||||
Always escape conflict markers with a backslash (\) when they
|
||||
appear in the content you're searching for or replacing.
|
||||
Example: \<<<<<<< HEAD instead of <<<<<<< HEAD
|
||||
</correct_approach>
|
||||
</pitfall>
|
||||
</common_pitfalls>
|
||||
|
||||
<quality_checklist>
|
||||
<category name="before_resolution">
|
||||
<item>Fetch PR title and description for context</item>
|
||||
<item>Identify all files with conflicts</item>
|
||||
<item>Understand the overall change being merged</item>
|
||||
</category>
|
||||
|
||||
<category name="during_resolution">
|
||||
<item>Run git blame on conflicting sections</item>
|
||||
<item>Read commit messages for intent</item>
|
||||
<item>Consider if changes can be combined</item>
|
||||
<item>Escape conflict markers in diffs</item>
|
||||
</category>
|
||||
|
||||
<category name="after_resolution">
|
||||
<item>Verify no conflict markers remain</item>
|
||||
<item>Check for syntax/compilation errors</item>
|
||||
<item>Review the complete diff</item>
|
||||
<item>Document resolution decisions</item>
|
||||
</category>
|
||||
</quality_checklist>
|
||||
</merge_resolver_best_practices>
|
||||
228
.roo/rules-merge-resolver/3_tool_usage.xml
Normal file
228
.roo/rules-merge-resolver/3_tool_usage.xml
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
<merge_resolver_tool_usage>
|
||||
<tool_priorities>
|
||||
<priority level="1">
|
||||
<tool>execute_command</tool>
|
||||
<when>For all git and gh CLI operations</when>
|
||||
<why>Git commands provide the historical context needed for intelligent resolution</why>
|
||||
</priority>
|
||||
|
||||
<priority level="2">
|
||||
<tool>read_file</tool>
|
||||
<when>To examine conflicted files and understand the conflict structure</when>
|
||||
<why>Need to see the actual conflict markers and code</why>
|
||||
</priority>
|
||||
|
||||
<priority level="3">
|
||||
<tool>apply_diff or search_and_replace</tool>
|
||||
<when>To resolve conflicts by replacing conflicted sections</when>
|
||||
<why>Precise editing of specific conflict blocks</why>
|
||||
</priority>
|
||||
</tool_priorities>
|
||||
|
||||
<tool_specific_guidance>
|
||||
<tool name="execute_command">
|
||||
<best_practices>
|
||||
<practice>Always use gh CLI for GitHub operations instead of MCP tools</practice>
|
||||
<practice>Chain git commands with && for efficiency</practice>
|
||||
<practice>Use --format options for structured output</practice>
|
||||
<practice>Capture command output for parsing</practice>
|
||||
</best_practices>
|
||||
|
||||
<common_commands>
|
||||
<command>
|
||||
<purpose>Get PR information</purpose>
|
||||
<syntax>gh pr view [PR_NUMBER] --json title,body,headRefName,baseRefName</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Checkout PR branch</purpose>
|
||||
<syntax>gh pr checkout [PR_NUMBER] --force</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Fetch latest main branch</purpose>
|
||||
<syntax>git fetch origin main</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Rebase onto main to reveal conflicts</purpose>
|
||||
<syntax>git rebase origin/main</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Check conflict status</purpose>
|
||||
<syntax>git status --porcelain | grep "^UU"</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Get blame for specific lines</purpose>
|
||||
<syntax>git blame -L [start],[end] HEAD -- [file] | cut -d' ' -f1</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Get commit message</purpose>
|
||||
<syntax>git log -1 --format="%s%n%n%b" [commit_sha]</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Stage resolved file</purpose>
|
||||
<syntax>git add [file_path]</syntax>
|
||||
</command>
|
||||
|
||||
<command>
|
||||
<purpose>Continue rebase after resolution</purpose>
|
||||
<syntax>git rebase --continue</syntax>
|
||||
</command>
|
||||
</common_commands>
|
||||
</tool>
|
||||
|
||||
<tool name="read_file">
|
||||
<best_practices>
|
||||
<practice>Read the entire conflicted file first to understand structure</practice>
|
||||
<practice>Note line numbers of conflict markers for precise editing</practice>
|
||||
<practice>Identify the pattern of conflicts (multiple vs single)</practice>
|
||||
</best_practices>
|
||||
|
||||
<conflict_parsing>
|
||||
<marker><<<<<<< HEAD - Start of current branch changes</marker>
|
||||
<marker>======= - Separator between versions</marker>
|
||||
<marker>>>>>>>> [branch] - End of incoming changes</marker>
|
||||
</conflict_parsing>
|
||||
</tool>
|
||||
|
||||
<tool name="apply_diff">
|
||||
<best_practices>
|
||||
<practice>Always escape conflict markers with backslash</practice>
|
||||
<practice>Include enough context to ensure unique matches</practice>
|
||||
<practice>Use :start_line: for precision</practice>
|
||||
<practice>Combine multiple resolutions in one diff when possible</practice>
|
||||
</best_practices>
|
||||
|
||||
<example><![CDATA[
|
||||
<apply_diff>
|
||||
<path>src/feature.ts</path>
|
||||
<diff>
|
||||
<<<<<<< SEARCH
|
||||
:start_line:45
|
||||
-------
|
||||
\<<<<<<< HEAD
|
||||
function oldImplementation() {
|
||||
return "old";
|
||||
}
|
||||
\=======
|
||||
function newImplementation() {
|
||||
return "new";
|
||||
}
|
||||
\>>>>>>> feature-branch
|
||||
=======
|
||||
function mergedImplementation() {
|
||||
// Combining both approaches
|
||||
return "merged";
|
||||
}
|
||||
>>>>>>> REPLACE
|
||||
</diff>
|
||||
</apply_diff>
|
||||
]]></example>
|
||||
</tool>
|
||||
|
||||
<tool name="search_and_replace">
|
||||
<best_practices>
|
||||
<practice>Use for simple conflict resolutions</practice>
|
||||
<practice>Enable regex mode for complex patterns</practice>
|
||||
<practice>Always escape special characters</practice>
|
||||
</best_practices>
|
||||
|
||||
<example><![CDATA[
|
||||
<search_and_replace>
|
||||
<path>src/config.ts</path>
|
||||
<search>\<<<<<<< HEAD[\s\S]*?\>>>>>>> \w+</search>
|
||||
<replace>// Resolved configuration
|
||||
const config = {
|
||||
// Merged settings from both branches
|
||||
}</replace>
|
||||
<use_regex>true</use_regex>
|
||||
</search_and_replace>
|
||||
]]></example>
|
||||
</tool>
|
||||
</tool_specific_guidance>
|
||||
|
||||
<tool_combination_patterns>
|
||||
<pattern name="initialize_pr_resolution">
|
||||
<sequence>
|
||||
<step>execute_command - Get PR info with gh CLI</step>
|
||||
<step>execute_command - Checkout PR with gh pr checkout --force</step>
|
||||
<step>execute_command - Fetch origin main</step>
|
||||
<step>execute_command - Rebase onto origin/main</step>
|
||||
<step>execute_command - Check for conflicts with git status</step>
|
||||
</sequence>
|
||||
</pattern>
|
||||
|
||||
<pattern name="analyze_conflict">
|
||||
<sequence>
|
||||
<step>execute_command - List conflicted files</step>
|
||||
<step>read_file - Examine conflict structure</step>
|
||||
<step>execute_command - Git blame on conflict regions</step>
|
||||
<step>execute_command - Fetch commit messages</step>
|
||||
</sequence>
|
||||
</pattern>
|
||||
|
||||
<pattern name="resolve_conflict">
|
||||
<sequence>
|
||||
<step>read_file - Get exact conflict content</step>
|
||||
<step>apply_diff - Replace conflict with resolution</step>
|
||||
<step>execute_command - Stage resolved file</step>
|
||||
<step>execute_command - Verify resolution status</step>
|
||||
</sequence>
|
||||
</pattern>
|
||||
|
||||
<pattern name="complete_rebase">
|
||||
<sequence>
|
||||
<step>execute_command - Check all conflicts resolved</step>
|
||||
<step>execute_command - Continue rebase with git rebase --continue</step>
|
||||
<step>execute_command - Verify clean status</step>
|
||||
</sequence>
|
||||
</pattern>
|
||||
</tool_combination_patterns>
|
||||
|
||||
<error_handling>
|
||||
<scenario name="no_conflicts_after_rebase">
|
||||
<description>Rebase completes without conflicts</description>
|
||||
<approach>
|
||||
Inform user that PR can be merged without conflicts
|
||||
No resolution needed
|
||||
</approach>
|
||||
</scenario>
|
||||
|
||||
<scenario name="rebase_in_progress">
|
||||
<description>A rebase is already in progress</description>
|
||||
<approach>
|
||||
Check status with git status
|
||||
Either continue existing rebase or abort with git rebase --abort
|
||||
</approach>
|
||||
</scenario>
|
||||
|
||||
<scenario name="malformed_conflicts">
|
||||
<description>Conflict markers are incomplete or nested</description>
|
||||
<approach>
|
||||
Use search_and_replace with careful regex patterns
|
||||
Manual inspection may be required
|
||||
</approach>
|
||||
</scenario>
|
||||
|
||||
<scenario name="binary_conflicts">
|
||||
<description>Binary files cannot be merged automatically</description>
|
||||
<approach>
|
||||
Identify which version to keep based on PR intent
|
||||
Use git checkout --theirs or --ours
|
||||
</approach>
|
||||
</scenario>
|
||||
|
||||
<scenario name="escaped_markers">
|
||||
<description>Code contains literal conflict marker strings</description>
|
||||
<approach>
|
||||
Extra careful escaping in diffs
|
||||
Consider using search_and_replace with precise patterns
|
||||
</approach>
|
||||
</scenario>
|
||||
</error_handling>
|
||||
</merge_resolver_tool_usage>
|
||||
315
.roo/rules-merge-resolver/4_complete_example.xml
Normal file
315
.roo/rules-merge-resolver/4_complete_example.xml
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
<merge_resolver_example>
|
||||
<scenario>
|
||||
User provides PR #123 which has merge conflicts between a bugfix branch
|
||||
and a feature branch that refactored the same code.
|
||||
</scenario>
|
||||
|
||||
<user_request>
|
||||
#123
|
||||
</user_request>
|
||||
|
||||
<workflow>
|
||||
<step number="1">
|
||||
<description>Parse PR number and fetch PR information</description>
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>gh pr view 123 --json title,body,headRefName,baseRefName</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
{
|
||||
"title": "Fix memory leak in data processor",
|
||||
"body": "This PR fixes a memory leak that occurs when processing large datasets. The leak was caused by event listeners not being properly removed.",
|
||||
"headRefName": "fix/memory-leak",
|
||||
"baseRefName": "main"
|
||||
}
|
||||
]]></expected_output>
|
||||
<analysis>
|
||||
The PR is a bugfix for a memory leak issue. This context will help
|
||||
prioritize preserving the fix during conflict resolution.
|
||||
</analysis>
|
||||
</step>
|
||||
|
||||
<step number="2">
|
||||
<description>Checkout PR branch and prepare for rebase</description>
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>gh pr checkout 123 --force</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
Switched to branch 'fix/memory-leak'
|
||||
Your branch is up to date with 'origin/fix/memory-leak'.
|
||||
]]></expected_output>
|
||||
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git fetch origin main</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
From github.com:user/repo
|
||||
* branch main -> FETCH_HEAD
|
||||
]]></expected_output>
|
||||
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git rebase origin/main</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
Auto-merging src/data/processor.ts
|
||||
CONFLICT (content): Merge conflict in src/data/processor.ts
|
||||
Auto-merging src/data/processor.test.ts
|
||||
CONFLICT (content): Merge conflict in src/data/processor.test.ts
|
||||
error: could not apply abc123... Fix memory leak in data processor
|
||||
Resolve all conflicts manually, mark them as resolved with
|
||||
"git add/rm <conflicted_files>", then run "git rebase --continue".
|
||||
]]></expected_output>
|
||||
</step>
|
||||
|
||||
<step number="3">
|
||||
<description>Check for merge conflicts</description>
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git status --porcelain | grep "^UU"</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
UU src/data/processor.ts
|
||||
UU src/data/processor.test.ts
|
||||
]]></expected_output>
|
||||
<analysis>
|
||||
Two files have conflicts: the main processor file and its test file.
|
||||
Both need to be resolved before continuing the rebase.
|
||||
</analysis>
|
||||
</step>
|
||||
|
||||
<step number="4">
|
||||
<description>Examine the conflicted processor file</description>
|
||||
<tool_use><![CDATA[
|
||||
<read_file>
|
||||
<path>src/data/processor.ts</path>
|
||||
</read_file>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
45 | export class DataProcessor {
|
||||
46 | private listeners: Map<string, EventListener> = new Map();
|
||||
47 |
|
||||
48 | <<<<<<< HEAD
|
||||
49 | async processData(data: DataInput): Promise<ProcessedData> {
|
||||
50 | // Refactored to use async/await
|
||||
51 | const result = await this.transform(data);
|
||||
52 | return result;
|
||||
53 | }
|
||||
54 | =======
|
||||
55 | processData(data: any[]): ProcessedData {
|
||||
56 | const listener = this.createListener();
|
||||
57 | this.listeners.set(data.id, listener);
|
||||
58 |
|
||||
59 | return this.transform(data);
|
||||
60 | }
|
||||
61 | >>>>>>> abc123 (Fix memory leak in data processor)
|
||||
62 |
|
||||
63 | cleanup() {
|
||||
64 | <<<<<<< HEAD
|
||||
65 | // TODO: Implement cleanup
|
||||
66 | =======
|
||||
67 | // Fix: Clear all listeners to prevent memory leak
|
||||
68 | this.listeners.forEach(listener => {
|
||||
69 | listener.removeAllListeners();
|
||||
70 | });
|
||||
71 | this.listeners.clear();
|
||||
72 | >>>>>>> abc123 (Fix memory leak in data processor)
|
||||
73 | }
|
||||
74 | }
|
||||
]]></expected_output>
|
||||
</step>
|
||||
|
||||
<step number="5">
|
||||
<description>Analyze the conflicts using git blame</description>
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git blame -L 49,53 HEAD -- src/data/processor.ts | cut -d' ' -f1 | sort -u | xargs -I {} git log -1 --format="%h %s" {}</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
def456 Refactor: Convert processData to async/await pattern
|
||||
]]></expected_output>
|
||||
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git log -1 --format="%h %s" abc123</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
abc123 Fix: Add listener cleanup to prevent memory leak
|
||||
]]></expected_output>
|
||||
|
||||
<analysis>
|
||||
HEAD (main after rebase): Has async/await refactor but missing listener logic
|
||||
Incoming (bugfix branch): Adds listener tracking and cleanup for memory leak fix
|
||||
|
||||
Resolution strategy: Combine both changes - keep async/await refactor
|
||||
but include the listener tracking and cleanup logic.
|
||||
</analysis>
|
||||
</step>
|
||||
|
||||
<step number="6">
|
||||
<description>Resolve the conflicts</description>
|
||||
<tool_use><![CDATA[
|
||||
<apply_diff>
|
||||
<path>src/data/processor.ts</path>
|
||||
<diff>
|
||||
<<<<<<< SEARCH
|
||||
:start_line:48
|
||||
-------
|
||||
\<<<<<<< HEAD
|
||||
async processData(data: DataInput): Promise<ProcessedData> {
|
||||
// Refactored to use async/await
|
||||
const result = await this.transform(data);
|
||||
return result;
|
||||
}
|
||||
\=======
|
||||
processData(data: any[]): ProcessedData {
|
||||
const listener = this.createListener();
|
||||
this.listeners.set(data.id, listener);
|
||||
|
||||
return this.transform(data);
|
||||
}
|
||||
\>>>>>>> abc123 (Fix memory leak in data processor)
|
||||
=======
|
||||
async processData(data: DataInput): Promise<ProcessedData> {
|
||||
// Create and track listener for cleanup (memory leak fix)
|
||||
const listener = this.createListener();
|
||||
this.listeners.set(data.id, listener);
|
||||
|
||||
// Refactored to use async/await
|
||||
const result = await this.transform(data);
|
||||
return result;
|
||||
}
|
||||
>>>>>>> REPLACE
|
||||
|
||||
<<<<<<< SEARCH
|
||||
:start_line:63
|
||||
-------
|
||||
cleanup() {
|
||||
\<<<<<<< HEAD
|
||||
// TODO: Implement cleanup
|
||||
\=======
|
||||
// Fix: Clear all listeners to prevent memory leak
|
||||
this.listeners.forEach(listener => {
|
||||
listener.removeAllListeners();
|
||||
});
|
||||
this.listeners.clear();
|
||||
\>>>>>>> abc123 (Fix memory leak in data processor)
|
||||
}
|
||||
=======
|
||||
cleanup() {
|
||||
// Fix: Clear all listeners to prevent memory leak
|
||||
this.listeners.forEach(listener => {
|
||||
listener.removeAllListeners();
|
||||
});
|
||||
this.listeners.clear();
|
||||
}
|
||||
>>>>>>> REPLACE
|
||||
</diff>
|
||||
</apply_diff>
|
||||
]]></tool_use>
|
||||
<explanation>
|
||||
Combined both changes: kept the async/await refactor from main
|
||||
while preserving the memory leak fix (listener tracking and cleanup)
|
||||
from the bugfix branch.
|
||||
</explanation>
|
||||
</step>
|
||||
|
||||
<step number="7">
|
||||
<description>Resolve test file conflicts</description>
|
||||
<tool_use><![CDATA[
|
||||
<read_file>
|
||||
<path>src/data/processor.test.ts</path>
|
||||
</read_file>
|
||||
]]></tool_use>
|
||||
<!-- Similar process for test file -->
|
||||
<tool_use><![CDATA[
|
||||
<apply_diff>
|
||||
<path>src/data/processor.test.ts</path>
|
||||
<diff>
|
||||
<!-- Test resolution would go here -->
|
||||
</diff>
|
||||
</apply_diff>
|
||||
]]></tool_use>
|
||||
</step>
|
||||
|
||||
<step number="8">
|
||||
<description>Stage resolved files and continue rebase</description>
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git add src/data/processor.ts src/data/processor.test.ts</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git rebase --continue</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
[detached HEAD def789] Fix memory leak in data processor
|
||||
2 files changed, 12 insertions(+), 2 deletions(-)
|
||||
Successfully rebased and updated refs/heads/fix/memory-leak.
|
||||
]]></expected_output>
|
||||
</step>
|
||||
|
||||
<step number="9">
|
||||
<description>Final validation</description>
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git status</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
On branch fix/memory-leak
|
||||
Your branch is ahead of 'origin/fix/memory-leak' by 1 commit.
|
||||
(use "git push" to publish your local commits)
|
||||
|
||||
nothing to commit, working tree clean
|
||||
]]></expected_output>
|
||||
|
||||
<tool_use><![CDATA[
|
||||
<execute_command>
|
||||
<command>git diff origin/main --stat</command>
|
||||
</execute_command>
|
||||
]]></tool_use>
|
||||
<expected_output><![CDATA[
|
||||
src/data/processor.ts | 8 ++++++--
|
||||
src/data/processor.test.ts | 4 ++--
|
||||
2 files changed, 8 insertions(+), 4 deletions(-)
|
||||
]]></expected_output>
|
||||
</step>
|
||||
</workflow>
|
||||
|
||||
<completion><![CDATA[
|
||||
<attempt_completion>
|
||||
<result>
|
||||
Successfully resolved merge conflicts for PR #123 "Fix memory leak in data processor".
|
||||
|
||||
Resolution Summary:
|
||||
- src/data/processor.ts: Combined the async/await refactor with the memory leak fix by preserving listener tracking and cleanup logic within the refactored async method
|
||||
- src/data/processor.test.ts: Updated tests to work with the async implementation while maintaining memory leak test coverage
|
||||
|
||||
Both the feature refactor and the critical bugfix have been preserved in the resolution. The rebase has been completed successfully and the branch is ready to be pushed.
|
||||
</result>
|
||||
</attempt_completion>
|
||||
]]></completion>
|
||||
|
||||
<key_takeaways>
|
||||
<takeaway>Always checkout PR with --force and rebase to reveal conflicts</takeaway>
|
||||
<takeaway>Fetch PR context to understand the intent of changes</takeaway>
|
||||
<takeaway>Use git blame and commit messages to understand the history</takeaway>
|
||||
<takeaway>Combine non-conflicting improvements when possible</takeaway>
|
||||
<takeaway>Prioritize bugfixes while accommodating refactors</takeaway>
|
||||
<takeaway>Complete the rebase process with git rebase --continue</takeaway>
|
||||
<takeaway>Validate that both sets of changes work together</takeaway>
|
||||
</key_takeaways>
|
||||
</merge_resolver_example>
|
||||
153
.roo/rules-merge-resolver/5_communication.xml
Normal file
153
.roo/rules-merge-resolver/5_communication.xml
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<merge_resolver_communication>
|
||||
<tone_and_style>
|
||||
<principle>Be direct and technical when explaining resolution decisions</principle>
|
||||
<principle>Focus on the rationale behind each conflict resolution</principle>
|
||||
<principle>Provide clear summaries of what was merged and why</principle>
|
||||
|
||||
<avoid>
|
||||
<phrase>I'll help you resolve these conflicts...</phrase>
|
||||
<phrase>Let me handle this for you...</phrase>
|
||||
<phrase>Don't worry about the conflicts...</phrase>
|
||||
</avoid>
|
||||
|
||||
<prefer>
|
||||
<phrase>Analyzing PR #123 for merge conflicts...</phrase>
|
||||
<phrase>Resolving conflicts based on commit history analysis...</phrase>
|
||||
<phrase>Applied resolution strategy: [specific strategy]</phrase>
|
||||
</prefer>
|
||||
</tone_and_style>
|
||||
|
||||
<initial_response>
|
||||
<structure>
|
||||
<element>Acknowledge the PR number</element>
|
||||
<element>State that you're fetching PR information</element>
|
||||
<element>Indicate the analysis will begin</element>
|
||||
</structure>
|
||||
|
||||
<example>
|
||||
Fetching information for PR #123 to understand the context and identify merge conflicts...
|
||||
</example>
|
||||
</initial_response>
|
||||
|
||||
<progress_updates>
|
||||
<when>During each major phase of resolution</when>
|
||||
<format>
|
||||
<update>Analyzing [X] conflicted files...</update>
|
||||
<update>Running git blame on [file] to understand change history...</update>
|
||||
<update>Resolving conflicts in [file] by [strategy]...</update>
|
||||
<update>Validating resolved changes...</update>
|
||||
</format>
|
||||
|
||||
<include_details>
|
||||
<detail>Number of conflicts found</detail>
|
||||
<detail>Files being processed</detail>
|
||||
<detail>Resolution strategy being applied</detail>
|
||||
</include_details>
|
||||
</progress_updates>
|
||||
|
||||
<conflict_explanations>
|
||||
<guideline>Explain each significant resolution decision</guideline>
|
||||
<guideline>Reference specific commits when relevant</guideline>
|
||||
<guideline>Justify why certain changes were kept or merged</guideline>
|
||||
|
||||
<format>
|
||||
<explanation>
|
||||
Conflict in [file]:
|
||||
- HEAD: [brief description of changes]
|
||||
- Incoming: [brief description of changes]
|
||||
- Resolution: [what was decided and why]
|
||||
</explanation>
|
||||
</format>
|
||||
</conflict_explanations>
|
||||
|
||||
<error_handling>
|
||||
<scenario name="no_pr_number">
|
||||
<response>
|
||||
Expected a PR number (e.g., "#123" or "123"). Please provide the PR number to resolve conflicts for.
|
||||
</response>
|
||||
</scenario>
|
||||
|
||||
<scenario name="no_conflicts">
|
||||
<response>
|
||||
PR #[number] does not have any merge conflicts. The branch can be merged without conflict resolution.
|
||||
</response>
|
||||
</scenario>
|
||||
|
||||
<scenario name="pr_not_found">
|
||||
<response>
|
||||
Could not find PR #[number]. Please verify the PR number and ensure you have access to the repository.
|
||||
</response>
|
||||
</scenario>
|
||||
|
||||
<scenario name="complex_conflicts">
|
||||
<response>
|
||||
Found complex conflicts in [file] that require careful analysis. Examining commit history to determine the best resolution strategy...
|
||||
</response>
|
||||
</scenario>
|
||||
</error_handling>
|
||||
|
||||
<completion_messages>
|
||||
<structure>
|
||||
<element>State that conflicts are resolved</element>
|
||||
<element>Provide resolution summary</element>
|
||||
<element>List files that were resolved</element>
|
||||
<element>Mention key decisions made</element>
|
||||
</structure>
|
||||
|
||||
<template><![CDATA[
|
||||
Successfully resolved merge conflicts for PR #[number] "[title]".
|
||||
|
||||
Resolution Summary:
|
||||
- [file1]: [brief description of resolution]
|
||||
- [file2]: [brief description of resolution]
|
||||
|
||||
[Key decision explanation if applicable]
|
||||
|
||||
All conflicts have been resolved and files have been staged for commit.
|
||||
]]></template>
|
||||
|
||||
<avoid>
|
||||
<element>Questions about next steps</element>
|
||||
<element>Offers to do additional work</element>
|
||||
<element>Uncertain language about the resolution</element>
|
||||
</avoid>
|
||||
</completion_messages>
|
||||
|
||||
<decision_documentation>
|
||||
<principle>Document why specific resolutions were chosen</principle>
|
||||
<principle>Reference commit SHAs when they influenced decisions</principle>
|
||||
<principle>Explain trade-offs when both sides had valid changes</principle>
|
||||
|
||||
<examples>
|
||||
<example>
|
||||
Preserved bugfix from commit abc123 while adapting it to the refactored structure from def456
|
||||
</example>
|
||||
<example>
|
||||
Combined both implementations as they addressed different aspects of the same feature
|
||||
</example>
|
||||
<example>
|
||||
Chose the more recent implementation as it included additional error handling
|
||||
</example>
|
||||
</examples>
|
||||
</decision_documentation>
|
||||
|
||||
<special_cases>
|
||||
<case name="binary_files">
|
||||
<message>
|
||||
Binary file conflict in [file]. Based on PR intent "[title]", choosing [which version] version.
|
||||
</message>
|
||||
</case>
|
||||
|
||||
<case name="deleted_vs_modified">
|
||||
<message>
|
||||
Conflict: [file] was deleted in one branch but modified in another. Based on the changes, [keeping/removing] the file because [reason].
|
||||
</message>
|
||||
</case>
|
||||
|
||||
<case name="whitespace_only">
|
||||
<message>
|
||||
Conflict in [file] involves only whitespace/formatting. Applying consistent formatting from [which] branch.
|
||||
</message>
|
||||
</case>
|
||||
</special_cases>
|
||||
</merge_resolver_communication>
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<step>Determine if the PR is from a fork by checking 'gh pr view [PR_NUMBER] --repo [owner]/[repo] --json isCrossRepository'.</step>
|
||||
<step>Apply code changes based on review feedback using file editing tools.</step>
|
||||
<step>Fix failing tests by modifying test files or source code as needed.</step>
|
||||
<step>For conflict resolution: Use GIT_EDITOR=true for non-interactive rebases, then resolve conflicts via file editing.</step>
|
||||
<step>For conflict resolution: Delegate to merge-resolver mode using new_task with the PR number.</step>
|
||||
<step>If changes affect user-facing content (i18n files, UI components, announcements), delegate translation updates using the new_task tool with translate mode.</step>
|
||||
<step>Review modified files with 'git status --porcelain' to ensure no temporary files are included.</step>
|
||||
<step>Stage files selectively using 'git add -u' (for modified tracked files) or 'git add <specific-files>' (for new files).</step>
|
||||
|
|
|
|||
|
|
@ -41,33 +41,25 @@
|
|||
|
||||
<code_conventions>
|
||||
<convention category="merge_conflicts">
|
||||
<rule>How to correctly escape conflict markers when using apply_diff.</rule>
|
||||
<rule>Delegate merge conflict resolution to the merge-resolver mode.</rule>
|
||||
<template>
|
||||
When removing merge conflict markers from files, you must **escape** them in your `SEARCH` section by prepending a backslash (`\`) at the beginning of the line. This prevents the system from mistaking them for actual diff syntax.
|
||||
When merge conflicts are detected, do not attempt to resolve them manually. Instead, use the new_task tool to create a task for the merge-resolver mode:
|
||||
|
||||
**Correct Format Example:**
|
||||
|
||||
```
|
||||
<<<<<<< SEARCH
|
||||
content before
|
||||
\<<<<<<< HEAD <-- Note the backslash here
|
||||
content after
|
||||
=======
|
||||
replacement content
|
||||
>>>>>>> REPLACE
|
||||
```xml
|
||||
<new_task>
|
||||
<mode>merge-resolver</mode>
|
||||
<message>#[PR_NUMBER]</message>
|
||||
</new_task>
|
||||
```
|
||||
|
||||
Without escaping, the system confuses your content with real diff markers.
|
||||
The merge-resolver mode will:
|
||||
- Checkout the PR branch
|
||||
- Perform the rebase
|
||||
- Intelligently resolve conflicts based on commit history and intent
|
||||
- Push the resolved changes
|
||||
- Return control back to pr-fixer mode
|
||||
|
||||
You may include multiple diff blocks in a single request, but if any of the following markers appear within your `SEARCH` or `REPLACE` content, they must be escaped:
|
||||
|
||||
```
|
||||
\<<<<<<< SEARCH
|
||||
\=======
|
||||
\>>>>>>> REPLACE
|
||||
```
|
||||
|
||||
Only these three need to be escaped when used in content.
|
||||
This ensures consistent and intelligent conflict resolution across all PRs.
|
||||
</template>
|
||||
</convention>
|
||||
</code_conventions>
|
||||
|
|
|
|||
|
|
@ -27,32 +27,26 @@
|
|||
<pattern name="detecting_conflicts">
|
||||
<usage>Commands to detect merge conflicts.</usage>
|
||||
<template>
|
||||
<comment>Fetch latest main branch</comment>
|
||||
<command tool="git">git fetch origin main</command>
|
||||
<comment>Check if rebase would create conflicts</comment>
|
||||
<command tool="git">git rebase --dry-run origin/main</command>
|
||||
<comment>Check PR mergeable status</comment>
|
||||
<command tool="gh">gh pr view <pr_number> --json mergeable,mergeStateStatus</command>
|
||||
<comment>If mergeable is false or mergeStateStatus is CONFLICTING, delegate to merge-resolver</comment>
|
||||
</template>
|
||||
</pattern>
|
||||
|
||||
<pattern name="non_interactive_rebase">
|
||||
<usage>Rebase operations using GIT_EDITOR to prevent interactive prompts.</usage>
|
||||
<pattern name="delegating_conflict_resolution">
|
||||
<usage>Delegate merge conflict resolution to the merge-resolver mode.</usage>
|
||||
<template>
|
||||
<command tool="git">git checkout <pr_branch></command>
|
||||
<command tool="git">GIT_EDITOR=true git rebase main</command>
|
||||
<comment>If conflicts occur, resolve them manually then use 'git rebase --continue'</comment>
|
||||
<command tool="git">git push --force-with-lease <remote> <pr_branch></command>
|
||||
<comment>When conflicts are detected, create a new task for merge-resolver</comment>
|
||||
<command tool="new_task"><![CDATA[
|
||||
<new_task>
|
||||
<mode>merge-resolver</mode>
|
||||
<message>#<pr_number></message>
|
||||
</new_task>
|
||||
]]></command>
|
||||
<comment>Wait for merge-resolver to complete before continuing with other fixes</comment>
|
||||
</template>
|
||||
</pattern>
|
||||
|
||||
<pattern name="conflict_status_check">
|
||||
<usage>Check current conflict status without interactive input.</usage>
|
||||
<template>
|
||||
<command tool="git">git status --porcelain</command>
|
||||
<command tool="git">git diff --name-only --diff-filter=U</command>
|
||||
<comment>List files with unresolved conflicts</comment>
|
||||
<command tool="git">git ls-files --unmerged</command>
|
||||
</template>
|
||||
</pattern>
|
||||
<pattern name="checking_out_pr">
|
||||
<usage>Check out a pull request branch locally.</usage>
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@
|
|||
<step>Push to appropriate remote: 'git push --force-with-lease [remote] [branch]'</step>
|
||||
</remote_handling>
|
||||
<conflict_resolution>
|
||||
<step>Use 'GIT_EDITOR=true git rebase main' to start rebase</step>
|
||||
<step>If conflicts occur, edit files to resolve them</step>
|
||||
<step>Use 'git add .' and 'git rebase --continue' to proceed</step>
|
||||
<step>Delegate to merge-resolver mode using new_task</step>
|
||||
<step>Provide the PR number (e.g., "#123") as the message</step>
|
||||
<step>The merge-resolver mode will handle all conflict resolution automatically</step>
|
||||
</conflict_resolution>
|
||||
</tool>
|
||||
|
||||
|
|
@ -114,6 +114,26 @@ Files modified:
|
|||
- webview-ui/src/components/settings/ApiSettings.tsx: Updated button text from "Save" to "Save Configuration"
|
||||
|
||||
Please ensure all supported languages (ca, de, es, fr, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW) are updated with appropriate translations for these changes.</message>
|
||||
</new_task>
|
||||
]]></example_usage>
|
||||
</tool>
|
||||
|
||||
<tool name="new_task (mode: merge-resolver)">
|
||||
<best_practices>
|
||||
<practice>Use when PR has merge conflicts that need to be resolved.</practice>
|
||||
<practice>Simply provide the PR number (e.g., "#123") as the message.</practice>
|
||||
<practice>The merge-resolver mode will handle checkout, rebase, conflict resolution, and pushing.</practice>
|
||||
<practice>Wait for merge-resolver to complete before continuing with other PR fixes.</practice>
|
||||
</best_practices>
|
||||
<when_to_use>
|
||||
<trigger>When gh pr view shows mergeable: false or mergeStateStatus: CONFLICTING</trigger>
|
||||
<trigger>When git rebase fails with conflicts</trigger>
|
||||
<trigger>When git status shows unmerged paths</trigger>
|
||||
</when_to_use>
|
||||
<example_usage><![CDATA[
|
||||
<new_task>
|
||||
<mode>merge-resolver</mode>
|
||||
<message>#1234</message>
|
||||
</new_task>
|
||||
]]></example_usage>
|
||||
</tool>
|
||||
|
|
|
|||
|
|
@ -200,4 +200,105 @@ Ensure consistency across all language files and maintain the same context and t
|
|||
<takeaway>Use gh pr view --json to get structured data about PR properties.</takeaway>
|
||||
</key_takeaways>
|
||||
</example>
|
||||
|
||||
<example name="fix_pr_with_merge_conflicts">
|
||||
<scenario>
|
||||
A pull request has merge conflicts that need to be resolved before other fixes can be applied.
|
||||
</scenario>
|
||||
|
||||
<user_request>
|
||||
Fix PR #5678 in RooCodeInc/Roo-Code - it has merge conflicts and failing tests.
|
||||
</user_request>
|
||||
|
||||
<workflow>
|
||||
<step number="1">
|
||||
<description>Get PR details and check merge status.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>gh pr view 5678 --repo RooCodeInc/Roo-Code --json number,title,author,state,body,url,headRefName,baseRefName,mergeable,mergeStateStatus</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<expected_outcome>Identify that mergeable is false and mergeStateStatus is CONFLICTING.</expected_outcome>
|
||||
</step>
|
||||
|
||||
<step number="2">
|
||||
<description>Delegate merge conflict resolution to merge-resolver mode.</description>
|
||||
<tool_use>
|
||||
<new_task>
|
||||
<mode>merge-resolver</mode>
|
||||
<message>#5678</message>
|
||||
</new_task>
|
||||
</tool_use>
|
||||
<expected_outcome>The merge-resolver mode will handle checkout, rebase, conflict resolution, and pushing the resolved changes.</expected_outcome>
|
||||
</step>
|
||||
|
||||
<step number="3">
|
||||
<description>After merge-resolver completes, check PR status again.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>gh pr view 5678 --repo RooCodeInc/Roo-Code --json mergeable,mergeStateStatus</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<analysis>Verify that the PR is now mergeable after conflict resolution.</analysis>
|
||||
</step>
|
||||
|
||||
<step number="4">
|
||||
<description>Check CI status for any remaining failures.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>gh pr checks 5678 --repo RooCodeInc/Roo-Code</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<analysis>Identify any tests that are still failing after the merge conflict resolution.</analysis>
|
||||
</step>
|
||||
|
||||
<step number="5">
|
||||
<description>If tests are still failing, proceed with fixing them.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>gh pr checkout 5678 --repo RooCodeInc/Roo-Code --force</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<analysis>Now that conflicts are resolved, we can focus on fixing the failing tests.</analysis>
|
||||
</step>
|
||||
|
||||
<step number="6">
|
||||
<description>Apply test fixes and push changes.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>git add -u && git commit -m "fix: resolve failing tests after merge conflict resolution"</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<analysis>Commit the test fixes separately from the merge conflict resolution.</analysis>
|
||||
</step>
|
||||
|
||||
<step number="7">
|
||||
<description>Push changes and monitor CI status.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>git push --force-with-lease origin [branch_name]</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<analysis>Push the test fixes to update the PR.</analysis>
|
||||
</step>
|
||||
|
||||
<step number="8">
|
||||
<description>Monitor CI checks in real-time.</description>
|
||||
<tool_use>
|
||||
<execute_command>
|
||||
<command>gh pr checks 5678 --repo RooCodeInc/Roo-Code --watch</command>
|
||||
</execute_command>
|
||||
</tool_use>
|
||||
<analysis>Watch CI checks continuously until all tests pass.</analysis>
|
||||
</step>
|
||||
</workflow>
|
||||
|
||||
<key_takeaways>
|
||||
<takeaway>Always check for merge conflicts before attempting other fixes.</takeaway>
|
||||
<takeaway>Delegate merge conflict resolution to the specialized merge-resolver mode.</takeaway>
|
||||
<takeaway>The merge-resolver mode handles the entire conflict resolution workflow including pushing.</takeaway>
|
||||
<takeaway>After conflict resolution, continue with other PR fixes like failing tests.</takeaway>
|
||||
<takeaway>Keep conflict resolution commits separate from other fix commits for clarity.</takeaway>
|
||||
</key_takeaways>
|
||||
</example>
|
||||
</complete_examples>
|
||||
|
|
|
|||
32
.roomodes
32
.roomodes
|
|
@ -225,3 +225,35 @@ customModes:
|
|||
- command
|
||||
- mcp
|
||||
source: project
|
||||
- slug: merge-resolver
|
||||
name: 🔀 Merge Resolver
|
||||
roleDefinition: |-
|
||||
You are Roo, a merge conflict resolution specialist with expertise in:
|
||||
- Analyzing pull request merge conflicts using git blame and commit history
|
||||
- Understanding code intent through commit messages and diffs
|
||||
- Making intelligent decisions about which changes to keep, merge, or discard
|
||||
- Using git commands and GitHub CLI to gather context
|
||||
- Resolving conflicts based on commit metadata and code semantics
|
||||
- Prioritizing changes based on intent (bugfix vs feature vs refactor)
|
||||
- Combining non-conflicting changes when appropriate
|
||||
|
||||
You receive a PR number (e.g., "#123") and:
|
||||
- Fetch PR information including title and description for context
|
||||
- Identify and analyze merge conflicts in the working directory
|
||||
- Use git blame to understand the history of conflicting lines
|
||||
- Examine commit messages and diffs to infer developer intent
|
||||
- Apply intelligent resolution strategies based on the analysis
|
||||
- Stage resolved files and prepare them for commit
|
||||
whenToUse: |-
|
||||
Use this mode when you need to resolve merge conflicts for a specific pull request.
|
||||
This mode is triggered by providing a PR number (e.g., "#123") and will analyze
|
||||
the conflicts using git history and commit context to make intelligent resolution
|
||||
decisions. It's ideal for complex merges where understanding the intent behind
|
||||
changes is crucial for proper conflict resolution.
|
||||
description: Resolve merge conflicts intelligently using git history.
|
||||
groups:
|
||||
- read
|
||||
- edit
|
||||
- command
|
||||
- mcp
|
||||
source: project
|
||||
|
|
|
|||
22
CHANGELOG.md
22
CHANGELOG.md
|
|
@ -1,5 +1,27 @@
|
|||
# Roo Code Changelog
|
||||
|
||||
## [3.23.17] - 2025-07-22
|
||||
|
||||
- Add: todo list tool enable checkbox to provider advanced settings
|
||||
- Add: Moonshot provider (thanks @CellenLee!)
|
||||
- Add: Qwen/Qwen3-235B-A22B-Instruct-2507 model to Chutes AI provider
|
||||
- Fix: move context condensing prompt to Prompts section (thanks @SannidhyaSah!)
|
||||
- Add: jump icon for newly created files
|
||||
- Fix: add character limit to prevent terminal output context explosion
|
||||
- Fix: resolve global mode export not including rules files
|
||||
- Fix: enable export, share, and copy buttons during API operations (thanks @MuriloFP!)
|
||||
- Add: configurable timeout for evals (5-10 min)
|
||||
- Add: auto-omit MCP content when no servers are configured
|
||||
- Fix: sort symlinked rules files by symlink names, not target names
|
||||
- Docs: clarify when to use update_todo_list tool
|
||||
- Add: Mistral embedding provider (thanks @SannidhyaSah!)
|
||||
- Fix: add run parameter to vitest command in rules (thanks @KJ7LNW!)
|
||||
- Update: the max_tokens fallback logic in the sliding window
|
||||
- Fix: Bedrock and Vertext token counting improvements (thanks @daniel-lxs!)
|
||||
- Add: llama-4-maverick model to Vertex AI provider (thanks @MuriloFP!)
|
||||
- Fix: properly distinguish between user cancellations and API failures
|
||||
- Fix: add case sensitivity mention to suggested fixes in apply_diff error message
|
||||
|
||||
## [3.23.16] - 2025-07-19
|
||||
|
||||
- Add global rate limiting for OpenAI-compatible embeddings (thanks @daniel-lxs!)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export async function createRun({ suite, exercises = [], systemPrompt, timeout,
|
|||
|
||||
const dockerArgs = [
|
||||
`--name evals-controller-${run.id}`,
|
||||
// "--rm",
|
||||
"--rm",
|
||||
"--network evals_default",
|
||||
"-v /var/run/docker.sock:/var/run/docker.sock",
|
||||
"-v /tmp/evals:/var/log/evals",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,14 @@ import * as os from "node:os"
|
|||
import pWaitFor from "p-wait-for"
|
||||
import { execa } from "execa"
|
||||
|
||||
import { type TaskEvent, TaskCommandName, RooCodeEventName, IpcMessageType, EVALS_SETTINGS } from "@roo-code/types"
|
||||
import {
|
||||
type TaskEvent,
|
||||
type ClineSay,
|
||||
TaskCommandName,
|
||||
RooCodeEventName,
|
||||
IpcMessageType,
|
||||
EVALS_SETTINGS,
|
||||
} from "@roo-code/types"
|
||||
import { IpcClient } from "@roo-code/ipc"
|
||||
|
||||
import {
|
||||
|
|
@ -203,6 +210,15 @@ export const runTask = async ({ run, task, publish, logger }: RunTaskOptions) =>
|
|||
log: [RooCodeEventName.TaskTokenUsageUpdated, RooCodeEventName.TaskAskResponded],
|
||||
}
|
||||
|
||||
const loggableSays: ClineSay[] = [
|
||||
"error",
|
||||
"command_output",
|
||||
"rooignore_error",
|
||||
"diff_error",
|
||||
"condense_context",
|
||||
"condense_context_error",
|
||||
]
|
||||
|
||||
client.on(IpcMessageType.TaskEvent, async (taskEvent) => {
|
||||
const { eventName, payload } = taskEvent
|
||||
|
||||
|
|
@ -215,7 +231,9 @@ export const runTask = async ({ run, task, publish, logger }: RunTaskOptions) =>
|
|||
// For message events we only log non-partial messages.
|
||||
if (
|
||||
!ignoreEvents.log.includes(eventName) &&
|
||||
(eventName !== RooCodeEventName.Message || payload[0].message.partial !== true)
|
||||
(eventName !== RooCodeEventName.Message ||
|
||||
(payload[0].message.say && loggableSays.includes(payload[0].message.say)) ||
|
||||
payload[0].message.partial !== true)
|
||||
) {
|
||||
logger.info(`${eventName} ->`, payload)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
|
|||
alwaysAllowUpdateTodoList: true,
|
||||
followupAutoApproveTimeoutMs: 0,
|
||||
allowedCommands: ["*"],
|
||||
commandExecutionTimeout: 30_000,
|
||||
commandExecutionTimeout: 20,
|
||||
commandTimeoutAllowlist: [],
|
||||
preventCompletionWithOpenTodos: false,
|
||||
|
||||
|
|
@ -266,7 +266,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
|
|||
|
||||
mcpEnabled: false,
|
||||
|
||||
mode: "code",
|
||||
mode: "code", // "architect",
|
||||
|
||||
customModes: [],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export type ChutesModelId =
|
|||
| "deepseek-ai/DeepSeek-R1-Zero"
|
||||
| "deepseek-ai/DeepSeek-V3-0324"
|
||||
| "Qwen/Qwen3-235B-A22B"
|
||||
| "Qwen/Qwen3-235B-A22B-Instruct-2507"
|
||||
| "Qwen/Qwen3-32B"
|
||||
| "Qwen/Qwen3-30B-A3B"
|
||||
| "Qwen/Qwen3-14B"
|
||||
|
|
@ -163,6 +164,15 @@ export const chutesModels = {
|
|||
outputPrice: 0,
|
||||
description: "DeepSeek V3 (0324) model.",
|
||||
},
|
||||
"Qwen/Qwen3-235B-A22B-Instruct-2507": {
|
||||
maxTokens: 32768,
|
||||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 235B A22B Instruct 2507 model with 262K context window.",
|
||||
},
|
||||
"Qwen/Qwen3-235B-A22B": {
|
||||
maxTokens: 32768,
|
||||
contextWindow: 40960,
|
||||
|
|
|
|||
|
|
@ -273,6 +273,15 @@ export const vertexModels = {
|
|||
maxThinkingTokens: 24_576,
|
||||
supportsReasoningBudget: true,
|
||||
},
|
||||
"llama-4-maverick-17b-128e-instruct-maas": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.35,
|
||||
outputPrice: 1.15,
|
||||
description: "Meta Llama 4 Maverick 17B Instruct model, 128K context.",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
||||
export const VERTEX_REGIONS = [
|
||||
|
|
|
|||
|
|
@ -163,6 +163,28 @@ describe("ChutesHandler", () => {
|
|||
expect(model.info).toEqual(expect.objectContaining(chutesModels[testModelId]))
|
||||
})
|
||||
|
||||
it("should return Qwen3-235B-A22B-Instruct-2507 model with correct configuration", () => {
|
||||
const testModelId: ChutesModelId = "Qwen/Qwen3-235B-A22B-Instruct-2507"
|
||||
const handlerWithModel = new ChutesHandler({
|
||||
apiModelId: testModelId,
|
||||
chutesApiKey: "test-chutes-api-key",
|
||||
})
|
||||
const model = handlerWithModel.getModel()
|
||||
expect(model.id).toBe(testModelId)
|
||||
expect(model.info).toEqual(
|
||||
expect.objectContaining({
|
||||
maxTokens: 32768,
|
||||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 235B A22B Instruct 2507 model with 262K context window.",
|
||||
temperature: 0.5, // Default temperature for non-DeepSeek models
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it("completePrompt method should return text from Chutes API", async () => {
|
||||
const expectedResponse = "This is a test response from Chutes"
|
||||
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] })
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { TelemetryService } from "@roo-code/telemetry"
|
|||
import { Task } from "../task/Task"
|
||||
|
||||
import { getWorkspacePath } from "../../utils/path"
|
||||
import { checkGitInstalled } from "../../utils/git"
|
||||
import { t } from "../../i18n"
|
||||
|
||||
import { ClineApiReqInfo } from "../../shared/ExtensionMessage"
|
||||
import { getApiMetrics } from "../../shared/getApiMetrics"
|
||||
|
|
@ -73,6 +75,47 @@ export function getCheckpointService(cline: Task) {
|
|||
|
||||
cline.checkpointServiceInitializing = true
|
||||
|
||||
// Check if Git is installed before initializing the service
|
||||
// Note: This is intentionally fire-and-forget to match the original IIFE pattern
|
||||
// The service is returned immediately while Git check happens asynchronously
|
||||
checkGitInstallation(cline, service, log, provider)
|
||||
|
||||
return service
|
||||
} catch (err) {
|
||||
log(`[Task#getCheckpointService] ${err.message}`)
|
||||
cline.enableCheckpoints = false
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
async function checkGitInstallation(
|
||||
cline: Task,
|
||||
service: RepoPerTaskCheckpointService,
|
||||
log: (message: string) => void,
|
||||
provider: any,
|
||||
) {
|
||||
try {
|
||||
const gitInstalled = await checkGitInstalled()
|
||||
|
||||
if (!gitInstalled) {
|
||||
log("[Task#getCheckpointService] Git is not installed, disabling checkpoints")
|
||||
cline.enableCheckpoints = false
|
||||
cline.checkpointServiceInitializing = false
|
||||
|
||||
// Show user-friendly notification
|
||||
const selection = await vscode.window.showWarningMessage(
|
||||
t("common:errors.git_not_installed"),
|
||||
t("common:buttons.learn_more"),
|
||||
)
|
||||
|
||||
if (selection === t("common:buttons.learn_more")) {
|
||||
await vscode.env.openExternal(vscode.Uri.parse("https://git-scm.com/downloads"))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Git is installed, proceed with initialization
|
||||
service.on("initialize", () => {
|
||||
log("[Task#getCheckpointService] service initialized")
|
||||
|
||||
|
|
@ -118,12 +161,11 @@ export function getCheckpointService(cline: Task) {
|
|||
log(`[Task#getCheckpointService] initShadowGit -> ${err.message}`)
|
||||
cline.enableCheckpoints = false
|
||||
})
|
||||
|
||||
return service
|
||||
} catch (err) {
|
||||
log(`[Task#getCheckpointService] ${err.message}`)
|
||||
log(`[Task#getCheckpointService] Unexpected error during Git check: ${err.message}`)
|
||||
console.error("Git check error:", err)
|
||||
cline.enableCheckpoints = false
|
||||
return undefined
|
||||
cline.checkpointServiceInitializing = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -508,7 +508,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
</update_todo_list>
|
||||
|
||||
**When to Use:**
|
||||
- The task involves multiple steps or requires ongoing tracking.
|
||||
- The task is complicated or involves multiple steps or requires ongoing tracking.
|
||||
- You need to update the status of several todos at once.
|
||||
- New actionable items are discovered during task execution.
|
||||
- The user requests a todo list or provides multiple tasks.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { t } from "../../i18n"
|
|||
class ShellIntegrationError extends Error {}
|
||||
|
||||
export async function executeCommandTool(
|
||||
cline: Task,
|
||||
task: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
@ -33,25 +33,25 @@ export async function executeCommandTool(
|
|||
|
||||
try {
|
||||
if (block.partial) {
|
||||
await cline.ask("command", removeClosingTag("command", command), block.partial).catch(() => {})
|
||||
await task.ask("command", removeClosingTag("command", command), block.partial).catch(() => {})
|
||||
return
|
||||
} else {
|
||||
if (!command) {
|
||||
cline.consecutiveMistakeCount++
|
||||
cline.recordToolError("execute_command")
|
||||
pushToolResult(await cline.sayAndCreateMissingParamError("execute_command", "command"))
|
||||
task.consecutiveMistakeCount++
|
||||
task.recordToolError("execute_command")
|
||||
pushToolResult(await task.sayAndCreateMissingParamError("execute_command", "command"))
|
||||
return
|
||||
}
|
||||
|
||||
const ignoredFileAttemptedToAccess = cline.rooIgnoreController?.validateCommand(command)
|
||||
const ignoredFileAttemptedToAccess = task.rooIgnoreController?.validateCommand(command)
|
||||
|
||||
if (ignoredFileAttemptedToAccess) {
|
||||
await cline.say("rooignore_error", ignoredFileAttemptedToAccess)
|
||||
await task.say("rooignore_error", ignoredFileAttemptedToAccess)
|
||||
pushToolResult(formatResponse.toolError(formatResponse.rooIgnoreError(ignoredFileAttemptedToAccess)))
|
||||
return
|
||||
}
|
||||
|
||||
cline.consecutiveMistakeCount = 0
|
||||
task.consecutiveMistakeCount = 0
|
||||
|
||||
command = unescapeHtmlEntities(command) // Unescape HTML entities.
|
||||
const didApprove = await askApproval("command", command)
|
||||
|
|
@ -60,14 +60,15 @@ export async function executeCommandTool(
|
|||
return
|
||||
}
|
||||
|
||||
const executionId = cline.lastMessageTs?.toString() ?? Date.now().toString()
|
||||
const clineProvider = await cline.providerRef.deref()
|
||||
const clineProviderState = await clineProvider?.getState()
|
||||
const executionId = task.lastMessageTs?.toString() ?? Date.now().toString()
|
||||
const provider = await task.providerRef.deref()
|
||||
const providerState = await provider?.getState()
|
||||
|
||||
const {
|
||||
terminalOutputLineLimit = 500,
|
||||
terminalOutputCharacterLimit = DEFAULT_TERMINAL_OUTPUT_CHARACTER_LIMIT,
|
||||
terminalShellIntegrationDisabled = false,
|
||||
} = clineProviderState ?? {}
|
||||
} = providerState ?? {}
|
||||
|
||||
// Get command execution timeout from VSCode configuration (in seconds)
|
||||
const commandExecutionTimeoutSeconds = vscode.workspace
|
||||
|
|
@ -96,26 +97,26 @@ export async function executeCommandTool(
|
|||
}
|
||||
|
||||
try {
|
||||
const [rejected, result] = await executeCommand(cline, options)
|
||||
const [rejected, result] = await executeCommand(task, options)
|
||||
|
||||
if (rejected) {
|
||||
cline.didRejectTool = true
|
||||
task.didRejectTool = true
|
||||
}
|
||||
|
||||
pushToolResult(result)
|
||||
} catch (error: unknown) {
|
||||
const status: CommandExecutionStatus = { executionId, status: "fallback" }
|
||||
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
await cline.say("shell_integration_warning")
|
||||
provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
await task.say("shell_integration_warning")
|
||||
|
||||
if (error instanceof ShellIntegrationError) {
|
||||
const [rejected, result] = await executeCommand(cline, {
|
||||
const [rejected, result] = await executeCommand(task, {
|
||||
...options,
|
||||
terminalShellIntegrationDisabled: true,
|
||||
})
|
||||
|
||||
if (rejected) {
|
||||
cline.didRejectTool = true
|
||||
task.didRejectTool = true
|
||||
}
|
||||
|
||||
pushToolResult(result)
|
||||
|
|
@ -143,7 +144,7 @@ export type ExecuteCommandOptions = {
|
|||
}
|
||||
|
||||
export async function executeCommand(
|
||||
cline: Task,
|
||||
task: Task,
|
||||
{
|
||||
executionId,
|
||||
command,
|
||||
|
|
@ -154,16 +155,16 @@ export async function executeCommand(
|
|||
commandExecutionTimeout = 0,
|
||||
}: ExecuteCommandOptions,
|
||||
): Promise<[boolean, ToolResponse]> {
|
||||
// Convert milliseconds back to seconds for display purposes
|
||||
// Convert milliseconds back to seconds for display purposes.
|
||||
const commandExecutionTimeoutSeconds = commandExecutionTimeout / 1000
|
||||
let workingDir: string
|
||||
|
||||
if (!customCwd) {
|
||||
workingDir = cline.cwd
|
||||
workingDir = task.cwd
|
||||
} else if (path.isAbsolute(customCwd)) {
|
||||
workingDir = customCwd
|
||||
} else {
|
||||
workingDir = path.resolve(cline.cwd, customCwd)
|
||||
workingDir = path.resolve(task.cwd, customCwd)
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -180,7 +181,7 @@ export async function executeCommand(
|
|||
let shellIntegrationError: string | undefined
|
||||
|
||||
const terminalProvider = terminalShellIntegrationDisabled ? "execa" : "vscode"
|
||||
const clineProvider = await cline.providerRef.deref()
|
||||
const provider = await task.providerRef.deref()
|
||||
|
||||
let accumulatedOutput = ""
|
||||
const callbacks: RooTerminalCallbacks = {
|
||||
|
|
@ -192,14 +193,14 @@ export async function executeCommand(
|
|||
terminalOutputCharacterLimit,
|
||||
)
|
||||
const status: CommandExecutionStatus = { executionId, status: "output", output: compressedOutput }
|
||||
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
|
||||
if (runInBackground) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const { response, text, images } = await cline.ask("command_output", "")
|
||||
const { response, text, images } = await task.ask("command_output", "")
|
||||
runInBackground = true
|
||||
|
||||
if (response === "messageResponse") {
|
||||
|
|
@ -214,29 +215,30 @@ export async function executeCommand(
|
|||
terminalOutputLineLimit,
|
||||
terminalOutputCharacterLimit,
|
||||
)
|
||||
cline.say("command_output", result)
|
||||
|
||||
task.say("command_output", result)
|
||||
completed = true
|
||||
},
|
||||
onShellExecutionStarted: (pid: number | undefined) => {
|
||||
console.log(`[executeCommand] onShellExecutionStarted: ${pid}`)
|
||||
const status: CommandExecutionStatus = { executionId, status: "started", pid, command }
|
||||
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
},
|
||||
onShellExecutionComplete: (details: ExitCodeDetails) => {
|
||||
const status: CommandExecutionStatus = { executionId, status: "exited", exitCode: details.exitCode }
|
||||
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
exitDetails = details
|
||||
},
|
||||
}
|
||||
|
||||
if (terminalProvider === "vscode") {
|
||||
callbacks.onNoShellIntegration = async (error: string) => {
|
||||
TelemetryService.instance.captureShellIntegrationError(cline.taskId)
|
||||
TelemetryService.instance.captureShellIntegrationError(task.taskId)
|
||||
shellIntegrationError = error
|
||||
}
|
||||
}
|
||||
|
||||
const terminal = await TerminalRegistry.getOrCreateTerminal(workingDir, !!customCwd, cline.taskId, terminalProvider)
|
||||
const terminal = await TerminalRegistry.getOrCreateTerminal(workingDir, !!customCwd, task.taskId, terminalProvider)
|
||||
|
||||
if (terminal instanceof Terminal) {
|
||||
terminal.terminal.show(true)
|
||||
|
|
@ -248,9 +250,9 @@ export async function executeCommand(
|
|||
}
|
||||
|
||||
const process = terminal.runCommand(command, callbacks)
|
||||
cline.terminalProcess = process
|
||||
task.terminalProcess = process
|
||||
|
||||
// Implement command execution timeout (skip if timeout is 0)
|
||||
// Implement command execution timeout (skip if timeout is 0).
|
||||
if (commandExecutionTimeout > 0) {
|
||||
let timeoutId: NodeJS.Timeout | undefined
|
||||
let isTimedOut = false
|
||||
|
|
@ -258,10 +260,7 @@ export async function executeCommand(
|
|||
const timeoutPromise = new Promise<void>((_, reject) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
isTimedOut = true
|
||||
// Try to abort the process
|
||||
if (cline.terminalProcess) {
|
||||
cline.terminalProcess.abort()
|
||||
}
|
||||
task.terminalProcess?.abort()
|
||||
reject(new Error(`Command execution timed out after ${commandExecutionTimeout}ms`))
|
||||
}, commandExecutionTimeout)
|
||||
})
|
||||
|
|
@ -270,17 +269,10 @@ export async function executeCommand(
|
|||
await Promise.race([process, timeoutPromise])
|
||||
} catch (error) {
|
||||
if (isTimedOut) {
|
||||
// Handle timeout case
|
||||
const status: CommandExecutionStatus = { executionId, status: "timeout" }
|
||||
clineProvider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
|
||||
// Add visual feedback for timeout
|
||||
await cline.say(
|
||||
"error",
|
||||
t("common:errors:command_timeout", { seconds: commandExecutionTimeoutSeconds }),
|
||||
)
|
||||
|
||||
cline.terminalProcess = undefined
|
||||
provider?.postMessageToWebview({ type: "commandExecutionStatus", text: JSON.stringify(status) })
|
||||
await task.say("error", t("common:errors:command_timeout", { seconds: commandExecutionTimeoutSeconds }))
|
||||
task.terminalProcess = undefined
|
||||
|
||||
return [
|
||||
false,
|
||||
|
|
@ -292,14 +284,15 @@ export async function executeCommand(
|
|||
if (timeoutId) {
|
||||
clearTimeout(timeoutId)
|
||||
}
|
||||
cline.terminalProcess = undefined
|
||||
|
||||
task.terminalProcess = undefined
|
||||
}
|
||||
} else {
|
||||
// No timeout - just wait for the process to complete
|
||||
// No timeout - just wait for the process to complete.
|
||||
try {
|
||||
await process
|
||||
} finally {
|
||||
cline.terminalProcess = undefined
|
||||
task.terminalProcess = undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +309,7 @@ export async function executeCommand(
|
|||
|
||||
if (message) {
|
||||
const { text, images } = message
|
||||
await cline.say("user_feedback", text, images)
|
||||
await task.say("user_feedback", text, images)
|
||||
|
||||
return [
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ Diff ${i + 1} failed for file: ${relPath}
|
|||
Error: ${failPart.error}
|
||||
|
||||
Suggested fixes:
|
||||
1. Verify the search content exactly matches the file content (including whitespace)
|
||||
1. Verify the search content exactly matches the file content (including whitespace and case)
|
||||
2. Check for correct indentation and line endings
|
||||
3. Use <read_file> to see the current file content
|
||||
4. Consider breaking complex changes into smaller diffs
|
||||
|
|
|
|||
4
src/i18n/locales/ca/common.json
generated
4
src/i18n/locales/ca/common.json
generated
|
|
@ -32,6 +32,7 @@
|
|||
"could_not_open_file_generic": "No s'ha pogut obrir el fitxer!",
|
||||
"checkpoint_timeout": "S'ha esgotat el temps en intentar restaurar el punt de control.",
|
||||
"checkpoint_failed": "Ha fallat la restauració del punt de control.",
|
||||
"git_not_installed": "Git és necessari per a la funció de punts de control. Si us plau, instal·la Git per activar els punts de control.",
|
||||
"no_workspace": "Si us plau, obre primer una carpeta de projecte",
|
||||
"update_support_prompt": "Ha fallat l'actualització del missatge de suport",
|
||||
"reset_support_prompt": "Ha fallat el restabliment del missatge de suport",
|
||||
|
|
@ -111,7 +112,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Desar",
|
||||
"edit": "Editar"
|
||||
"edit": "Editar",
|
||||
"learn_more": "Més informació"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Error de tasca: Ha estat aturada i cancel·lada per l'usuari.",
|
||||
|
|
|
|||
4
src/i18n/locales/de/common.json
generated
4
src/i18n/locales/de/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Datei konnte nicht geöffnet werden!",
|
||||
"checkpoint_timeout": "Zeitüberschreitung beim Versuch, den Checkpoint wiederherzustellen.",
|
||||
"checkpoint_failed": "Fehler beim Wiederherstellen des Checkpoints.",
|
||||
"git_not_installed": "Git ist für die Checkpoint-Funktion erforderlich. Bitte installiere Git, um Checkpoints zu aktivieren.",
|
||||
"no_workspace": "Bitte öffne zuerst einen Projektordner",
|
||||
"update_support_prompt": "Fehler beim Aktualisieren der Support-Nachricht",
|
||||
"reset_support_prompt": "Fehler beim Zurücksetzen der Support-Nachricht",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Speichern",
|
||||
"edit": "Bearbeiten"
|
||||
"edit": "Bearbeiten",
|
||||
"learn_more": "Mehr erfahren"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Aufgabenfehler: Die Aufgabe wurde vom Benutzer gestoppt und abgebrochen.",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Could not open file!",
|
||||
"checkpoint_timeout": "Timed out when attempting to restore checkpoint.",
|
||||
"checkpoint_failed": "Failed to restore checkpoint.",
|
||||
"git_not_installed": "Git is required for the checkpoints feature. Please install Git to enable checkpoints.",
|
||||
"no_workspace": "Please open a project folder first",
|
||||
"update_support_prompt": "Failed to update support prompt",
|
||||
"reset_support_prompt": "Failed to reset support prompt",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Save",
|
||||
"edit": "Edit"
|
||||
"edit": "Edit",
|
||||
"learn_more": "Learn More"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Task error: It was stopped and canceled by the user.",
|
||||
|
|
|
|||
4
src/i18n/locales/es/common.json
generated
4
src/i18n/locales/es/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "¡No se pudo abrir el archivo!",
|
||||
"checkpoint_timeout": "Se agotó el tiempo al intentar restaurar el punto de control.",
|
||||
"checkpoint_failed": "Error al restaurar el punto de control.",
|
||||
"git_not_installed": "Git es necesario para la función de puntos de control. Por favor, instala Git para activar los puntos de control.",
|
||||
"no_workspace": "Por favor, abre primero una carpeta de proyecto",
|
||||
"update_support_prompt": "Error al actualizar el mensaje de soporte",
|
||||
"reset_support_prompt": "Error al restablecer el mensaje de soporte",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Guardar",
|
||||
"edit": "Editar"
|
||||
"edit": "Editar",
|
||||
"learn_more": "Más información"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Error de tarea: Fue detenida y cancelada por el usuario.",
|
||||
|
|
|
|||
4
src/i18n/locales/fr/common.json
generated
4
src/i18n/locales/fr/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Impossible d'ouvrir le fichier !",
|
||||
"checkpoint_timeout": "Expiration du délai lors de la tentative de rétablissement du checkpoint.",
|
||||
"checkpoint_failed": "Échec du rétablissement du checkpoint.",
|
||||
"git_not_installed": "Git est requis pour la fonctionnalité des points de contrôle. Veuillez installer Git pour activer les points de contrôle.",
|
||||
"no_workspace": "Veuillez d'abord ouvrir un espace de travail",
|
||||
"update_support_prompt": "Erreur lors de la mise à jour du prompt de support",
|
||||
"reset_support_prompt": "Erreur lors de la réinitialisation du prompt de support",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Enregistrer",
|
||||
"edit": "Modifier"
|
||||
"edit": "Modifier",
|
||||
"learn_more": "En savoir plus"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Erreur de tâche : Elle a été arrêtée et annulée par l'utilisateur.",
|
||||
|
|
|
|||
4
src/i18n/locales/hi/common.json
generated
4
src/i18n/locales/hi/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "फ़ाइल नहीं खोली जा सकी!",
|
||||
"checkpoint_timeout": "चेकपॉइंट को पुनर्स्थापित करने का प्रयास करते समय टाइमआउट हो गया।",
|
||||
"checkpoint_failed": "चेकपॉइंट पुनर्स्थापित करने में विफल।",
|
||||
"git_not_installed": "चेकपॉइंट सुविधा के लिए Git आवश्यक है। कृपया चेकपॉइंट সক্ষম करने के लिए Git इंस्टॉल करें।",
|
||||
"no_workspace": "कृपया पहले प्रोजेक्ट फ़ोल्डर खोलें",
|
||||
"update_support_prompt": "सपोर्ट प्रॉम्प्ट अपडेट करने में विफल",
|
||||
"reset_support_prompt": "सपोर्ट प्रॉम्प्ट रीसेट करने में विफल",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "सहेजें",
|
||||
"edit": "संपादित करें"
|
||||
"edit": "संपादित करें",
|
||||
"learn_more": "और अधिक जानें"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "टास्क त्रुटि: इसे उपयोगकर्ता द्वारा रोका और रद्द किया गया था।",
|
||||
|
|
|
|||
4
src/i18n/locales/id/common.json
generated
4
src/i18n/locales/id/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Tidak dapat membuka file!",
|
||||
"checkpoint_timeout": "Timeout saat mencoba memulihkan checkpoint.",
|
||||
"checkpoint_failed": "Gagal memulihkan checkpoint.",
|
||||
"git_not_installed": "Git diperlukan untuk fitur checkpoint. Silakan instal Git untuk mengaktifkan checkpoint.",
|
||||
"no_workspace": "Silakan buka folder proyek terlebih dahulu",
|
||||
"update_support_prompt": "Gagal memperbarui support prompt",
|
||||
"reset_support_prompt": "Gagal mereset support prompt",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Simpan",
|
||||
"edit": "Edit"
|
||||
"edit": "Edit",
|
||||
"learn_more": "Pelajari Lebih Lanjut"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Error tugas: Dihentikan dan dibatalkan oleh pengguna.",
|
||||
|
|
|
|||
4
src/i18n/locales/it/common.json
generated
4
src/i18n/locales/it/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Impossibile aprire il file!",
|
||||
"checkpoint_timeout": "Timeout durante il tentativo di ripristinare il checkpoint.",
|
||||
"checkpoint_failed": "Impossibile ripristinare il checkpoint.",
|
||||
"git_not_installed": "Git è richiesto per la funzione di checkpoint. Per favore, installa Git per abilitare i checkpoint.",
|
||||
"no_workspace": "Per favore, apri prima una cartella di progetto",
|
||||
"update_support_prompt": "Errore durante l'aggiornamento del messaggio di supporto",
|
||||
"reset_support_prompt": "Errore durante il ripristino del messaggio di supporto",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Salva",
|
||||
"edit": "Modifica"
|
||||
"edit": "Modifica",
|
||||
"learn_more": "Scopri di più"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Errore attività: È stata interrotta e annullata dall'utente.",
|
||||
|
|
|
|||
4
src/i18n/locales/ja/common.json
generated
4
src/i18n/locales/ja/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "ファイルを開けませんでした!",
|
||||
"checkpoint_timeout": "チェックポイントの復元を試みる際にタイムアウトしました。",
|
||||
"checkpoint_failed": "チェックポイントの復元に失敗しました。",
|
||||
"git_not_installed": "チェックポイント機能にはGitが必要です。チェックポイントを有効にするにはGitをインストールしてください。",
|
||||
"no_workspace": "まずプロジェクトフォルダを開いてください",
|
||||
"update_support_prompt": "サポートメッセージの更新に失敗しました",
|
||||
"reset_support_prompt": "サポートメッセージのリセットに失敗しました",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "保存",
|
||||
"edit": "編集"
|
||||
"edit": "編集",
|
||||
"learn_more": "詳細"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "タスクエラー:ユーザーによって停止およびキャンセルされました。",
|
||||
|
|
|
|||
4
src/i18n/locales/ko/common.json
generated
4
src/i18n/locales/ko/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "파일을 열 수 없습니다!",
|
||||
"checkpoint_timeout": "체크포인트 복원을 시도하는 중 시간 초과되었습니다.",
|
||||
"checkpoint_failed": "체크포인트 복원에 실패했습니다.",
|
||||
"git_not_installed": "체크포인트 기능을 사용하려면 Git이 필요합니다. 체크포인트를 활성화하려면 Git을 설치하세요.",
|
||||
"no_workspace": "먼저 프로젝트 폴더를 열어주세요",
|
||||
"update_support_prompt": "지원 프롬프트 업데이트에 실패했습니다",
|
||||
"reset_support_prompt": "지원 프롬프트 재설정에 실패했습니다",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "저장",
|
||||
"edit": "편집"
|
||||
"edit": "편집",
|
||||
"learn_more": "더 알아보기"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "작업 오류: 사용자에 의해 중지 및 취소되었습니다.",
|
||||
|
|
|
|||
4
src/i18n/locales/nl/common.json
generated
4
src/i18n/locales/nl/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Kon bestand niet openen!",
|
||||
"checkpoint_timeout": "Time-out bij het herstellen van checkpoint.",
|
||||
"checkpoint_failed": "Herstellen van checkpoint mislukt.",
|
||||
"git_not_installed": "Git is vereist voor de checkpoint-functie. Installeer Git om checkpoints in te schakelen.",
|
||||
"no_workspace": "Open eerst een projectmap",
|
||||
"update_support_prompt": "Bijwerken van ondersteuningsprompt mislukt",
|
||||
"reset_support_prompt": "Resetten van ondersteuningsprompt mislukt",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Opslaan",
|
||||
"edit": "Bewerken"
|
||||
"edit": "Bewerken",
|
||||
"learn_more": "Meer informatie"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Taakfout: gestopt en geannuleerd door gebruiker.",
|
||||
|
|
|
|||
4
src/i18n/locales/pl/common.json
generated
4
src/i18n/locales/pl/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Nie można otworzyć pliku!",
|
||||
"checkpoint_timeout": "Upłynął limit czasu podczas próby przywrócenia punktu kontrolnego.",
|
||||
"checkpoint_failed": "Nie udało się przywrócić punktu kontrolnego.",
|
||||
"git_not_installed": "Funkcja punktów kontrolnych wymaga oprogramowania Git. Zainstaluj Git, aby włączyć punkty kontrolne.",
|
||||
"no_workspace": "Najpierw otwórz folder projektu",
|
||||
"update_support_prompt": "Nie udało się zaktualizować komunikatu wsparcia",
|
||||
"reset_support_prompt": "Nie udało się zresetować komunikatu wsparcia",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Zapisz",
|
||||
"edit": "Edytuj"
|
||||
"edit": "Edytuj",
|
||||
"learn_more": "Dowiedz się więcej"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Błąd zadania: Zostało zatrzymane i anulowane przez użytkownika.",
|
||||
|
|
|
|||
4
src/i18n/locales/pt-BR/common.json
generated
4
src/i18n/locales/pt-BR/common.json
generated
|
|
@ -32,6 +32,7 @@
|
|||
"could_not_open_file_generic": "Não foi possível abrir o arquivo!",
|
||||
"checkpoint_timeout": "Tempo esgotado ao tentar restaurar o ponto de verificação.",
|
||||
"checkpoint_failed": "Falha ao restaurar o ponto de verificação.",
|
||||
"git_not_installed": "O Git é necessário para o recurso de checkpoints. Por favor, instale o Git para habilitar os checkpoints.",
|
||||
"no_workspace": "Por favor, abra primeiro uma pasta de projeto",
|
||||
"update_support_prompt": "Falha ao atualizar o prompt de suporte",
|
||||
"reset_support_prompt": "Falha ao redefinir o prompt de suporte",
|
||||
|
|
@ -111,7 +112,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Salvar",
|
||||
"edit": "Editar"
|
||||
"edit": "Editar",
|
||||
"learn_more": "Saiba Mais"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Erro na tarefa: Foi interrompida e cancelada pelo usuário.",
|
||||
|
|
|
|||
4
src/i18n/locales/ru/common.json
generated
4
src/i18n/locales/ru/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Не удалось открыть файл!",
|
||||
"checkpoint_timeout": "Превышено время ожидания при попытке восстановления контрольной точки.",
|
||||
"checkpoint_failed": "Не удалось восстановить контрольную точку.",
|
||||
"git_not_installed": "Для функции контрольных точек требуется Git. Пожалуйста, установите Git, чтобы включить контрольные точки.",
|
||||
"no_workspace": "Пожалуйста, сначала откройте папку проекта",
|
||||
"update_support_prompt": "Не удалось обновить промпт поддержки",
|
||||
"reset_support_prompt": "Не удалось сбросить промпт поддержки",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Сохранить",
|
||||
"edit": "Редактировать"
|
||||
"edit": "Редактировать",
|
||||
"learn_more": "Узнать больше"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Ошибка задачи: Она была остановлена и отменена пользователем.",
|
||||
|
|
|
|||
4
src/i18n/locales/tr/common.json
generated
4
src/i18n/locales/tr/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Dosya açılamadı!",
|
||||
"checkpoint_timeout": "Kontrol noktasını geri yüklemeye çalışırken zaman aşımına uğradı.",
|
||||
"checkpoint_failed": "Kontrol noktası geri yüklenemedi.",
|
||||
"git_not_installed": "Kontrol noktaları özelliği için Git gereklidir. Kontrol noktalarını etkinleştirmek için lütfen Git'i yükleyin.",
|
||||
"no_workspace": "Lütfen önce bir proje klasörü açın",
|
||||
"update_support_prompt": "Destek istemi güncellenemedi",
|
||||
"reset_support_prompt": "Destek istemi sıfırlanamadı",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Kaydet",
|
||||
"edit": "Düzenle"
|
||||
"edit": "Düzenle",
|
||||
"learn_more": "Daha Fazla Bilgi"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Görev hatası: Kullanıcı tarafından durduruldu ve iptal edildi.",
|
||||
|
|
|
|||
4
src/i18n/locales/vi/common.json
generated
4
src/i18n/locales/vi/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "Không thể mở tệp!",
|
||||
"checkpoint_timeout": "Đã hết thời gian khi cố gắng khôi phục điểm kiểm tra.",
|
||||
"checkpoint_failed": "Không thể khôi phục điểm kiểm tra.",
|
||||
"git_not_installed": "Yêu cầu Git cho tính năng điểm kiểm tra. Vui lòng cài đặt Git để bật điểm kiểm tra.",
|
||||
"no_workspace": "Vui lòng mở thư mục dự án trước",
|
||||
"update_support_prompt": "Không thể cập nhật lời nhắc hỗ trợ",
|
||||
"reset_support_prompt": "Không thể đặt lại lời nhắc hỗ trợ",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "Lưu",
|
||||
"edit": "Chỉnh sửa"
|
||||
"edit": "Chỉnh sửa",
|
||||
"learn_more": "Tìm hiểu thêm"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "Lỗi nhiệm vụ: Nó đã bị dừng và hủy bởi người dùng.",
|
||||
|
|
|
|||
4
src/i18n/locales/zh-CN/common.json
generated
4
src/i18n/locales/zh-CN/common.json
generated
|
|
@ -33,6 +33,7 @@
|
|||
"could_not_open_file_generic": "无法打开文件!",
|
||||
"checkpoint_timeout": "尝试恢复检查点时超时。",
|
||||
"checkpoint_failed": "恢复检查点失败。",
|
||||
"git_not_installed": "存档点功能需要 Git。请安装 Git 以启用存档点。",
|
||||
"no_workspace": "请先打开项目文件夹",
|
||||
"update_support_prompt": "更新支持消息失败",
|
||||
"reset_support_prompt": "重置支持消息失败",
|
||||
|
|
@ -112,7 +113,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "保存",
|
||||
"edit": "编辑"
|
||||
"edit": "编辑",
|
||||
"learn_more": "了解更多"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "任务错误:它已被用户停止并取消。",
|
||||
|
|
|
|||
4
src/i18n/locales/zh-TW/common.json
generated
4
src/i18n/locales/zh-TW/common.json
generated
|
|
@ -28,6 +28,7 @@
|
|||
"could_not_open_file_generic": "無法開啟檔案!",
|
||||
"checkpoint_timeout": "嘗試恢復檢查點時超時。",
|
||||
"checkpoint_failed": "恢復檢查點失敗。",
|
||||
"git_not_installed": "存檔點功能需要 Git。請安裝 Git 以啟用存檔點。",
|
||||
"no_workspace": "請先開啟專案資料夾",
|
||||
"update_support_prompt": "更新支援訊息失敗",
|
||||
"reset_support_prompt": "重設支援訊息失敗",
|
||||
|
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"buttons": {
|
||||
"save": "儲存",
|
||||
"edit": "編輯"
|
||||
"edit": "編輯",
|
||||
"learn_more": "了解更多"
|
||||
},
|
||||
"tasks": {
|
||||
"canceled": "工作錯誤:它已被使用者停止並取消。",
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
|
|||
let timeoutId: NodeJS.Timeout | undefined
|
||||
|
||||
const kill = new Promise<void>((resolve) => {
|
||||
console.log(`[ExecaTerminalProcess#run] SIGKILL -> ${this.pid}`)
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
try {
|
||||
subprocess.kill("SIGKILL")
|
||||
|
|
@ -86,7 +88,7 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
|
|||
await Promise.race([subprocess, kill])
|
||||
} catch (error) {
|
||||
console.log(
|
||||
`[ExecaTerminalProcess] subprocess termination error: ${error instanceof Error ? error.message : String(error)}`,
|
||||
`[ExecaTerminalProcess#run] subprocess termination error: ${error instanceof Error ? error.message : String(error)}`,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -98,12 +100,13 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
|
|||
this.emit("shell_execution_complete", { exitCode: 0 })
|
||||
} catch (error) {
|
||||
if (error instanceof ExecaError) {
|
||||
console.error(`[ExecaTerminalProcess] shell execution error: ${error.message}`)
|
||||
console.error(`[ExecaTerminalProcess#run] shell execution error: ${error.message}`)
|
||||
this.emit("shell_execution_complete", { exitCode: error.exitCode ?? 0, signalName: error.signal })
|
||||
} else {
|
||||
console.error(
|
||||
`[ExecaTerminalProcess] shell execution error: ${error instanceof Error ? error.message : String(error)}`,
|
||||
`[ExecaTerminalProcess#run] shell execution error: ${error instanceof Error ? error.message : String(error)}`,
|
||||
)
|
||||
|
||||
this.emit("shell_execution_complete", { exitCode: 1 })
|
||||
}
|
||||
}
|
||||
|
|
@ -128,29 +131,30 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
|
|||
psTree(this.pid, async (err, children) => {
|
||||
if (!err) {
|
||||
const pids = children.map((p) => parseInt(p.PID))
|
||||
console.error(`[ExecaTerminalProcess#abort] SIGKILL children -> ${pids.join(", ")}`)
|
||||
|
||||
for (const pid of pids) {
|
||||
try {
|
||||
process.kill(pid, "SIGINT")
|
||||
process.kill(pid, "SIGKILL")
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`[ExecaTerminalProcess] Failed to send SIGINT to child PID ${pid}: ${e instanceof Error ? e.message : String(e)}`,
|
||||
`[ExecaTerminalProcess#abort] Failed to send SIGKILL to child PID ${pid}: ${e instanceof Error ? e.message : String(e)}`,
|
||||
)
|
||||
// Optionally try SIGTERM or SIGKILL on failure, depending on desired behavior.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error(
|
||||
`[ExecaTerminalProcess] Failed to get process tree for PID ${this.pid}: ${err.message}`,
|
||||
`[ExecaTerminalProcess#abort] Failed to get process tree for PID ${this.pid}: ${err.message}`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
process.kill(this.pid, "SIGINT")
|
||||
console.error(`[ExecaTerminalProcess#abort] SIGKILL parent -> ${this.pid}`)
|
||||
process.kill(this.pid, "SIGKILL")
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`[ExecaTerminalProcess] Failed to send SIGINT to main PID ${this.pid}: ${e instanceof Error ? e.message : String(e)}`,
|
||||
`[ExecaTerminalProcess#abort] Failed to send SIGKILL to main PID ${this.pid}: ${e instanceof Error ? e.message : String(e)}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"displayName": "%extension.displayName%",
|
||||
"description": "%extension.description%",
|
||||
"publisher": "RooVeterinaryInc",
|
||||
"version": "3.23.16",
|
||||
"version": "3.23.17",
|
||||
"icon": "assets/icons/icon.png",
|
||||
"galleryBanner": {
|
||||
"color": "#617A91",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import * as fs from "fs"
|
|||
import * as path from "path"
|
||||
|
||||
import {
|
||||
checkGitInstalled,
|
||||
searchCommits,
|
||||
getCommitInfo,
|
||||
getWorkingState,
|
||||
|
|
@ -83,6 +84,54 @@ describe("git utils", () => {
|
|||
vitest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe("checkGitInstalled", () => {
|
||||
it("should return true when git --version succeeds", async () => {
|
||||
vitest.mocked(exec).mockImplementation((command: string, options: any, callback: any) => {
|
||||
if (command === "git --version") {
|
||||
callback(null, { stdout: "git version 2.39.2", stderr: "" })
|
||||
return {} as any
|
||||
}
|
||||
callback(new Error("Unexpected command"))
|
||||
return {} as any
|
||||
})
|
||||
|
||||
const result = await checkGitInstalled()
|
||||
expect(result).toBe(true)
|
||||
expect(vitest.mocked(exec)).toHaveBeenCalledWith("git --version", {}, expect.any(Function))
|
||||
})
|
||||
|
||||
it("should return false when git --version fails", async () => {
|
||||
vitest.mocked(exec).mockImplementation((command: string, options: any, callback: any) => {
|
||||
if (command === "git --version") {
|
||||
callback(new Error("git not found"))
|
||||
return {} as any
|
||||
}
|
||||
callback(new Error("Unexpected command"))
|
||||
return {} as any
|
||||
})
|
||||
|
||||
const result = await checkGitInstalled()
|
||||
expect(result).toBe(false)
|
||||
expect(vitest.mocked(exec)).toHaveBeenCalledWith("git --version", {}, expect.any(Function))
|
||||
})
|
||||
|
||||
it("should handle unexpected errors gracefully", async () => {
|
||||
vitest.mocked(exec).mockImplementation((command: string, options: any, callback: any) => {
|
||||
if (command === "git --version") {
|
||||
// Simulate an unexpected error
|
||||
callback(new Error("Unexpected system error"))
|
||||
return {} as any
|
||||
}
|
||||
callback(new Error("Unexpected command"))
|
||||
return {} as any
|
||||
})
|
||||
|
||||
const result = await checkGitInstalled()
|
||||
expect(result).toBe(false)
|
||||
expect(vitest.mocked(exec)).toHaveBeenCalledWith("git --version", {}, expect.any(Function))
|
||||
})
|
||||
})
|
||||
|
||||
describe("searchCommits", () => {
|
||||
const mockCommitData = [
|
||||
"abc123def456",
|
||||
|
|
|
|||
|
|
@ -210,7 +210,16 @@ async function checkGitRepo(cwd: string): Promise<boolean> {
|
|||
}
|
||||
}
|
||||
|
||||
async function checkGitInstalled(): Promise<boolean> {
|
||||
/**
|
||||
* Checks if Git is installed on the system by attempting to run git --version
|
||||
* @returns {Promise<boolean>} True if Git is installed and accessible, false otherwise
|
||||
* @example
|
||||
* const isGitInstalled = await checkGitInstalled();
|
||||
* if (!isGitInstalled) {
|
||||
* console.log("Git is not installed");
|
||||
* }
|
||||
*/
|
||||
export async function checkGitInstalled(): Promise<boolean> {
|
||||
try {
|
||||
await execAsync("git --version")
|
||||
return true
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue