sequant 2.0.0 โ†’ 2.1.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.
Files changed (61) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +7 -6
  4. package/dist/bin/cli.js +2 -1
  5. package/dist/marketplace/external_plugins/sequant/.claude-plugin/plugin.json +1 -1
  6. package/dist/marketplace/external_plugins/sequant/.mcp.json +6 -0
  7. package/dist/marketplace/external_plugins/sequant/README.md +58 -8
  8. package/dist/marketplace/external_plugins/sequant/hooks/post-tool.sh +19 -8
  9. package/dist/marketplace/external_plugins/sequant/hooks/pre-tool.sh +36 -49
  10. package/dist/marketplace/external_plugins/sequant/skills/_shared/references/subagent-types.md +158 -48
  11. package/dist/marketplace/external_plugins/sequant/skills/assess/SKILL.md +354 -352
  12. package/dist/marketplace/external_plugins/sequant/skills/exec/SKILL.md +1155 -33
  13. package/dist/marketplace/external_plugins/sequant/skills/fullsolve/SKILL.md +35 -4
  14. package/dist/marketplace/external_plugins/sequant/skills/qa/SKILL.md +2157 -104
  15. package/dist/marketplace/external_plugins/sequant/skills/qa/scripts/quality-checks.sh +1 -1
  16. package/dist/marketplace/external_plugins/sequant/skills/setup/SKILL.md +386 -0
  17. package/dist/marketplace/external_plugins/sequant/skills/solve/SKILL.md +38 -664
  18. package/dist/marketplace/external_plugins/sequant/skills/spec/SKILL.md +505 -120
  19. package/dist/marketplace/external_plugins/sequant/skills/test/SKILL.md +246 -1
  20. package/dist/marketplace/external_plugins/sequant/skills/testgen/SKILL.md +138 -1
  21. package/dist/src/commands/dashboard.js +1 -1
  22. package/dist/src/commands/doctor.js +1 -1
  23. package/dist/src/commands/init.js +10 -10
  24. package/dist/src/commands/logs.js +1 -1
  25. package/dist/src/commands/run.js +49 -39
  26. package/dist/src/commands/state.js +3 -3
  27. package/dist/src/commands/status.js +5 -5
  28. package/dist/src/commands/sync.js +8 -8
  29. package/dist/src/commands/update.js +16 -16
  30. package/dist/src/lib/cli-ui.js +20 -19
  31. package/dist/src/lib/merge-check/index.js +2 -2
  32. package/dist/src/lib/settings.d.ts +8 -0
  33. package/dist/src/lib/settings.js +1 -0
  34. package/dist/src/lib/shutdown.js +1 -1
  35. package/dist/src/lib/templates.js +2 -0
  36. package/dist/src/lib/wizard.js +6 -4
  37. package/dist/src/lib/workflow/batch-executor.d.ts +9 -1
  38. package/dist/src/lib/workflow/batch-executor.js +39 -2
  39. package/dist/src/lib/workflow/log-writer.js +6 -6
  40. package/dist/src/lib/workflow/metrics-writer.js +5 -3
  41. package/dist/src/lib/workflow/phase-executor.d.ts +1 -1
  42. package/dist/src/lib/workflow/phase-executor.js +52 -22
  43. package/dist/src/lib/workflow/platforms/github.js +5 -1
  44. package/dist/src/lib/workflow/state-cleanup.js +1 -1
  45. package/dist/src/lib/workflow/state-manager.js +15 -13
  46. package/dist/src/lib/workflow/state-rebuild.js +2 -2
  47. package/dist/src/lib/workflow/types.d.ts +27 -0
  48. package/dist/src/lib/workflow/worktree-manager.js +40 -41
  49. package/dist/src/lib/worktree-isolation.d.ts +130 -0
  50. package/dist/src/lib/worktree-isolation.js +310 -0
  51. package/package.json +24 -14
  52. package/templates/agents/sequant-explorer.md +23 -0
  53. package/templates/agents/sequant-implementer.md +18 -0
  54. package/templates/agents/sequant-qa-checker.md +24 -0
  55. package/templates/agents/sequant-testgen.md +25 -0
  56. package/templates/scripts/cleanup-worktree.sh +18 -0
  57. package/templates/skills/_shared/references/subagent-types.md +158 -48
  58. package/templates/skills/exec/SKILL.md +72 -6
  59. package/templates/skills/qa/SKILL.md +8 -217
  60. package/templates/skills/spec/SKILL.md +446 -120
  61. package/templates/skills/testgen/SKILL.md +138 -1
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Worktree isolation for parallel /exec agent groups.
3
+ *
4
+ * Provides sub-worktree creation, merge-back, and cleanup for
5
+ * parallel agent execution, eliminating file conflicts structurally.
6
+ *
7
+ * @see https://github.com/sequant-io/sequant/issues/485
8
+ */
9
+ import { execSync } from "child_process";
10
+ import { existsSync, mkdirSync, symlinkSync, copyFileSync, readFileSync, readdirSync, rmdirSync, } from "fs";
11
+ import { join, basename, dirname } from "path";
12
+ /**
13
+ * Directory name for sub-worktrees inside the issue worktree.
14
+ * This directory is nested inside the issue worktree for locality.
15
+ */
16
+ export const SUB_WORKTREE_DIR = ".exec-agents";
17
+ /**
18
+ * Default files to copy into sub-worktrees when no .worktreeinclude exists.
19
+ * Matches the pattern in scripts/dev/new-feature.sh.
20
+ */
21
+ const DEFAULT_INCLUDE_FILES = [
22
+ ".env",
23
+ ".env.local",
24
+ ".env.development",
25
+ ".claude/settings.local.json",
26
+ ];
27
+ /** Name of the worktree include file */
28
+ export const WORKTREE_INCLUDE_FILE = ".worktreeinclude";
29
+ /**
30
+ * Read the list of files to copy into sub-worktrees.
31
+ *
32
+ * Reads from .worktreeinclude if it exists (one path per line, # comments),
33
+ * otherwise returns the hardcoded default list.
34
+ */
35
+ export function getIncludeFiles(worktreePath) {
36
+ const includeFile = join(worktreePath, WORKTREE_INCLUDE_FILE);
37
+ if (!existsSync(includeFile)) {
38
+ return DEFAULT_INCLUDE_FILES;
39
+ }
40
+ try {
41
+ return readFileSync(includeFile, "utf-8")
42
+ .split("\n")
43
+ .map((line) => line.trim())
44
+ .filter((line) => line.length > 0 && !line.startsWith("#"));
45
+ }
46
+ catch {
47
+ return DEFAULT_INCLUDE_FILES;
48
+ }
49
+ }
50
+ /**
51
+ * Run a git command and return stdout, trimmed.
52
+ * Throws on non-zero exit code.
53
+ */
54
+ function git(args, cwd) {
55
+ return execSync(`git ${args}`, {
56
+ cwd,
57
+ encoding: "utf-8",
58
+ stdio: ["pipe", "pipe", "pipe"],
59
+ }).trim();
60
+ }
61
+ /**
62
+ * Run a git command and return success/failure without throwing.
63
+ */
64
+ function gitSafe(args, cwd) {
65
+ try {
66
+ const stdout = execSync(`git ${args}`, {
67
+ cwd,
68
+ encoding: "utf-8",
69
+ stdio: ["pipe", "pipe", "pipe"],
70
+ }).trim();
71
+ return { success: true, stdout, stderr: "" };
72
+ }
73
+ catch (err) {
74
+ const error = err;
75
+ return {
76
+ success: false,
77
+ stdout: error.stdout ?? "",
78
+ stderr: error.stderr ?? "",
79
+ };
80
+ }
81
+ }
82
+ /**
83
+ * Generate a branch name for a sub-worktree agent.
84
+ *
85
+ * @param issueWorktreePath - Path to the issue worktree
86
+ * @param agentIndex - Zero-based agent index
87
+ * @returns Branch name like `exec-agent-485-0`
88
+ */
89
+ export function agentBranchName(issueWorktreePath, agentIndex) {
90
+ // Extract issue number from worktree path
91
+ const dirName = basename(issueWorktreePath);
92
+ const issueMatch = dirName.match(/^(\d+)-/);
93
+ const issueNum = issueMatch ? issueMatch[1] : dirName.slice(0, 10);
94
+ return `exec-agent-${issueNum}-${agentIndex}`;
95
+ }
96
+ /**
97
+ * Create a sub-worktree for a parallel agent.
98
+ *
99
+ * The sub-worktree is created inside the issue worktree at
100
+ * `.exec-agents/agent-<N>/` and branches from the issue branch HEAD.
101
+ *
102
+ * node_modules is symlinked from the issue worktree for speed.
103
+ * Environment files are copied per new-feature.sh convention.
104
+ *
105
+ * @param issueWorktreePath - Absolute path to the issue worktree
106
+ * @param agentIndex - Zero-based agent index
107
+ * @returns Sub-worktree info, or null if creation failed
108
+ */
109
+ export function createSubWorktree(issueWorktreePath, agentIndex) {
110
+ const branch = agentBranchName(issueWorktreePath, agentIndex);
111
+ const subDir = join(issueWorktreePath, SUB_WORKTREE_DIR);
112
+ const agentPath = join(subDir, `agent-${agentIndex}`);
113
+ try {
114
+ // Ensure .exec-agents directory exists
115
+ if (!existsSync(subDir)) {
116
+ mkdirSync(subDir, { recursive: true });
117
+ }
118
+ // Create worktree branching from current HEAD
119
+ git(`worktree add "${agentPath}" -b ${branch}`, issueWorktreePath);
120
+ // Symlink node_modules from issue worktree (fast: ~13ms)
121
+ const issueNodeModules = join(issueWorktreePath, "node_modules");
122
+ const agentNodeModules = join(agentPath, "node_modules");
123
+ if (existsSync(issueNodeModules) && !existsSync(agentNodeModules)) {
124
+ symlinkSync(issueNodeModules, agentNodeModules);
125
+ }
126
+ // Copy files listed in .worktreeinclude (AC-7)
127
+ const includeFiles = getIncludeFiles(issueWorktreePath);
128
+ for (const filePath of includeFiles) {
129
+ const src = join(issueWorktreePath, filePath);
130
+ if (existsSync(src)) {
131
+ const dest = join(agentPath, filePath);
132
+ const destDir = dirname(dest);
133
+ if (!existsSync(destDir)) {
134
+ mkdirSync(destDir, { recursive: true });
135
+ }
136
+ copyFileSync(src, dest);
137
+ }
138
+ }
139
+ return { path: agentPath, branch, agentIndex };
140
+ }
141
+ catch (err) {
142
+ const message = err instanceof Error ? err.message : String(err);
143
+ console.error(`Failed to create sub-worktree for agent ${agentIndex}: ${message}`);
144
+ return null;
145
+ }
146
+ }
147
+ /**
148
+ * Merge a single sub-worktree's changes back into the issue worktree.
149
+ *
150
+ * Uses `git merge --no-ff` for built-in conflict detection.
151
+ *
152
+ * @param issueWorktreePath - Absolute path to the issue worktree
153
+ * @param subWorktree - Sub-worktree info
154
+ * @returns Merge result with conflict details if any
155
+ */
156
+ export function mergeBackSubWorktree(issueWorktreePath, subWorktree) {
157
+ const { branch, agentIndex } = subWorktree;
158
+ // Check if the agent branch has any commits beyond the base
159
+ const hasChanges = gitSafe(`log ${branch} --not HEAD --oneline`, issueWorktreePath);
160
+ if (hasChanges.success && hasChanges.stdout.length === 0) {
161
+ return { success: true, branch, agentIndex, conflictFiles: [] };
162
+ }
163
+ // Attempt merge
164
+ const mergeResult = gitSafe(`merge --no-ff ${branch} -m "Merge exec-agent-${agentIndex}"`, issueWorktreePath);
165
+ if (mergeResult.success) {
166
+ return { success: true, branch, agentIndex, conflictFiles: [] };
167
+ }
168
+ // Merge failed โ€” detect conflict files
169
+ const conflictResult = gitSafe("diff --name-only --diff-filter=U", issueWorktreePath);
170
+ const conflictFiles = conflictResult.stdout
171
+ .split("\n")
172
+ .filter((f) => f.length > 0);
173
+ // Abort the failed merge to leave clean state
174
+ gitSafe("merge --abort", issueWorktreePath);
175
+ return {
176
+ success: false,
177
+ branch,
178
+ agentIndex,
179
+ conflictFiles,
180
+ error: `Merge conflict in ${conflictFiles.length} file(s): ${conflictFiles.join(", ")}`,
181
+ };
182
+ }
183
+ /**
184
+ * Merge all sub-worktrees back into the issue worktree.
185
+ *
186
+ * Merges are attempted sequentially. If one conflicts, the merge is
187
+ * aborted and subsequent agents are still attempted. Non-conflicting
188
+ * changes are preserved in the issue worktree.
189
+ *
190
+ * @param issueWorktreePath - Absolute path to the issue worktree
191
+ * @param subWorktrees - Array of sub-worktree info
192
+ * @returns Aggregate merge result
193
+ */
194
+ export function mergeAllSubWorktrees(issueWorktreePath, subWorktrees) {
195
+ const results = [];
196
+ let merged = 0;
197
+ let conflicts = 0;
198
+ for (const sub of subWorktrees) {
199
+ const result = mergeBackSubWorktree(issueWorktreePath, sub);
200
+ results.push(result);
201
+ if (result.success) {
202
+ merged++;
203
+ }
204
+ else {
205
+ conflicts++;
206
+ }
207
+ }
208
+ return { merged, conflicts, results };
209
+ }
210
+ /**
211
+ * Remove a single sub-worktree and its branch.
212
+ *
213
+ * @param issueWorktreePath - Absolute path to the issue worktree
214
+ * @param subWorktree - Sub-worktree info to clean up
215
+ */
216
+ export function cleanupSubWorktree(issueWorktreePath, subWorktree) {
217
+ const { path: subPath, branch } = subWorktree;
218
+ // Remove worktree
219
+ if (existsSync(subPath)) {
220
+ gitSafe(`worktree remove "${subPath}" --force`, issueWorktreePath);
221
+ }
222
+ // Delete branch
223
+ gitSafe(`branch -D ${branch}`, issueWorktreePath);
224
+ }
225
+ /**
226
+ * Clean up all sub-worktrees for an issue worktree.
227
+ *
228
+ * Handles both successful cleanup and orphaned worktrees from
229
+ * interrupted sessions.
230
+ *
231
+ * @param issueWorktreePath - Absolute path to the issue worktree
232
+ * @param subWorktrees - Known sub-worktrees to clean (if provided)
233
+ */
234
+ export function cleanupAllSubWorktrees(issueWorktreePath, subWorktrees) {
235
+ if (subWorktrees) {
236
+ for (const sub of subWorktrees) {
237
+ cleanupSubWorktree(issueWorktreePath, sub);
238
+ }
239
+ }
240
+ // Also clean any orphaned sub-worktrees from interrupted sessions
241
+ cleanupOrphanedSubWorktrees(issueWorktreePath);
242
+ }
243
+ /**
244
+ * Detect and clean up orphaned sub-worktrees from interrupted sessions.
245
+ *
246
+ * Scans the `.exec-agents/` directory for any remaining worktrees and
247
+ * removes them. Also prunes stale worktree entries from git.
248
+ *
249
+ * @param issueWorktreePath - Absolute path to the issue worktree
250
+ */
251
+ export function cleanupOrphanedSubWorktrees(issueWorktreePath) {
252
+ const subDir = join(issueWorktreePath, SUB_WORKTREE_DIR);
253
+ if (!existsSync(subDir)) {
254
+ return;
255
+ }
256
+ // Prune stale worktree entries
257
+ gitSafe("worktree prune", issueWorktreePath);
258
+ // List worktrees to find any still pointing to .exec-agents/
259
+ const listResult = gitSafe("worktree list --porcelain", issueWorktreePath);
260
+ if (!listResult.success)
261
+ return;
262
+ const lines = listResult.stdout.split("\n");
263
+ for (const line of lines) {
264
+ if (line.startsWith("worktree ") && line.includes(SUB_WORKTREE_DIR)) {
265
+ const worktreePath = line.replace("worktree ", "");
266
+ gitSafe(`worktree remove "${worktreePath}" --force`, issueWorktreePath);
267
+ }
268
+ }
269
+ // Clean up orphaned exec-agent branches
270
+ const branchResult = gitSafe("branch --list exec-agent-*", issueWorktreePath);
271
+ if (branchResult.success && branchResult.stdout.length > 0) {
272
+ const branches = branchResult.stdout
273
+ .split("\n")
274
+ .map((b) => b.trim())
275
+ .filter((b) => b.length > 0);
276
+ for (const branch of branches) {
277
+ gitSafe(`branch -D ${branch}`, issueWorktreePath);
278
+ }
279
+ }
280
+ // Remove the .exec-agents directory if empty
281
+ try {
282
+ const entries = readdirSync(subDir);
283
+ if (entries.length === 0) {
284
+ rmdirSync(subDir);
285
+ }
286
+ }
287
+ catch {
288
+ // Ignore errors during directory cleanup
289
+ }
290
+ }
291
+ /**
292
+ * Format merge-back results for logging.
293
+ *
294
+ * @param result - Aggregate merge result
295
+ * @returns Human-readable summary
296
+ */
297
+ export function formatMergeResult(result) {
298
+ const lines = [];
299
+ const total = result.merged + result.conflicts;
300
+ lines.push(`Merge-back: ${result.merged}/${total} agents merged successfully`);
301
+ if (result.conflicts > 0) {
302
+ lines.push(`Conflicts: ${result.conflicts} agent(s) had merge conflicts`);
303
+ for (const r of result.results) {
304
+ if (!r.success) {
305
+ lines.push(` Agent ${r.agentIndex}: ${r.error}`);
306
+ }
307
+ }
308
+ }
309
+ return lines.join("\n");
310
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sequant",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Quantize your development workflow - Sequential AI phases with quality gates",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,16 +32,26 @@
32
32
  "prepublishOnly": "npm run build"
33
33
  },
