@wbern/claude-instructions 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/cli.js +61 -11
- package/downloads/with-beads/commands-metadata.json +1 -1
- package/downloads/with-beads/worktree-add.md +143 -52
- package/downloads/with-beads/worktree-cleanup.md +74 -55
- package/downloads/without-beads/commands-metadata.json +1 -1
- package/downloads/without-beads/worktree-add.md +143 -52
- package/downloads/without-beads/worktree-cleanup.md +74 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -221,7 +221,7 @@ flowchart TB
|
|
|
221
221
|
|
|
222
222
|
### Worktree Management
|
|
223
223
|
|
|
224
|
-
- `/worktree-add` - Add a new git worktree from branch name or
|
|
224
|
+
- `/worktree-add` - Add a new git worktree from branch name or issue URL, copy settings, install deps, and open in current IDE
|
|
225
225
|
- `/worktree-cleanup` - Clean up merged worktrees by verifying PR/issue status, consolidating settings, and removing stale worktrees
|
|
226
226
|
|
|
227
227
|
### Utilities
|
package/bin/cli.js
CHANGED
|
@@ -548,19 +548,31 @@ function extractLabelFromTool(tool) {
|
|
|
548
548
|
const match = tool.match(/^Bash\(([^:]+):/);
|
|
549
549
|
return match ? match[1] : tool;
|
|
550
550
|
}
|
|
551
|
+
function formatCommandsHint(commands) {
|
|
552
|
+
if (commands.length <= 2) {
|
|
553
|
+
return commands.map((c) => `/${c}`).join(", ");
|
|
554
|
+
}
|
|
555
|
+
const first = commands.slice(0, 2).map((c) => `/${c}`);
|
|
556
|
+
const remaining = commands.length - 2;
|
|
557
|
+
return `${first.join(", ")}, and ${remaining} ${remaining === 1 ? "other" : "others"}`;
|
|
558
|
+
}
|
|
551
559
|
async function getRequestedToolsOptions(variant) {
|
|
552
560
|
const metadata = await loadCommandsMetadata(variant);
|
|
553
|
-
const
|
|
554
|
-
for (const data of Object.
|
|
561
|
+
const toolToCommands = /* @__PURE__ */ new Map();
|
|
562
|
+
for (const [filename, data] of Object.entries(metadata)) {
|
|
555
563
|
if (data["_requested-tools"]) {
|
|
564
|
+
const commandName = filename.replace(/\.md$/, "");
|
|
556
565
|
for (const tool of data["_requested-tools"]) {
|
|
557
|
-
|
|
566
|
+
const commands = toolToCommands.get(tool) || [];
|
|
567
|
+
commands.push(commandName);
|
|
568
|
+
toolToCommands.set(tool, commands);
|
|
558
569
|
}
|
|
559
570
|
}
|
|
560
571
|
}
|
|
561
|
-
return Array.from(
|
|
572
|
+
return Array.from(toolToCommands.entries()).map(([tool, commands]) => ({
|
|
562
573
|
value: tool,
|
|
563
|
-
label: extractLabelFromTool(tool)
|
|
574
|
+
label: extractLabelFromTool(tool),
|
|
575
|
+
hint: formatCommandsHint(commands)
|
|
564
576
|
}));
|
|
565
577
|
}
|
|
566
578
|
function getDestinationPath(outputPath, scope) {
|
|
@@ -894,7 +906,8 @@ async function main(args) {
|
|
|
894
906
|
if (requestedToolsOptions.length > 0) {
|
|
895
907
|
selectedAllowedTools = await multiselect({
|
|
896
908
|
message: "Select allowed tools for commands (optional)",
|
|
897
|
-
options: requestedToolsOptions
|
|
909
|
+
options: requestedToolsOptions,
|
|
910
|
+
required: false
|
|
898
911
|
});
|
|
899
912
|
if (isCancel(selectedAllowedTools)) {
|
|
900
913
|
return;
|
|
@@ -907,21 +920,58 @@ async function main(args) {
|
|
|
907
920
|
});
|
|
908
921
|
const skipFiles = [];
|
|
909
922
|
if (!args?.overwrite && !args?.skipOnConflict) {
|
|
923
|
+
const conflictingFiles = existingFiles.filter((f) => !f.isIdentical);
|
|
924
|
+
const hasMultipleConflicts = conflictingFiles.length > 1;
|
|
925
|
+
let overwriteAllSelected = false;
|
|
926
|
+
let skipAllSelected = false;
|
|
910
927
|
for (const file of existingFiles) {
|
|
911
928
|
if (file.isIdentical) {
|
|
912
929
|
log.info(`${file.filename} is identical, skipping`);
|
|
913
930
|
skipFiles.push(file.filename);
|
|
914
931
|
continue;
|
|
915
932
|
}
|
|
933
|
+
if (overwriteAllSelected) {
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
if (skipAllSelected) {
|
|
937
|
+
skipFiles.push(file.filename);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
916
940
|
const stats = getDiffStats(file.existingContent, file.newContent);
|
|
917
941
|
const diff = formatCompactDiff(file.existingContent, file.newContent);
|
|
918
942
|
note(diff, `Diff: ${file.filename}`);
|
|
919
943
|
log.info(`+${stats.added} -${stats.removed}`);
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
944
|
+
if (hasMultipleConflicts) {
|
|
945
|
+
const choice = await select({
|
|
946
|
+
message: `Overwrite ${file.filename}?`,
|
|
947
|
+
options: [
|
|
948
|
+
{ value: "yes", label: "Yes" },
|
|
949
|
+
{ value: "no", label: "No" },
|
|
950
|
+
{ value: "overwrite_all", label: "Overwrite all" },
|
|
951
|
+
{ value: "skip_all", label: "Skip all" }
|
|
952
|
+
]
|
|
953
|
+
});
|
|
954
|
+
if (isCancel(choice)) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
if (choice === "no") {
|
|
958
|
+
skipFiles.push(file.filename);
|
|
959
|
+
} else if (choice === "overwrite_all") {
|
|
960
|
+
overwriteAllSelected = true;
|
|
961
|
+
} else if (choice === "skip_all") {
|
|
962
|
+
skipAllSelected = true;
|
|
963
|
+
skipFiles.push(file.filename);
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
const shouldOverwrite = await confirm({
|
|
967
|
+
message: `Overwrite ${file.filename}?`
|
|
968
|
+
});
|
|
969
|
+
if (isCancel(shouldOverwrite)) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
if (!shouldOverwrite) {
|
|
973
|
+
skipFiles.push(file.filename);
|
|
974
|
+
}
|
|
925
975
|
}
|
|
926
976
|
}
|
|
927
977
|
} else if (args?.skipOnConflict) {
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"order": 1
|
|
126
126
|
},
|
|
127
127
|
"worktree-add.md": {
|
|
128
|
-
"description": "Add a new git worktree from branch name or
|
|
128
|
+
"description": "Add a new git worktree from branch name or issue URL, copy settings, install deps, and open in current IDE",
|
|
129
129
|
"hint": "Add worktree",
|
|
130
130
|
"category": "Worktree Management",
|
|
131
131
|
"order": 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Add a new git worktree from branch name or
|
|
3
|
-
argument-hint: <branch-name-or-
|
|
2
|
+
description: Add a new git worktree from branch name or issue URL, copy settings, install deps, and open in current IDE
|
|
3
|
+
argument-hint: <branch-name-or-issue-url> [optional-base-branch]
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Git Worktree Setup
|
|
@@ -18,35 +18,61 @@ Beads is available for task tracking. Use `mcp__beads__*` tools to manage issues
|
|
|
18
18
|
Create a new git worktree for branch: $ARGUMENTS
|
|
19
19
|
|
|
20
20
|
<current_state>
|
|
21
|
-
Current branch:
|
|
22
|
-
Current worktrees:
|
|
23
|
-
Remote branches:
|
|
24
|
-
Uncommitted changes:
|
|
21
|
+
Current branch: `git branch --show-current`
|
|
22
|
+
Current worktrees: `git worktree list`
|
|
23
|
+
Remote branches: `git branch -r`
|
|
24
|
+
Uncommitted changes: `git status --short`
|
|
25
25
|
</current_state>
|
|
26
26
|
|
|
27
27
|
<execution_steps>
|
|
28
28
|
<step_0>
|
|
29
|
-
<description>
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
</
|
|
45
|
-
<purpose>Ensure required MCP dependencies are available before proceeding</purpose>
|
|
29
|
+
<description>Ask user for setup mode</description>
|
|
30
|
+
<prompt>
|
|
31
|
+
<message>How would you like to set up the worktree?</message>
|
|
32
|
+
<options>
|
|
33
|
+
<option value="quick">
|
|
34
|
+
<label>Quick</label>
|
|
35
|
+
<description>Just create the worktree (skip deps, settings, IDE)</description>
|
|
36
|
+
</option>
|
|
37
|
+
<option value="full">
|
|
38
|
+
<label>Full setup</label>
|
|
39
|
+
<description>Install dependencies, copy settings, open in IDE</description>
|
|
40
|
+
</option>
|
|
41
|
+
</options>
|
|
42
|
+
</prompt>
|
|
43
|
+
<set_variable>$SETUP_MODE = user selection ("quick" or "full")</set_variable>
|
|
44
|
+
<purpose>Allow quick worktree creation when user just needs the branch</purpose>
|
|
46
45
|
</step_0>
|
|
47
46
|
|
|
47
|
+
<step_0b>
|
|
48
|
+
<description>Detect git hosting provider and available tools (only needed if argument is an issue URL)</description>
|
|
49
|
+
<condition>Only run this step if first argument looks like a git hosting URL</condition>
|
|
50
|
+
<detect_provider>
|
|
51
|
+
<check_remote_url>git remote get-url origin</check_remote_url>
|
|
52
|
+
<identify_host>
|
|
53
|
+
- github.com → GitHub
|
|
54
|
+
- gitlab.com → GitLab
|
|
55
|
+
- bitbucket.org → Bitbucket
|
|
56
|
+
- Other → Ask user
|
|
57
|
+
</identify_host>
|
|
58
|
+
</detect_provider>
|
|
59
|
+
<check_available_tools>
|
|
60
|
+
<list_mcp_servers>Check which git-hosting MCP servers are available (github, gitlab, etc.)</list_mcp_servers>
|
|
61
|
+
<check_cli>Check if gh/glab CLI is available as fallback</check_cli>
|
|
62
|
+
</check_available_tools>
|
|
63
|
+
<select_tool>
|
|
64
|
+
<if_single_mcp>If only one relevant MCP available, confirm with user</if_single_mcp>
|
|
65
|
+
<if_multiple>Let user choose which tool to use</if_multiple>
|
|
66
|
+
<if_told_earlier>If user specified tool earlier in conversation, use that without asking again</if_told_earlier>
|
|
67
|
+
<store_as>$GIT_HOST_TOOL (e.g., "github_mcp", "gitlab_mcp", "gh_cli")</store_as>
|
|
68
|
+
</select_tool>
|
|
69
|
+
|
|
70
|
+
<purpose>Detect git hosting provider and select appropriate tool for issue lookup</purpose>
|
|
71
|
+
</step_0b>
|
|
72
|
+
|
|
48
73
|
<step_1>
|
|
49
74
|
<description>Detect current IDE environment</description>
|
|
75
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
50
76
|
<detection_methods>
|
|
51
77
|
<method_1>
|
|
52
78
|
<tool>mcp__ide__getDiagnostics</tool>
|
|
@@ -70,30 +96,41 @@ Uncommitted changes: !git status --short`
|
|
|
70
96
|
</step_1>
|
|
71
97
|
|
|
72
98
|
<step_2>
|
|
73
|
-
<description>
|
|
99
|
+
<description>Determine default branch and parse arguments</description>
|
|
100
|
+
<find_default_branch>
|
|
101
|
+
<command>git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'</command>
|
|
102
|
+
<fallback>git remote show origin | grep 'HEAD branch' | cut -d: -f2 | tr -d ' '</fallback>
|
|
103
|
+
<store_as>$DEFAULT_BRANCH (typically "main" or "master")</store_as>
|
|
104
|
+
</find_default_branch>
|
|
74
105
|
<input>The user-provided arguments</input>
|
|
75
|
-
<expected_format>branch-name-or-
|
|
106
|
+
<expected_format>branch-name-or-issue-url [optional-base-branch]</expected_format>
|
|
76
107
|
<example>fix/issue-123-main-content-area-visually-clipped main</example>
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
</
|
|
108
|
+
<example_issue_url>https://github.com/owner/project/issues/123 main</example_issue_url>
|
|
109
|
+
<base_branch>Use provided base branch, or $DEFAULT_BRANCH if not specified</base_branch>
|
|
110
|
+
</step_2>
|
|
80
111
|
|
|
81
112
|
<step_2_5>
|
|
82
|
-
<description>Handle
|
|
83
|
-
<condition>If first argument matches
|
|
84
|
-
<url_detection>
|
|
113
|
+
<description>Handle issue URLs from git hosting provider</description>
|
|
114
|
+
<condition>If first argument matches issue URL pattern (detected in step_0)</condition>
|
|
115
|
+
<url_detection>
|
|
116
|
+
<github>Check if argument contains "github.com" and "/issues/"</github>
|
|
117
|
+
<gitlab>Check if argument contains "gitlab.com" and "/-/issues/"</gitlab>
|
|
118
|
+
<bitbucket>Check if argument contains "bitbucket.org" and "/issues/"</bitbucket>
|
|
119
|
+
</url_detection>
|
|
85
120
|
<url_parsing>
|
|
86
|
-
<
|
|
121
|
+
<github_pattern><https://github.com/{owner}/{repo}/issues/{issue_number}></github_pattern>
|
|
122
|
+
<gitlab_pattern><https://gitlab.com/{owner}/{repo}/-/issues/{issue_number}></gitlab_pattern>
|
|
123
|
+
<bitbucket_pattern><https://bitbucket.org/{owner}/{repo}/issues/{issue_number}></bitbucket_pattern>
|
|
87
124
|
<extract>owner, repo, issue_number from URL</extract>
|
|
88
125
|
</url_parsing>
|
|
89
126
|
<fetch_issue_details>
|
|
90
|
-
<tool>
|
|
91
|
-
<method>get</method>
|
|
127
|
+
<tool>Use $GIT_HOST_TOOL from step_0</tool>
|
|
128
|
+
<method>get issue details</method>
|
|
92
129
|
<parameters>owner, repo, issue_number</parameters>
|
|
93
130
|
</fetch_issue_details>
|
|
94
131
|
<generate_branch_name>
|
|
95
132
|
<determine_type>Analyze issue title/labels to determine type (feat/fix/refactor/chore)</determine_type>
|
|
96
|
-
<format>{type}/
|
|
133
|
+
<format>{type}/issue-{issue_number}-{kebab-case-title}</format>
|
|
97
134
|
<kebab_case>Convert title to lowercase, replace spaces/special chars with hyphens</kebab_case>
|
|
98
135
|
<sanitization>
|
|
99
136
|
<rule>Always use lowercase for branch names</rule>
|
|
@@ -116,14 +153,32 @@ Uncommitted changes: !git status --short`
|
|
|
116
153
|
<title>"Fix duplicate items in list view"</title>
|
|
117
154
|
<generated>fix/issue-456-duplicate-items-in-list-view</generated>
|
|
118
155
|
</examples>
|
|
119
|
-
</
|
|
156
|
+
</step_2_5>
|
|
120
157
|
|
|
121
158
|
<step_3>
|
|
122
|
-
<description>
|
|
123
|
-
<condition>If output is not empty (has uncommitted changes)</condition>
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
159
|
+
<description>Handle uncommitted changes if any exist</description>
|
|
160
|
+
<condition>If git status --short output is not empty (has uncommitted changes)</condition>
|
|
161
|
+
<prompt>
|
|
162
|
+
<message>You have uncommitted changes. Move them to the new branch?</message>
|
|
163
|
+
<options>
|
|
164
|
+
<option value="yes">
|
|
165
|
+
<label>Yes</label>
|
|
166
|
+
<description>Stash changes and apply them in the new worktree</description>
|
|
167
|
+
</option>
|
|
168
|
+
<option value="no">
|
|
169
|
+
<label>No</label>
|
|
170
|
+
<description>Leave changes in current branch</description>
|
|
171
|
+
</option>
|
|
172
|
+
</options>
|
|
173
|
+
</prompt>
|
|
174
|
+
<if_yes>
|
|
175
|
+
<command>git add -A && git stash push -m "Worktree switch: Moving changes to ${branch_name}"</command>
|
|
176
|
+
<set_variable>$STASH_CREATED = true</set_variable>
|
|
177
|
+
</if_yes>
|
|
178
|
+
<if_no>
|
|
179
|
+
<set_variable>$STASH_CREATED = false</set_variable>
|
|
180
|
+
</if_no>
|
|
181
|
+
<purpose>Let user decide whether to move work in progress to new branch</purpose>
|
|
127
182
|
</step_3>
|
|
128
183
|
|
|
129
184
|
<step_4>
|
|
@@ -140,20 +195,20 @@ Uncommitted changes: !git status --short`
|
|
|
140
195
|
<step_5>
|
|
141
196
|
<description>Fetch latest changes from remote</description>
|
|
142
197
|
<command>git fetch origin</command>
|
|
143
|
-
<purpose>Ensure we have the latest remote branches and
|
|
144
|
-
<note>This ensures new worktrees are created from the most recent
|
|
145
|
-
</
|
|
198
|
+
<purpose>Ensure we have the latest remote branches and default branch state</purpose>
|
|
199
|
+
<note>This ensures new worktrees are created from the most recent default branch</note>
|
|
200
|
+
</step_5>
|
|
146
201
|
|
|
147
|
-
<
|
|
202
|
+
<step_6>
|
|
148
203
|
<description>Check if branch exists on remote</description>
|
|
149
204
|
<command>git branch -r | grep "origin/${branch_name}"</command>
|
|
150
205
|
<decision>
|
|
151
206
|
<if_exists>Branch exists on remote - will checkout existing branch</if_exists>
|
|
152
207
|
<if_not_exists>Branch does not exist - will create new branch from base</if_not_exists>
|
|
153
208
|
</decision>
|
|
154
|
-
</
|
|
209
|
+
</step_6>
|
|
155
210
|
|
|
156
|
-
<
|
|
211
|
+
<step_7>
|
|
157
212
|
<description>Create the worktree</description>
|
|
158
213
|
<option_a_new_branch>
|
|
159
214
|
<condition>Remote branch does NOT exist</condition>
|
|
@@ -167,8 +222,32 @@ Uncommitted changes: !git status --short`
|
|
|
167
222
|
</option_b_existing_branch>
|
|
168
223
|
</step_7>
|
|
169
224
|
|
|
225
|
+
<step_7b>
|
|
226
|
+
<description>Set up remote tracking for new branch</description>
|
|
227
|
+
<condition>Only if new branch was created (option_a from step_7)</condition>
|
|
228
|
+
<working_directory>${parent_path}/${branch_name}</working_directory>
|
|
229
|
+
<command>cd ${parent_path}/${branch_name} && git push -u origin ${branch_name}</command>
|
|
230
|
+
<purpose>Establish remote tracking so git status shows ahead/behind and git push/pull work without specifying remote</purpose>
|
|
231
|
+
<note>This creates the remote branch and sets upstream tracking in one step</note>
|
|
232
|
+
</step_7b>
|
|
233
|
+
|
|
234
|
+
<step_7c>
|
|
235
|
+
<description>Quick mode completion</description>
|
|
236
|
+
<condition>Only if $SETUP_MODE is "quick"</condition>
|
|
237
|
+
<message>Worktree created at: ${parent_path}/${branch_name}</message>
|
|
238
|
+
<suggested_next_steps>
|
|
239
|
+
<intro>You can now:</intro>
|
|
240
|
+
<suggestion priority="1">Open in VS Code: `code ${parent_path}/${branch_name}`</suggestion>
|
|
241
|
+
<suggestion priority="2">Open in Cursor: `cursor ${parent_path}/${branch_name}`</suggestion>
|
|
242
|
+
<suggestion priority="3">Navigate to it: `cd ${parent_path}/${branch_name}`</suggestion>
|
|
243
|
+
<suggestion priority="4">Install dependencies: `cd ${parent_path}/${branch_name} && pnpm install`</suggestion>
|
|
244
|
+
</suggested_next_steps>
|
|
245
|
+
<action>STOP here - do not continue to remaining steps</action>
|
|
246
|
+
</step_7c>
|
|
247
|
+
|
|
170
248
|
<step_8>
|
|
171
249
|
<description>Copy Claude settings to new worktree</description>
|
|
250
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
172
251
|
<source>.claude/settings.local.json</source>
|
|
173
252
|
<destination>${parent_path}/${branch_name}/.claude/settings.local.json</destination>
|
|
174
253
|
<command>cp -r .claude/settings.local.json ${parent_path}/${branch_name}/.claude/settings.local.json</command>
|
|
@@ -177,6 +256,7 @@ Uncommitted changes: !git status --short`
|
|
|
177
256
|
|
|
178
257
|
<step_9>
|
|
179
258
|
<description>Copy .env.local files to new worktree</description>
|
|
259
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
180
260
|
<search_command>find . -name ".env.local" -type f</search_command>
|
|
181
261
|
<copy_logic>For each .env.local file found, copy to corresponding location in new worktree</copy_logic>
|
|
182
262
|
<common_locations>
|
|
@@ -184,14 +264,14 @@ Uncommitted changes: !git status --short`
|
|
|
184
264
|
- packages/*/.env.local
|
|
185
265
|
- (any other .env.local files found)
|
|
186
266
|
</common_locations>
|
|
187
|
-
<copy_command>find . -name ".env.local" -type f -exec sh -c 'mkdir -p "$(dirname "${parent_path}/${branch_name}/$1")" && cp "$1" "${parent_path}/${branch_name}/$1"'
|
|
267
|
+
<copy_command>find . -name ".env.local" -type f -exec sh -c 'mkdir -p "$(dirname "${parent_path}/${branch_name}/$1")" && cp "$1" "${parent_path}/${branch_name}/$1"'_ {} \;</copy_command>
|
|
188
268
|
<purpose>Preserve local environment configurations for development</purpose>
|
|
189
269
|
<note>Only copies files that exist; ignores missing ones</note>
|
|
190
270
|
</step_9>
|
|
191
271
|
|
|
192
272
|
<step_10>
|
|
193
273
|
<description>Create IDE-specific configuration (conditional)</description>
|
|
194
|
-
<condition>Only if supports_tasks is true (VS Code variants)</condition>
|
|
274
|
+
<condition>Only if $SETUP_MODE is "full" AND supports_tasks is true (VS Code variants)</condition>
|
|
195
275
|
<vs_code_tasks>
|
|
196
276
|
<create_directory>mkdir -p ${parent_path}/${branch_name}/.vscode</create_directory>
|
|
197
277
|
<create_file_command>cat > ${parent_path}/${branch_name}/.vscode/tasks.json << 'EOF'
|
|
@@ -223,6 +303,7 @@ EOF</create_file_command>
|
|
|
223
303
|
|
|
224
304
|
<step_11>
|
|
225
305
|
<description>Install dependencies in new worktree</description>
|
|
306
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
226
307
|
<working_directory>${parent_path}/${branch_name}</working_directory>
|
|
227
308
|
<command>cd ${parent_path}/${branch_name} && pnpm install</command>
|
|
228
309
|
<purpose>Ensure all node_modules are installed for the new worktree</purpose>
|
|
@@ -230,7 +311,7 @@ EOF</create_file_command>
|
|
|
230
311
|
|
|
231
312
|
<step_12>
|
|
232
313
|
<description>Apply stashed changes to new worktree (if stash was created)</description>
|
|
233
|
-
<condition>Only if
|
|
314
|
+
<condition>Only if $SETUP_MODE is "full" AND $STASH_CREATED is true</condition>
|
|
234
315
|
<working_directory>${parent_path}/${branch_name}</working_directory>
|
|
235
316
|
<command>cd ${parent_path}/${branch_name} && git stash pop</command>
|
|
236
317
|
<purpose>Restore uncommitted work-in-progress to the new worktree branch</purpose>
|
|
@@ -239,6 +320,7 @@ EOF</create_file_command>
|
|
|
239
320
|
|
|
240
321
|
<step_13>
|
|
241
322
|
<description>Open detected IDE in new worktree</description>
|
|
323
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
242
324
|
<command>${ide_command} ${parent_path}/${branch_name}</command>
|
|
243
325
|
<ide_specific_behavior>
|
|
244
326
|
<vs_code_variants>Opens folder in VS Code/Insiders/Cursor with tasks.json auto-starting Claude</vs_code_variants>
|
|
@@ -247,12 +329,13 @@ EOF</create_file_command>
|
|
|
247
329
|
</ide_specific_behavior>
|
|
248
330
|
<purpose>Launch development environment for the new worktree using detected IDE</purpose>
|
|
249
331
|
<confirmation_message>Opening worktree in ${ide_name}</confirmation_message>
|
|
250
|
-
</
|
|
332
|
+
</step_13>
|
|
251
333
|
</execution_steps>
|
|
252
334
|
|
|
253
335
|
<important_notes>
|
|
254
336
|
|
|
255
|
-
-
|
|
337
|
+
- Offers Quick or Full setup mode - Quick just creates the worktree, Full does everything
|
|
338
|
+
- Automatically detects and uses your current IDE (VS Code, VS Code Insiders, Cursor, Zed, etc.) in Full mode
|
|
256
339
|
- Creates VS Code-specific tasks.json only for VS Code variants (auto-starts Claude on folder open)
|
|
257
340
|
- Branch names with slashes (feat/, fix/, etc.) are fully supported
|
|
258
341
|
- The worktree directory path will match the full branch name including slashes
|
|
@@ -262,4 +345,12 @@ EOF</create_file_command>
|
|
|
262
345
|
- Uncommitted changes are automatically stashed and moved to the new worktree
|
|
263
346
|
- Your work-in-progress seamlessly transfers to the new branch
|
|
264
347
|
- IDE detection fallback: checks available editors and uses priority order
|
|
348
|
+
- New branches are automatically pushed with `-u` to set up remote tracking
|
|
349
|
+
|
|
350
|
+
Limitations:
|
|
351
|
+
|
|
352
|
+
- Assumes remote is named "origin" (most common convention)
|
|
353
|
+
- Supports macOS and Linux only (no Windows support)
|
|
354
|
+
- Requires MCP server or CLI for git hosting provider when using issue URLs (GitHub, GitLab, etc.)
|
|
355
|
+
- Dependency install command is pnpm (modify for npm/yarn if needed)
|
|
265
356
|
</important_notes>
|
|
@@ -20,54 +20,71 @@ Clean up merged worktrees by finding the oldest merged branch, consolidating set
|
|
|
20
20
|
Additional info: $ARGUMENTS
|
|
21
21
|
|
|
22
22
|
<current_state>
|
|
23
|
-
Current branch:
|
|
24
|
-
Current worktrees:
|
|
23
|
+
Current branch: `git branch --show-current`
|
|
24
|
+
Current worktrees: `git worktree list`
|
|
25
25
|
</current_state>
|
|
26
26
|
|
|
27
27
|
<execution_steps>
|
|
28
28
|
<step_0>
|
|
29
|
-
<description>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
</
|
|
45
|
-
<
|
|
29
|
+
<description>Detect git hosting provider and available tools</description>
|
|
30
|
+
<detect_provider>
|
|
31
|
+
<check_remote_url>git remote get-url origin</check_remote_url>
|
|
32
|
+
<identify_host>
|
|
33
|
+
- github.com → GitHub
|
|
34
|
+
- gitlab.com → GitLab
|
|
35
|
+
- bitbucket.org → Bitbucket
|
|
36
|
+
- Other → Ask user
|
|
37
|
+
</identify_host>
|
|
38
|
+
</detect_provider>
|
|
39
|
+
<check_available_tools>
|
|
40
|
+
<list_mcp_servers>Check which git-hosting MCP servers are available (github, gitlab, etc.)</list_mcp_servers>
|
|
41
|
+
<check_cli>Check if gh/glab CLI is available as fallback</check_cli>
|
|
42
|
+
</check_available_tools>
|
|
43
|
+
<select_tool>
|
|
44
|
+
<if_single_mcp>If only one relevant MCP available, confirm with user</if_single_mcp>
|
|
45
|
+
<if_multiple>Let user choose which tool to use</if_multiple>
|
|
46
|
+
<if_told_earlier>If user specified tool earlier in conversation, use that without asking again</if_told_earlier>
|
|
47
|
+
<store_as>$GIT_HOST_TOOL (e.g., "github_mcp", "gitlab_mcp", "gh_cli")</store_as>
|
|
48
|
+
</select_tool>
|
|
49
|
+
|
|
50
|
+
<purpose>Detect git hosting provider and select appropriate tool for PR verification</purpose>
|
|
46
51
|
</step_0>
|
|
47
52
|
|
|
48
53
|
<step_1>
|
|
49
|
-
<description>
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
<description>Determine default branch and verify we're on it</description>
|
|
55
|
+
<find_default_branch>
|
|
56
|
+
<command>git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'</command>
|
|
57
|
+
<fallback>git remote show origin | grep 'HEAD branch' | cut -d: -f2 | tr -d ' '</fallback>
|
|
58
|
+
<store_as>$DEFAULT_BRANCH (typically "main" or "master")</store_as>
|
|
59
|
+
</find_default_branch>
|
|
60
|
+
<check_current_branch>git branch --show-current</check_current_branch>
|
|
61
|
+
<verify>Current branch must equal $DEFAULT_BRANCH</verify>
|
|
62
|
+
<error_if_not_default>Exit with error: "This command must be run from the default branch ($DEFAULT_BRANCH)"</error_if_not_default>
|
|
63
|
+
<purpose>Ensure we're consolidating to the default branch worktree</purpose>
|
|
54
64
|
</step_1>
|
|
55
65
|
|
|
56
66
|
<step_2>
|
|
57
67
|
<description>Get list of all worktrees</description>
|
|
58
68
|
<command>git worktree list --porcelain</command>
|
|
59
69
|
<parse_output>Extract worktree paths and branch names</parse_output>
|
|
60
|
-
<
|
|
70
|
+
<exclude_default>Filter out the default branch worktree from cleanup candidates</exclude_default>
|
|
61
71
|
<purpose>Identify all worktrees that could potentially be cleaned up</purpose>
|
|
62
72
|
</step_2>
|
|
63
73
|
|
|
64
74
|
<step_3>
|
|
65
75
|
<description>Find oldest worktree by directory age</description>
|
|
66
76
|
<get_worktree_ages>
|
|
67
|
-
<
|
|
68
|
-
<
|
|
77
|
+
<detect_platform>uname -s (returns "Darwin" for macOS, "Linux" for Linux)</detect_platform>
|
|
78
|
+
<command_macos>git worktree list | grep -v "\[$DEFAULT_BRANCH\]" | awk '{print $1}' > /tmp/worktrees-$$.txt && while IFS= read -r path; do echo "$(/usr/bin/stat -f '%Sm' -t '%Y-%m-%d %H:%M' "$path" 2>/dev/null)|$path"; done < /tmp/worktrees-$$.txt | sort; rm -f /tmp/worktrees-$$.txt</command_macos>
|
|
79
|
+
<command_linux>git worktree list | grep -v "\[$DEFAULT_BRANCH\]" | awk '{print $1}' > /tmp/worktrees-$$.txt && while IFS= read -r path; do echo "$(stat -c '%y' "$path" 2>/dev/null | cut -d. -f1)|$path"; done < /tmp/worktrees-$$.txt | sort; rm -f /tmp/worktrees-$$.txt</command_linux>
|
|
69
80
|
<purpose>List all worktrees sorted by directory modification time (oldest first)</purpose>
|
|
70
|
-
<
|
|
81
|
+
<critical_notes>
|
|
82
|
+
- Replace $DEFAULT_BRANCH with value from step_1 (e.g., "main" or "master")
|
|
83
|
+
- grep "\[branch\]" matches branch name in brackets, not paths containing the word
|
|
84
|
+
- Temp file approach avoids subshell parsing issues with piped while-loops
|
|
85
|
+
- /usr/bin/stat on macOS avoids homebrew stat conflicts
|
|
86
|
+
</critical_notes>
|
|
87
|
+
<expected_output_format>YYYY-MM-DD HH:MM|/full/path/to/worktree (oldest first)</expected_output_format>
|
|
71
88
|
</get_worktree_ages>
|
|
72
89
|
<filter_recent>
|
|
73
90
|
<exclude_new>For worktrees created within the last 24 hours, let user know that this worktree might not be worth cleaning</exclude_new>
|
|
@@ -78,28 +95,27 @@ Current worktrees: !git worktree list`
|
|
|
78
95
|
<important_note>DO NOT use "git branch --merged" to check merge status - it's unreliable</important_note>
|
|
79
96
|
<proceed_to_pr_check>Move directly to step 4 to verify PR merge status instead</proceed_to_pr_check>
|
|
80
97
|
</select_oldest>
|
|
81
|
-
<purpose>Identify oldest worktree candidate - actual merge verification happens via
|
|
98
|
+
<purpose>Identify oldest worktree candidate - actual merge verification happens via PR/MR in next step</purpose>
|
|
82
99
|
</step_3>
|
|
83
100
|
|
|
84
101
|
<step_4>
|
|
85
|
-
<description>Verify
|
|
102
|
+
<description>Verify PR/MR merge status (primary merge verification)</description>
|
|
86
103
|
<determine_repo>
|
|
87
104
|
<check_remote>git remote get-url origin</check_remote>
|
|
88
|
-
<parse_repo>Extract owner/repo from
|
|
89
|
-
<fallback>Use project repository from git remote (owner/repo format)</fallback>
|
|
105
|
+
<parse_repo>Extract owner/repo from remote URL</parse_repo>
|
|
90
106
|
</determine_repo>
|
|
91
107
|
<search_pr>
|
|
92
|
-
<tool>mcp__github__search_pull_requests</tool>
|
|
93
|
-
<query>
|
|
94
|
-
<purpose>Find PR for this branch targeting
|
|
108
|
+
<tool>Use $GIT_HOST_TOOL from step_0 (e.g., mcp__github__search_pull_requests, mcp__gitlab__*, or gh CLI)</tool>
|
|
109
|
+
<query>Find PRs/MRs where head={branch_name} and base=$DEFAULT_BRANCH</query>
|
|
110
|
+
<purpose>Find PR/MR for this branch targeting default branch</purpose>
|
|
95
111
|
<important>This is the PRIMARY way to verify if a branch was merged - NOT git commands</important>
|
|
96
112
|
</search_pr>
|
|
97
113
|
<verify_pr_merged>
|
|
98
114
|
<if_pr_found>
|
|
99
|
-
<get_pr_details>Use
|
|
100
|
-
<confirm_merged>Verify PR state is "closed" AND merged_at is not null AND base is "
|
|
101
|
-
<extract_issue_number>Look for issue references in PR title/body (e.g., #
|
|
102
|
-
<if_merged>Proceed with cleanup - this branch was definitively merged to
|
|
115
|
+
<get_pr_details>Use $GIT_HOST_TOOL to get full PR/MR info</get_pr_details>
|
|
116
|
+
<confirm_merged>Verify PR/MR state is "closed"/"merged" AND merged_at is not null AND base is "$DEFAULT_BRANCH"</confirm_merged>
|
|
117
|
+
<extract_issue_number>Look for issue references in PR title/body (e.g., #123, owner/repo#123)</extract_issue_number>
|
|
118
|
+
<if_merged>Proceed with cleanup - this branch was definitively merged to default branch</if_merged>
|
|
103
119
|
<if_not_merged>
|
|
104
120
|
<skip_worktree>This worktree is NOT merged - continue to next oldest worktree</skip_worktree>
|
|
105
121
|
<repeat_from_step_3>Go back and find the next oldest worktree to check</repeat_from_step_3>
|
|
@@ -110,15 +126,14 @@ Current worktrees: !git worktree list`
|
|
|
110
126
|
<continue_to_next>Continue checking next oldest worktree</continue_to_next>
|
|
111
127
|
</if_no_pr>
|
|
112
128
|
</verify_pr_merged>
|
|
113
|
-
<purpose>Use
|
|
129
|
+
<purpose>Use PR/MR status as the authoritative source for merge verification instead of unreliable git commands</purpose>
|
|
114
130
|
</step_4>
|
|
115
131
|
|
|
116
132
|
<step_4_5>
|
|
117
|
-
<description>Check and close related
|
|
133
|
+
<description>Check and close related issue</description>
|
|
118
134
|
<if_issue_found>
|
|
119
135
|
<get_issue_details>
|
|
120
|
-
<tool>
|
|
121
|
-
<method>get</method>
|
|
136
|
+
<tool>Use $GIT_HOST_TOOL to read issue details</tool>
|
|
122
137
|
<extract_repo>From issue reference (main-repo vs cross-repo)</extract_repo>
|
|
123
138
|
</get_issue_details>
|
|
124
139
|
<check_issue_state>
|
|
@@ -126,14 +141,13 @@ Current worktrees: !git worktree list`
|
|
|
126
141
|
<ask_close>Ask user: "Related issue #{number} is still open. Should I close it? (y/N)"</ask_close>
|
|
127
142
|
<if_yes_close>
|
|
128
143
|
<add_closing_comment>
|
|
129
|
-
<tool>
|
|
130
|
-
<body_template>Closing this issue as branch {branch_name} was merged to
|
|
131
|
-
<get_merge_date>Extract merge date from PR details</get_merge_date>
|
|
132
|
-
<get_pr_number>Use PR number from search results</get_pr_number>
|
|
144
|
+
<tool>Use $GIT_HOST_TOOL to add comment</tool>
|
|
145
|
+
<body_template>Closing this issue as branch {branch_name} was merged to {default_branch} on {merge_date} via PR/MR #{pr_number}.</body_template>
|
|
146
|
+
<get_merge_date>Extract merge date from PR/MR details</get_merge_date>
|
|
147
|
+
<get_pr_number>Use PR/MR number from search results</get_pr_number>
|
|
133
148
|
</add_closing_comment>
|
|
134
149
|
<close_issue>
|
|
135
|
-
<tool>
|
|
136
|
-
<method>update</method>
|
|
150
|
+
<tool>Use $GIT_HOST_TOOL to close issue</tool>
|
|
137
151
|
<state>closed</state>
|
|
138
152
|
<state_reason>completed</state_reason>
|
|
139
153
|
</close_issue>
|
|
@@ -215,17 +229,22 @@ Current worktrees: !git worktree list`
|
|
|
215
229
|
|
|
216
230
|
<important_notes>
|
|
217
231
|
|
|
218
|
-
- Uses
|
|
232
|
+
- Uses PR/MR merge status as the ONLY reliable way to verify if a branch was merged
|
|
219
233
|
- DOES NOT use "git branch --merged" command as it's unreliable for merge verification
|
|
220
|
-
- Only processes branches with PRs that were definitively merged to
|
|
221
|
-
- Skips worktrees without merged PRs and continues to next oldest candidate
|
|
222
|
-
- Checks and optionally closes related
|
|
234
|
+
- Only processes branches with PRs/MRs that were definitively merged to default branch
|
|
235
|
+
- Skips worktrees without merged PRs/MRs and continues to next oldest candidate
|
|
236
|
+
- Checks and optionally closes related issues
|
|
223
237
|
- Prioritizes oldest worktrees by directory age first for systematic cleanup
|
|
224
238
|
- Warns about very recent worktrees (created within 24 hours) to avoid cleaning active work
|
|
225
239
|
- Preserves useful development settings before deletion
|
|
226
240
|
- Requires explicit confirmation before any destructive actions
|
|
227
241
|
- Handles locked worktrees automatically
|
|
228
242
|
- Processes one worktree at a time to maintain control
|
|
229
|
-
- Must be run from
|
|
230
|
-
|
|
243
|
+
- Must be run from default branch for safety
|
|
244
|
+
|
|
245
|
+
Limitations:
|
|
246
|
+
|
|
247
|
+
- Assumes remote is named "origin" (most common convention)
|
|
248
|
+
- Supports macOS and Linux only (no Windows support)
|
|
249
|
+
- Requires MCP server or CLI for git hosting provider (GitHub, GitLab, etc.)
|
|
231
250
|
</important_notes>
|
|
@@ -125,7 +125,7 @@
|
|
|
125
125
|
"order": 1
|
|
126
126
|
},
|
|
127
127
|
"worktree-add.md": {
|
|
128
|
-
"description": "Add a new git worktree from branch name or
|
|
128
|
+
"description": "Add a new git worktree from branch name or issue URL, copy settings, install deps, and open in current IDE",
|
|
129
129
|
"hint": "Add worktree",
|
|
130
130
|
"category": "Worktree Management",
|
|
131
131
|
"order": 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Add a new git worktree from branch name or
|
|
3
|
-
argument-hint: <branch-name-or-
|
|
2
|
+
description: Add a new git worktree from branch name or issue URL, copy settings, install deps, and open in current IDE
|
|
3
|
+
argument-hint: <branch-name-or-issue-url> [optional-base-branch]
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Git Worktree Setup
|
|
@@ -16,35 +16,61 @@ argument-hint: <branch-name-or-github-issue-url> [optional-base-branch]
|
|
|
16
16
|
Create a new git worktree for branch: $ARGUMENTS
|
|
17
17
|
|
|
18
18
|
<current_state>
|
|
19
|
-
Current branch:
|
|
20
|
-
Current worktrees:
|
|
21
|
-
Remote branches:
|
|
22
|
-
Uncommitted changes:
|
|
19
|
+
Current branch: `git branch --show-current`
|
|
20
|
+
Current worktrees: `git worktree list`
|
|
21
|
+
Remote branches: `git branch -r`
|
|
22
|
+
Uncommitted changes: `git status --short`
|
|
23
23
|
</current_state>
|
|
24
24
|
|
|
25
25
|
<execution_steps>
|
|
26
26
|
<step_0>
|
|
27
|
-
<description>
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
</
|
|
43
|
-
<purpose>Ensure required MCP dependencies are available before proceeding</purpose>
|
|
27
|
+
<description>Ask user for setup mode</description>
|
|
28
|
+
<prompt>
|
|
29
|
+
<message>How would you like to set up the worktree?</message>
|
|
30
|
+
<options>
|
|
31
|
+
<option value="quick">
|
|
32
|
+
<label>Quick</label>
|
|
33
|
+
<description>Just create the worktree (skip deps, settings, IDE)</description>
|
|
34
|
+
</option>
|
|
35
|
+
<option value="full">
|
|
36
|
+
<label>Full setup</label>
|
|
37
|
+
<description>Install dependencies, copy settings, open in IDE</description>
|
|
38
|
+
</option>
|
|
39
|
+
</options>
|
|
40
|
+
</prompt>
|
|
41
|
+
<set_variable>$SETUP_MODE = user selection ("quick" or "full")</set_variable>
|
|
42
|
+
<purpose>Allow quick worktree creation when user just needs the branch</purpose>
|
|
44
43
|
</step_0>
|
|
45
44
|
|
|
45
|
+
<step_0b>
|
|
46
|
+
<description>Detect git hosting provider and available tools (only needed if argument is an issue URL)</description>
|
|
47
|
+
<condition>Only run this step if first argument looks like a git hosting URL</condition>
|
|
48
|
+
<detect_provider>
|
|
49
|
+
<check_remote_url>git remote get-url origin</check_remote_url>
|
|
50
|
+
<identify_host>
|
|
51
|
+
- github.com → GitHub
|
|
52
|
+
- gitlab.com → GitLab
|
|
53
|
+
- bitbucket.org → Bitbucket
|
|
54
|
+
- Other → Ask user
|
|
55
|
+
</identify_host>
|
|
56
|
+
</detect_provider>
|
|
57
|
+
<check_available_tools>
|
|
58
|
+
<list_mcp_servers>Check which git-hosting MCP servers are available (github, gitlab, etc.)</list_mcp_servers>
|
|
59
|
+
<check_cli>Check if gh/glab CLI is available as fallback</check_cli>
|
|
60
|
+
</check_available_tools>
|
|
61
|
+
<select_tool>
|
|
62
|
+
<if_single_mcp>If only one relevant MCP available, confirm with user</if_single_mcp>
|
|
63
|
+
<if_multiple>Let user choose which tool to use</if_multiple>
|
|
64
|
+
<if_told_earlier>If user specified tool earlier in conversation, use that without asking again</if_told_earlier>
|
|
65
|
+
<store_as>$GIT_HOST_TOOL (e.g., "github_mcp", "gitlab_mcp", "gh_cli")</store_as>
|
|
66
|
+
</select_tool>
|
|
67
|
+
|
|
68
|
+
<purpose>Detect git hosting provider and select appropriate tool for issue lookup</purpose>
|
|
69
|
+
</step_0b>
|
|
70
|
+
|
|
46
71
|
<step_1>
|
|
47
72
|
<description>Detect current IDE environment</description>
|
|
73
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
48
74
|
<detection_methods>
|
|
49
75
|
<method_1>
|
|
50
76
|
<tool>mcp__ide__getDiagnostics</tool>
|
|
@@ -68,30 +94,41 @@ Uncommitted changes: !git status --short`
|
|
|
68
94
|
</step_1>
|
|
69
95
|
|
|
70
96
|
<step_2>
|
|
71
|
-
<description>
|
|
97
|
+
<description>Determine default branch and parse arguments</description>
|
|
98
|
+
<find_default_branch>
|
|
99
|
+
<command>git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'</command>
|
|
100
|
+
<fallback>git remote show origin | grep 'HEAD branch' | cut -d: -f2 | tr -d ' '</fallback>
|
|
101
|
+
<store_as>$DEFAULT_BRANCH (typically "main" or "master")</store_as>
|
|
102
|
+
</find_default_branch>
|
|
72
103
|
<input>The user-provided arguments</input>
|
|
73
|
-
<expected_format>branch-name-or-
|
|
104
|
+
<expected_format>branch-name-or-issue-url [optional-base-branch]</expected_format>
|
|
74
105
|
<example>fix/issue-123-main-content-area-visually-clipped main</example>
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
</
|
|
106
|
+
<example_issue_url>https://github.com/owner/project/issues/123 main</example_issue_url>
|
|
107
|
+
<base_branch>Use provided base branch, or $DEFAULT_BRANCH if not specified</base_branch>
|
|
108
|
+
</step_2>
|
|
78
109
|
|
|
79
110
|
<step_2_5>
|
|
80
|
-
<description>Handle
|
|
81
|
-
<condition>If first argument matches
|
|
82
|
-
<url_detection>
|
|
111
|
+
<description>Handle issue URLs from git hosting provider</description>
|
|
112
|
+
<condition>If first argument matches issue URL pattern (detected in step_0)</condition>
|
|
113
|
+
<url_detection>
|
|
114
|
+
<github>Check if argument contains "github.com" and "/issues/"</github>
|
|
115
|
+
<gitlab>Check if argument contains "gitlab.com" and "/-/issues/"</gitlab>
|
|
116
|
+
<bitbucket>Check if argument contains "bitbucket.org" and "/issues/"</bitbucket>
|
|
117
|
+
</url_detection>
|
|
83
118
|
<url_parsing>
|
|
84
|
-
<
|
|
119
|
+
<github_pattern><https://github.com/{owner}/{repo}/issues/{issue_number}></github_pattern>
|
|
120
|
+
<gitlab_pattern><https://gitlab.com/{owner}/{repo}/-/issues/{issue_number}></gitlab_pattern>
|
|
121
|
+
<bitbucket_pattern><https://bitbucket.org/{owner}/{repo}/issues/{issue_number}></bitbucket_pattern>
|
|
85
122
|
<extract>owner, repo, issue_number from URL</extract>
|
|
86
123
|
</url_parsing>
|
|
87
124
|
<fetch_issue_details>
|
|
88
|
-
<tool>
|
|
89
|
-
<method>get</method>
|
|
125
|
+
<tool>Use $GIT_HOST_TOOL from step_0</tool>
|
|
126
|
+
<method>get issue details</method>
|
|
90
127
|
<parameters>owner, repo, issue_number</parameters>
|
|
91
128
|
</fetch_issue_details>
|
|
92
129
|
<generate_branch_name>
|
|
93
130
|
<determine_type>Analyze issue title/labels to determine type (feat/fix/refactor/chore)</determine_type>
|
|
94
|
-
<format>{type}/
|
|
131
|
+
<format>{type}/issue-{issue_number}-{kebab-case-title}</format>
|
|
95
132
|
<kebab_case>Convert title to lowercase, replace spaces/special chars with hyphens</kebab_case>
|
|
96
133
|
<sanitization>
|
|
97
134
|
<rule>Always use lowercase for branch names</rule>
|
|
@@ -114,14 +151,32 @@ Uncommitted changes: !git status --short`
|
|
|
114
151
|
<title>"Fix duplicate items in list view"</title>
|
|
115
152
|
<generated>fix/issue-456-duplicate-items-in-list-view</generated>
|
|
116
153
|
</examples>
|
|
117
|
-
</
|
|
154
|
+
</step_2_5>
|
|
118
155
|
|
|
119
156
|
<step_3>
|
|
120
|
-
<description>
|
|
121
|
-
<condition>If output is not empty (has uncommitted changes)</condition>
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
157
|
+
<description>Handle uncommitted changes if any exist</description>
|
|
158
|
+
<condition>If git status --short output is not empty (has uncommitted changes)</condition>
|
|
159
|
+
<prompt>
|
|
160
|
+
<message>You have uncommitted changes. Move them to the new branch?</message>
|
|
161
|
+
<options>
|
|
162
|
+
<option value="yes">
|
|
163
|
+
<label>Yes</label>
|
|
164
|
+
<description>Stash changes and apply them in the new worktree</description>
|
|
165
|
+
</option>
|
|
166
|
+
<option value="no">
|
|
167
|
+
<label>No</label>
|
|
168
|
+
<description>Leave changes in current branch</description>
|
|
169
|
+
</option>
|
|
170
|
+
</options>
|
|
171
|
+
</prompt>
|
|
172
|
+
<if_yes>
|
|
173
|
+
<command>git add -A && git stash push -m "Worktree switch: Moving changes to ${branch_name}"</command>
|
|
174
|
+
<set_variable>$STASH_CREATED = true</set_variable>
|
|
175
|
+
</if_yes>
|
|
176
|
+
<if_no>
|
|
177
|
+
<set_variable>$STASH_CREATED = false</set_variable>
|
|
178
|
+
</if_no>
|
|
179
|
+
<purpose>Let user decide whether to move work in progress to new branch</purpose>
|
|
125
180
|
</step_3>
|
|
126
181
|
|
|
127
182
|
<step_4>
|
|
@@ -138,20 +193,20 @@ Uncommitted changes: !git status --short`
|
|
|
138
193
|
<step_5>
|
|
139
194
|
<description>Fetch latest changes from remote</description>
|
|
140
195
|
<command>git fetch origin</command>
|
|
141
|
-
<purpose>Ensure we have the latest remote branches and
|
|
142
|
-
<note>This ensures new worktrees are created from the most recent
|
|
143
|
-
</
|
|
196
|
+
<purpose>Ensure we have the latest remote branches and default branch state</purpose>
|
|
197
|
+
<note>This ensures new worktrees are created from the most recent default branch</note>
|
|
198
|
+
</step_5>
|
|
144
199
|
|
|
145
|
-
<
|
|
200
|
+
<step_6>
|
|
146
201
|
<description>Check if branch exists on remote</description>
|
|
147
202
|
<command>git branch -r | grep "origin/${branch_name}"</command>
|
|
148
203
|
<decision>
|
|
149
204
|
<if_exists>Branch exists on remote - will checkout existing branch</if_exists>
|
|
150
205
|
<if_not_exists>Branch does not exist - will create new branch from base</if_not_exists>
|
|
151
206
|
</decision>
|
|
152
|
-
</
|
|
207
|
+
</step_6>
|
|
153
208
|
|
|
154
|
-
<
|
|
209
|
+
<step_7>
|
|
155
210
|
<description>Create the worktree</description>
|
|
156
211
|
<option_a_new_branch>
|
|
157
212
|
<condition>Remote branch does NOT exist</condition>
|
|
@@ -165,8 +220,32 @@ Uncommitted changes: !git status --short`
|
|
|
165
220
|
</option_b_existing_branch>
|
|
166
221
|
</step_7>
|
|
167
222
|
|
|
223
|
+
<step_7b>
|
|
224
|
+
<description>Set up remote tracking for new branch</description>
|
|
225
|
+
<condition>Only if new branch was created (option_a from step_7)</condition>
|
|
226
|
+
<working_directory>${parent_path}/${branch_name}</working_directory>
|
|
227
|
+
<command>cd ${parent_path}/${branch_name} && git push -u origin ${branch_name}</command>
|
|
228
|
+
<purpose>Establish remote tracking so git status shows ahead/behind and git push/pull work without specifying remote</purpose>
|
|
229
|
+
<note>This creates the remote branch and sets upstream tracking in one step</note>
|
|
230
|
+
</step_7b>
|
|
231
|
+
|
|
232
|
+
<step_7c>
|
|
233
|
+
<description>Quick mode completion</description>
|
|
234
|
+
<condition>Only if $SETUP_MODE is "quick"</condition>
|
|
235
|
+
<message>Worktree created at: ${parent_path}/${branch_name}</message>
|
|
236
|
+
<suggested_next_steps>
|
|
237
|
+
<intro>You can now:</intro>
|
|
238
|
+
<suggestion priority="1">Open in VS Code: `code ${parent_path}/${branch_name}`</suggestion>
|
|
239
|
+
<suggestion priority="2">Open in Cursor: `cursor ${parent_path}/${branch_name}`</suggestion>
|
|
240
|
+
<suggestion priority="3">Navigate to it: `cd ${parent_path}/${branch_name}`</suggestion>
|
|
241
|
+
<suggestion priority="4">Install dependencies: `cd ${parent_path}/${branch_name} && pnpm install`</suggestion>
|
|
242
|
+
</suggested_next_steps>
|
|
243
|
+
<action>STOP here - do not continue to remaining steps</action>
|
|
244
|
+
</step_7c>
|
|
245
|
+
|
|
168
246
|
<step_8>
|
|
169
247
|
<description>Copy Claude settings to new worktree</description>
|
|
248
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
170
249
|
<source>.claude/settings.local.json</source>
|
|
171
250
|
<destination>${parent_path}/${branch_name}/.claude/settings.local.json</destination>
|
|
172
251
|
<command>cp -r .claude/settings.local.json ${parent_path}/${branch_name}/.claude/settings.local.json</command>
|
|
@@ -175,6 +254,7 @@ Uncommitted changes: !git status --short`
|
|
|
175
254
|
|
|
176
255
|
<step_9>
|
|
177
256
|
<description>Copy .env.local files to new worktree</description>
|
|
257
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
178
258
|
<search_command>find . -name ".env.local" -type f</search_command>
|
|
179
259
|
<copy_logic>For each .env.local file found, copy to corresponding location in new worktree</copy_logic>
|
|
180
260
|
<common_locations>
|
|
@@ -182,14 +262,14 @@ Uncommitted changes: !git status --short`
|
|
|
182
262
|
- packages/*/.env.local
|
|
183
263
|
- (any other .env.local files found)
|
|
184
264
|
</common_locations>
|
|
185
|
-
<copy_command>find . -name ".env.local" -type f -exec sh -c 'mkdir -p "$(dirname "${parent_path}/${branch_name}/$1")" && cp "$1" "${parent_path}/${branch_name}/$1"'
|
|
265
|
+
<copy_command>find . -name ".env.local" -type f -exec sh -c 'mkdir -p "$(dirname "${parent_path}/${branch_name}/$1")" && cp "$1" "${parent_path}/${branch_name}/$1"'_ {} \;</copy_command>
|
|
186
266
|
<purpose>Preserve local environment configurations for development</purpose>
|
|
187
267
|
<note>Only copies files that exist; ignores missing ones</note>
|
|
188
268
|
</step_9>
|
|
189
269
|
|
|
190
270
|
<step_10>
|
|
191
271
|
<description>Create IDE-specific configuration (conditional)</description>
|
|
192
|
-
<condition>Only if supports_tasks is true (VS Code variants)</condition>
|
|
272
|
+
<condition>Only if $SETUP_MODE is "full" AND supports_tasks is true (VS Code variants)</condition>
|
|
193
273
|
<vs_code_tasks>
|
|
194
274
|
<create_directory>mkdir -p ${parent_path}/${branch_name}/.vscode</create_directory>
|
|
195
275
|
<create_file_command>cat > ${parent_path}/${branch_name}/.vscode/tasks.json << 'EOF'
|
|
@@ -221,6 +301,7 @@ EOF</create_file_command>
|
|
|
221
301
|
|
|
222
302
|
<step_11>
|
|
223
303
|
<description>Install dependencies in new worktree</description>
|
|
304
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
224
305
|
<working_directory>${parent_path}/${branch_name}</working_directory>
|
|
225
306
|
<command>cd ${parent_path}/${branch_name} && pnpm install</command>
|
|
226
307
|
<purpose>Ensure all node_modules are installed for the new worktree</purpose>
|
|
@@ -228,7 +309,7 @@ EOF</create_file_command>
|
|
|
228
309
|
|
|
229
310
|
<step_12>
|
|
230
311
|
<description>Apply stashed changes to new worktree (if stash was created)</description>
|
|
231
|
-
<condition>Only if
|
|
312
|
+
<condition>Only if $SETUP_MODE is "full" AND $STASH_CREATED is true</condition>
|
|
232
313
|
<working_directory>${parent_path}/${branch_name}</working_directory>
|
|
233
314
|
<command>cd ${parent_path}/${branch_name} && git stash pop</command>
|
|
234
315
|
<purpose>Restore uncommitted work-in-progress to the new worktree branch</purpose>
|
|
@@ -237,6 +318,7 @@ EOF</create_file_command>
|
|
|
237
318
|
|
|
238
319
|
<step_13>
|
|
239
320
|
<description>Open detected IDE in new worktree</description>
|
|
321
|
+
<condition>Only if $SETUP_MODE is "full"</condition>
|
|
240
322
|
<command>${ide_command} ${parent_path}/${branch_name}</command>
|
|
241
323
|
<ide_specific_behavior>
|
|
242
324
|
<vs_code_variants>Opens folder in VS Code/Insiders/Cursor with tasks.json auto-starting Claude</vs_code_variants>
|
|
@@ -245,12 +327,13 @@ EOF</create_file_command>
|
|
|
245
327
|
</ide_specific_behavior>
|
|
246
328
|
<purpose>Launch development environment for the new worktree using detected IDE</purpose>
|
|
247
329
|
<confirmation_message>Opening worktree in ${ide_name}</confirmation_message>
|
|
248
|
-
</
|
|
330
|
+
</step_13>
|
|
249
331
|
</execution_steps>
|
|
250
332
|
|
|
251
333
|
<important_notes>
|
|
252
334
|
|
|
253
|
-
-
|
|
335
|
+
- Offers Quick or Full setup mode - Quick just creates the worktree, Full does everything
|
|
336
|
+
- Automatically detects and uses your current IDE (VS Code, VS Code Insiders, Cursor, Zed, etc.) in Full mode
|
|
254
337
|
- Creates VS Code-specific tasks.json only for VS Code variants (auto-starts Claude on folder open)
|
|
255
338
|
- Branch names with slashes (feat/, fix/, etc.) are fully supported
|
|
256
339
|
- The worktree directory path will match the full branch name including slashes
|
|
@@ -260,4 +343,12 @@ EOF</create_file_command>
|
|
|
260
343
|
- Uncommitted changes are automatically stashed and moved to the new worktree
|
|
261
344
|
- Your work-in-progress seamlessly transfers to the new branch
|
|
262
345
|
- IDE detection fallback: checks available editors and uses priority order
|
|
346
|
+
- New branches are automatically pushed with `-u` to set up remote tracking
|
|
347
|
+
|
|
348
|
+
Limitations:
|
|
349
|
+
|
|
350
|
+
- Assumes remote is named "origin" (most common convention)
|
|
351
|
+
- Supports macOS and Linux only (no Windows support)
|
|
352
|
+
- Requires MCP server or CLI for git hosting provider when using issue URLs (GitHub, GitLab, etc.)
|
|
353
|
+
- Dependency install command is pnpm (modify for npm/yarn if needed)
|
|
263
354
|
</important_notes>
|
|
@@ -18,54 +18,71 @@ Clean up merged worktrees by finding the oldest merged branch, consolidating set
|
|
|
18
18
|
Additional info: $ARGUMENTS
|
|
19
19
|
|
|
20
20
|
<current_state>
|
|
21
|
-
Current branch:
|
|
22
|
-
Current worktrees:
|
|
21
|
+
Current branch: `git branch --show-current`
|
|
22
|
+
Current worktrees: `git worktree list`
|
|
23
23
|
</current_state>
|
|
24
24
|
|
|
25
25
|
<execution_steps>
|
|
26
26
|
<step_0>
|
|
27
|
-
<description>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
</
|
|
43
|
-
<
|
|
27
|
+
<description>Detect git hosting provider and available tools</description>
|
|
28
|
+
<detect_provider>
|
|
29
|
+
<check_remote_url>git remote get-url origin</check_remote_url>
|
|
30
|
+
<identify_host>
|
|
31
|
+
- github.com → GitHub
|
|
32
|
+
- gitlab.com → GitLab
|
|
33
|
+
- bitbucket.org → Bitbucket
|
|
34
|
+
- Other → Ask user
|
|
35
|
+
</identify_host>
|
|
36
|
+
</detect_provider>
|
|
37
|
+
<check_available_tools>
|
|
38
|
+
<list_mcp_servers>Check which git-hosting MCP servers are available (github, gitlab, etc.)</list_mcp_servers>
|
|
39
|
+
<check_cli>Check if gh/glab CLI is available as fallback</check_cli>
|
|
40
|
+
</check_available_tools>
|
|
41
|
+
<select_tool>
|
|
42
|
+
<if_single_mcp>If only one relevant MCP available, confirm with user</if_single_mcp>
|
|
43
|
+
<if_multiple>Let user choose which tool to use</if_multiple>
|
|
44
|
+
<if_told_earlier>If user specified tool earlier in conversation, use that without asking again</if_told_earlier>
|
|
45
|
+
<store_as>$GIT_HOST_TOOL (e.g., "github_mcp", "gitlab_mcp", "gh_cli")</store_as>
|
|
46
|
+
</select_tool>
|
|
47
|
+
|
|
48
|
+
<purpose>Detect git hosting provider and select appropriate tool for PR verification</purpose>
|
|
44
49
|
</step_0>
|
|
45
50
|
|
|
46
51
|
<step_1>
|
|
47
|
-
<description>
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
<description>Determine default branch and verify we're on it</description>
|
|
53
|
+
<find_default_branch>
|
|
54
|
+
<command>git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'</command>
|
|
55
|
+
<fallback>git remote show origin | grep 'HEAD branch' | cut -d: -f2 | tr -d ' '</fallback>
|
|
56
|
+
<store_as>$DEFAULT_BRANCH (typically "main" or "master")</store_as>
|
|
57
|
+
</find_default_branch>
|
|
58
|
+
<check_current_branch>git branch --show-current</check_current_branch>
|
|
59
|
+
<verify>Current branch must equal $DEFAULT_BRANCH</verify>
|
|
60
|
+
<error_if_not_default>Exit with error: "This command must be run from the default branch ($DEFAULT_BRANCH)"</error_if_not_default>
|
|
61
|
+
<purpose>Ensure we're consolidating to the default branch worktree</purpose>
|
|
52
62
|
</step_1>
|
|
53
63
|
|
|
54
64
|
<step_2>
|
|
55
65
|
<description>Get list of all worktrees</description>
|
|
56
66
|
<command>git worktree list --porcelain</command>
|
|
57
67
|
<parse_output>Extract worktree paths and branch names</parse_output>
|
|
58
|
-
<
|
|
68
|
+
<exclude_default>Filter out the default branch worktree from cleanup candidates</exclude_default>
|
|
59
69
|
<purpose>Identify all worktrees that could potentially be cleaned up</purpose>
|
|
60
70
|
</step_2>
|
|
61
71
|
|
|
62
72
|
<step_3>
|
|
63
73
|
<description>Find oldest worktree by directory age</description>
|
|
64
74
|
<get_worktree_ages>
|
|
65
|
-
<
|
|
66
|
-
<
|
|
75
|
+
<detect_platform>uname -s (returns "Darwin" for macOS, "Linux" for Linux)</detect_platform>
|
|
76
|
+
<command_macos>git worktree list | grep -v "\[$DEFAULT_BRANCH\]" | awk '{print $1}' > /tmp/worktrees-$$.txt && while IFS= read -r path; do echo "$(/usr/bin/stat -f '%Sm' -t '%Y-%m-%d %H:%M' "$path" 2>/dev/null)|$path"; done < /tmp/worktrees-$$.txt | sort; rm -f /tmp/worktrees-$$.txt</command_macos>
|
|
77
|
+
<command_linux>git worktree list | grep -v "\[$DEFAULT_BRANCH\]" | awk '{print $1}' > /tmp/worktrees-$$.txt && while IFS= read -r path; do echo "$(stat -c '%y' "$path" 2>/dev/null | cut -d. -f1)|$path"; done < /tmp/worktrees-$$.txt | sort; rm -f /tmp/worktrees-$$.txt</command_linux>
|
|
67
78
|
<purpose>List all worktrees sorted by directory modification time (oldest first)</purpose>
|
|
68
|
-
<
|
|
79
|
+
<critical_notes>
|
|
80
|
+
- Replace $DEFAULT_BRANCH with value from step_1 (e.g., "main" or "master")
|
|
81
|
+
- grep "\[branch\]" matches branch name in brackets, not paths containing the word
|
|
82
|
+
- Temp file approach avoids subshell parsing issues with piped while-loops
|
|
83
|
+
- /usr/bin/stat on macOS avoids homebrew stat conflicts
|
|
84
|
+
</critical_notes>
|
|
85
|
+
<expected_output_format>YYYY-MM-DD HH:MM|/full/path/to/worktree (oldest first)</expected_output_format>
|
|
69
86
|
</get_worktree_ages>
|
|
70
87
|
<filter_recent>
|
|
71
88
|
<exclude_new>For worktrees created within the last 24 hours, let user know that this worktree might not be worth cleaning</exclude_new>
|
|
@@ -76,28 +93,27 @@ Current worktrees: !git worktree list`
|
|
|
76
93
|
<important_note>DO NOT use "git branch --merged" to check merge status - it's unreliable</important_note>
|
|
77
94
|
<proceed_to_pr_check>Move directly to step 4 to verify PR merge status instead</proceed_to_pr_check>
|
|
78
95
|
</select_oldest>
|
|
79
|
-
<purpose>Identify oldest worktree candidate - actual merge verification happens via
|
|
96
|
+
<purpose>Identify oldest worktree candidate - actual merge verification happens via PR/MR in next step</purpose>
|
|
80
97
|
</step_3>
|
|
81
98
|
|
|
82
99
|
<step_4>
|
|
83
|
-
<description>Verify
|
|
100
|
+
<description>Verify PR/MR merge status (primary merge verification)</description>
|
|
84
101
|
<determine_repo>
|
|
85
102
|
<check_remote>git remote get-url origin</check_remote>
|
|
86
|
-
<parse_repo>Extract owner/repo from
|
|
87
|
-
<fallback>Use project repository from git remote (owner/repo format)</fallback>
|
|
103
|
+
<parse_repo>Extract owner/repo from remote URL</parse_repo>
|
|
88
104
|
</determine_repo>
|
|
89
105
|
<search_pr>
|
|
90
|
-
<tool>mcp__github__search_pull_requests</tool>
|
|
91
|
-
<query>
|
|
92
|
-
<purpose>Find PR for this branch targeting
|
|
106
|
+
<tool>Use $GIT_HOST_TOOL from step_0 (e.g., mcp__github__search_pull_requests, mcp__gitlab__*, or gh CLI)</tool>
|
|
107
|
+
<query>Find PRs/MRs where head={branch_name} and base=$DEFAULT_BRANCH</query>
|
|
108
|
+
<purpose>Find PR/MR for this branch targeting default branch</purpose>
|
|
93
109
|
<important>This is the PRIMARY way to verify if a branch was merged - NOT git commands</important>
|
|
94
110
|
</search_pr>
|
|
95
111
|
<verify_pr_merged>
|
|
96
112
|
<if_pr_found>
|
|
97
|
-
<get_pr_details>Use
|
|
98
|
-
<confirm_merged>Verify PR state is "closed" AND merged_at is not null AND base is "
|
|
99
|
-
<extract_issue_number>Look for issue references in PR title/body (e.g., #
|
|
100
|
-
<if_merged>Proceed with cleanup - this branch was definitively merged to
|
|
113
|
+
<get_pr_details>Use $GIT_HOST_TOOL to get full PR/MR info</get_pr_details>
|
|
114
|
+
<confirm_merged>Verify PR/MR state is "closed"/"merged" AND merged_at is not null AND base is "$DEFAULT_BRANCH"</confirm_merged>
|
|
115
|
+
<extract_issue_number>Look for issue references in PR title/body (e.g., #123, owner/repo#123)</extract_issue_number>
|
|
116
|
+
<if_merged>Proceed with cleanup - this branch was definitively merged to default branch</if_merged>
|
|
101
117
|
<if_not_merged>
|
|
102
118
|
<skip_worktree>This worktree is NOT merged - continue to next oldest worktree</skip_worktree>
|
|
103
119
|
<repeat_from_step_3>Go back and find the next oldest worktree to check</repeat_from_step_3>
|
|
@@ -108,15 +124,14 @@ Current worktrees: !git worktree list`
|
|
|
108
124
|
<continue_to_next>Continue checking next oldest worktree</continue_to_next>
|
|
109
125
|
</if_no_pr>
|
|
110
126
|
</verify_pr_merged>
|
|
111
|
-
<purpose>Use
|
|
127
|
+
<purpose>Use PR/MR status as the authoritative source for merge verification instead of unreliable git commands</purpose>
|
|
112
128
|
</step_4>
|
|
113
129
|
|
|
114
130
|
<step_4_5>
|
|
115
|
-
<description>Check and close related
|
|
131
|
+
<description>Check and close related issue</description>
|
|
116
132
|
<if_issue_found>
|
|
117
133
|
<get_issue_details>
|
|
118
|
-
<tool>
|
|
119
|
-
<method>get</method>
|
|
134
|
+
<tool>Use $GIT_HOST_TOOL to read issue details</tool>
|
|
120
135
|
<extract_repo>From issue reference (main-repo vs cross-repo)</extract_repo>
|
|
121
136
|
</get_issue_details>
|
|
122
137
|
<check_issue_state>
|
|
@@ -124,14 +139,13 @@ Current worktrees: !git worktree list`
|
|
|
124
139
|
<ask_close>Ask user: "Related issue #{number} is still open. Should I close it? (y/N)"</ask_close>
|
|
125
140
|
<if_yes_close>
|
|
126
141
|
<add_closing_comment>
|
|
127
|
-
<tool>
|
|
128
|
-
<body_template>Closing this issue as branch {branch_name} was merged to
|
|
129
|
-
<get_merge_date>Extract merge date from PR details</get_merge_date>
|
|
130
|
-
<get_pr_number>Use PR number from search results</get_pr_number>
|
|
142
|
+
<tool>Use $GIT_HOST_TOOL to add comment</tool>
|
|
143
|
+
<body_template>Closing this issue as branch {branch_name} was merged to {default_branch} on {merge_date} via PR/MR #{pr_number}.</body_template>
|
|
144
|
+
<get_merge_date>Extract merge date from PR/MR details</get_merge_date>
|
|
145
|
+
<get_pr_number>Use PR/MR number from search results</get_pr_number>
|
|
131
146
|
</add_closing_comment>
|
|
132
147
|
<close_issue>
|
|
133
|
-
<tool>
|
|
134
|
-
<method>update</method>
|
|
148
|
+
<tool>Use $GIT_HOST_TOOL to close issue</tool>
|
|
135
149
|
<state>closed</state>
|
|
136
150
|
<state_reason>completed</state_reason>
|
|
137
151
|
</close_issue>
|
|
@@ -213,17 +227,22 @@ Current worktrees: !git worktree list`
|
|
|
213
227
|
|
|
214
228
|
<important_notes>
|
|
215
229
|
|
|
216
|
-
- Uses
|
|
230
|
+
- Uses PR/MR merge status as the ONLY reliable way to verify if a branch was merged
|
|
217
231
|
- DOES NOT use "git branch --merged" command as it's unreliable for merge verification
|
|
218
|
-
- Only processes branches with PRs that were definitively merged to
|
|
219
|
-
- Skips worktrees without merged PRs and continues to next oldest candidate
|
|
220
|
-
- Checks and optionally closes related
|
|
232
|
+
- Only processes branches with PRs/MRs that were definitively merged to default branch
|
|
233
|
+
- Skips worktrees without merged PRs/MRs and continues to next oldest candidate
|
|
234
|
+
- Checks and optionally closes related issues
|
|
221
235
|
- Prioritizes oldest worktrees by directory age first for systematic cleanup
|
|
222
236
|
- Warns about very recent worktrees (created within 24 hours) to avoid cleaning active work
|
|
223
237
|
- Preserves useful development settings before deletion
|
|
224
238
|
- Requires explicit confirmation before any destructive actions
|
|
225
239
|
- Handles locked worktrees automatically
|
|
226
240
|
- Processes one worktree at a time to maintain control
|
|
227
|
-
- Must be run from
|
|
228
|
-
|
|
241
|
+
- Must be run from default branch for safety
|
|
242
|
+
|
|
243
|
+
Limitations:
|
|
244
|
+
|
|
245
|
+
- Assumes remote is named "origin" (most common convention)
|
|
246
|
+
- Supports macOS and Linux only (no Windows support)
|
|
247
|
+
- Requires MCP server or CLI for git hosting provider (GitHub, GitLab, etc.)
|
|
229
248
|
</important_notes>
|