34
34
  "keywords": [
35
+ "ai",
35
36
  "claude",
36
37
  "claude-code",
38
+ "aider",
39
+ "mcp",
40
+ "cli",
37
41
  "workflow",
38
- "ai",
39
42
  "automation",
40
- "quality",
41
- "sequential",
42
- "agent-skills",
43
- "cursor",
44
- "vscode"
43
+ "coding-agent",
44
+ "agent",
45
+ "github",
46
+ "github-issues",
47
+ "quality-gates",
48
+ "code-quality",
49
+ "orchestrator",
50
+ "developer-tools",
51
+ "anthropic",
52
+ "llm",
53
+ "ai-coding",
54
+ "copilot"
45
55
  ],
46
56
  "author": "Sequant Contributors",
47
57
  "license": "MIT",
@@ -54,7 +64,7 @@
54
64
  },
55
65
  "homepage": "https://sequant.io",
56
66
  "engines": {
57
- "node": ">=20.0.0"
67
+ "node": ">=20.19.0"
58
68
  },
59
69
  "peerDependencies": {
60
70
  "@modelcontextprotocol/sdk": "^1.27.1"
@@ -83,17 +93,17 @@
83
93
  "zod": "^4.3.5"
84
94
  },
85
95
  "devDependencies": {
86
- "@eslint/js": "^9.39.2",
96
+ "@eslint/js": "^10.0.1",
87
97
  "@types/gradient-string": "^1.1.6",
88
98
  "@types/inquirer": "^9.0.7",
89
99
  "@types/node": "^25.4.0",
90
- "@typescript-eslint/eslint-plugin": "^8.52.0",
91
- "@typescript-eslint/parser": "^8.52.0",
92
- "eslint": "^9.39.2",
100
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
101
+ "@typescript-eslint/parser": "^8.58.0",
102
+ "eslint": "^10.1.0",
93
103
  "globals": "^17.0.0",
94
104
  "tsx": "^4.19.2",
95
- "typescript": "^5.7.2",
96
- "typescript-eslint": "^8.52.0",
105
+ "typescript": "^6.0.2",
106
+ "typescript-eslint": "^8.58.0",
97
107
  "vitest": "^4.1.0"
98
108
  }
99
109
  }
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: sequant-explorer
3
+ description: Codebase exploration agent for sequant /spec phase. Searches for existing patterns, components, database schemas, and file structures. Use when gathering context before planning a feature implementation.
4
+ model: haiku
5
+ maxTurns: 15
6
+ tools:
7
+ - Read
8
+ - Grep
9
+ - Glob
10
+ ---
11
+
12
+ You are an exploration agent for the sequant development workflow.
13
+
14
+ Your job is to search the codebase for existing patterns, components, and structures relevant to a planned feature.
15
+
16
+ Rules:
17
+ - Search thoroughly across relevant directories
18
+ - Report findings in structured format: file paths, patterns discovered, recommendations
19
+ - Do NOT modify any files
20
+ - Do NOT run shell commands
21
+ - Send results back via SendMessage when complete
22
+ - All grep commands must use `|| true` to prevent exit code 1 on zero matches
23
+ - Focus on actionable findings that inform implementation decisions
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: sequant-implementer
3
+ description: Implementation agent for sequant /exec parallel groups. Handles component creation, type definitions, CLI scripts, and refactoring tasks. Use when spawned by the /exec skill to implement a specific subtask in a feature worktree.
4
+ permissionMode: bypassPermissions
5
+ maxTurns: 25
6
+ ---
7
+
8
+ You are an implementation agent for the sequant development workflow.
9
+
10
+ Your job is to implement a specific subtask as described in your prompt, working within a feature worktree.
11
+
12
+ Rules:
13
+ - Work ONLY in the worktree path specified in your prompt
14
+ - Do NOT create test files unless explicitly asked
15
+ - Do NOT push to remote or create PRs
16
+ - Report what files were created/modified when complete via SendMessage
17
+ - Follow existing codebase patterns and conventions
18
+ - All grep commands must use `|| true` to prevent exit code 1 on zero matches
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: sequant-qa-checker
3
+ description: Quality check agent for sequant /qa phase. Runs type safety, scope/size, security, and documentation checks on diffs. Use when spawned by the /qa skill to perform parallel or sequential quality checks.
4
+ model: haiku
5
+ permissionMode: bypassPermissions
6
+ effort: low
7
+ maxTurns: 15
8
+ tools:
9
+ - Read
10
+ - Grep
11
+ - Glob
12
+ - Bash
13
+ ---
14
+
15
+ You are a quality check agent for the sequant development workflow.
16
+
17
+ Your job is to run a specific quality check on a code diff and report results concisely.
18
+
19
+ Rules:
20
+ - Run only the check described in your prompt
21
+ - Report results in structured format: check name, pass/fail, issue count, details
22
+ - Send results back via SendMessage when complete
23
+ - Do not modify any files
24
+ - All grep commands must use `|| true` to prevent exit code 1 on zero matches
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: sequant-testgen
3
+ description: Test stub generator for sequant /testgen phase. Parses verification criteria from /spec comments and generates Jest/Vitest test stubs with Given/When/Then structure. Use when spawned by the /testgen skill.
4
+ model: haiku
5
+ maxTurns: 25
6
+ tools:
7
+ - Read
8
+ - Grep
9
+ - Glob
10
+ - Write
11
+ ---
12
+
13
+ You are a test stub generation agent for the sequant development workflow.
14
+
15
+ Your job is to parse verification criteria and generate test stubs following project conventions.
16
+
17
+ Rules:
18
+ - Generate test stubs using the project's test framework (Jest or Vitest)
19
+ - Include Given/When/Then comments in each test
20
+ - Add TODO markers where implementation is needed
21
+ - Use `throw new Error('Test stub - implement this test')` for unimplemented tests
22
+ - Include failure path stubs based on the action verb
23
+ - Do NOT run shell commands
24
+ - Send results back via SendMessage when complete
25
+ - Return ONLY the test code, no explanation
@@ -53,6 +53,24 @@ if [ "$PR_STATUS" != "MERGED" ]; then
53
53
  fi
54
54
  fi
55
55
 
56
+ # Clean up any exec-agent sub-worktrees first (from parallel isolation)
57
+ EXEC_AGENTS_DIR="$WORKTREE_PATH/.exec-agents"
58
+ if [ -d "$EXEC_AGENTS_DIR" ]; then
59
+ echo -e "${BLUE}๐Ÿงน Cleaning up exec-agent sub-worktrees...${NC}"
60
+ for agent_dir in "$EXEC_AGENTS_DIR"/agent-*; do
61
+ if [ -d "$agent_dir" ]; then
62
+ echo -e "${BLUE} Removing: $(basename "$agent_dir")${NC}"
63
+ git worktree remove "$agent_dir" --force 2>/dev/null || true
64
+ fi
65
+ done
66
+ # Clean up orphaned exec-agent branches
67
+ git branch --list 'exec-agent-*' 2>/dev/null | while read -r branch; do
68
+ branch=$(echo "$branch" | tr -d ' *')
69
+ git branch -D "$branch" 2>/dev/null || true
70
+ done
71
+ rmdir "$EXEC_AGENTS_DIR" 2>/dev/null || true
72
+ fi
73
+
56
74
  # Remove worktree
57
75
  echo -e "${BLUE}๐Ÿ“‚ Removing worktree...${NC}"
58
76
  git worktree remove "$WORKTREE_PATH" --force