@iloom/cli 0.12.1 → 0.12.2

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 (59) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -1
  3. package/dist/README.md +1 -1
  4. package/dist/agents/iloom-wave-verifier.md +54 -2
  5. package/dist/{build-DMWSIME6.js → build-PKHPE34Y.js} +3 -3
  6. package/dist/{chunk-FV4KXBGO.js → chunk-6RINI7OL.js} +2 -2
  7. package/dist/{chunk-FV4KXBGO.js.map → chunk-6RINI7OL.js.map} +1 -1
  8. package/dist/{chunk-IHSA7VGI.js → chunk-CTHB7345.js} +2 -2
  9. package/dist/{chunk-XVCGPTEQ.js → chunk-GDDRANOZ.js} +1 -1
  10. package/dist/chunk-GDDRANOZ.js.map +1 -0
  11. package/dist/{chunk-UVXB6O24.js → chunk-H2M62IKR.js} +2 -2
  12. package/dist/{chunk-DY6MUWQW.js → chunk-UMZ2CIDW.js} +3 -3
  13. package/dist/{chunk-HIGWKLQR.js → chunk-VZ55H5X6.js} +2 -2
  14. package/dist/{cleanup-RLBLNQZN.js → cleanup-QTZU46OP.js} +2 -2
  15. package/dist/cli.js +24 -24
  16. package/dist/cli.js.map +1 -1
  17. package/dist/{commit-RILBXFWO.js → commit-P3OOQ3JN.js} +3 -3
  18. package/dist/{compile-QEL5724K.js → compile-IOXQTCP3.js} +3 -3
  19. package/dist/{dev-server-2WSWZXJG.js → dev-server-BLJ7NPKG.js} +2 -2
  20. package/dist/{ignite-X2NNTNUN.js → ignite-6XT5BKSF.js} +3 -3
  21. package/dist/index.d.ts +2 -2
  22. package/dist/index.js +1 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/{init-LWU2M53W.js → init-6FUPISD7.js} +3 -3
  25. package/dist/{install-deps-HXP2TM7G.js → install-deps-BMRONT2L.js} +3 -3
  26. package/dist/{lint-FDZC77GL.js → lint-PRD2DO5K.js} +3 -3
  27. package/dist/{open-US4XACLW.js → open-NVFYA5IM.js} +2 -2
  28. package/dist/{plan-5S6355GF.js → plan-7M5WB7VT.js} +5 -5
  29. package/dist/{rebase-JA3RW2XO.js → rebase-5B7WQQAY.js} +2 -2
  30. package/dist/{recap-5TO42HN2.js → recap-7PSTJ3MF.js} +2 -2
  31. package/dist/{run-KKCRBRLW.js → run-6ZCDG7MX.js} +2 -2
  32. package/dist/{shell-GAB2FCXH.js → shell-MX3WRDQN.js} +2 -2
  33. package/dist/{summary-P7QE3TNW.js → summary-WQ7QOAIQ.js} +2 -2
  34. package/dist/{test-6LFB5WOO.js → test-LAIG62XM.js} +3 -3
  35. package/dist/{vscode-HXIXRZ3A.js → vscode-VZCCFQRY.js} +2 -2
  36. package/package.json +1 -1
  37. package/dist/chunk-XVCGPTEQ.js.map +0 -1
  38. /package/dist/{build-DMWSIME6.js.map → build-PKHPE34Y.js.map} +0 -0
  39. /package/dist/{chunk-IHSA7VGI.js.map → chunk-CTHB7345.js.map} +0 -0
  40. /package/dist/{chunk-UVXB6O24.js.map → chunk-H2M62IKR.js.map} +0 -0
  41. /package/dist/{chunk-DY6MUWQW.js.map → chunk-UMZ2CIDW.js.map} +0 -0
  42. /package/dist/{chunk-HIGWKLQR.js.map → chunk-VZ55H5X6.js.map} +0 -0
  43. /package/dist/{cleanup-RLBLNQZN.js.map → cleanup-QTZU46OP.js.map} +0 -0
  44. /package/dist/{commit-RILBXFWO.js.map → commit-P3OOQ3JN.js.map} +0 -0
  45. /package/dist/{compile-QEL5724K.js.map → compile-IOXQTCP3.js.map} +0 -0
  46. /package/dist/{dev-server-2WSWZXJG.js.map → dev-server-BLJ7NPKG.js.map} +0 -0
  47. /package/dist/{ignite-X2NNTNUN.js.map → ignite-6XT5BKSF.js.map} +0 -0
  48. /package/dist/{init-LWU2M53W.js.map → init-6FUPISD7.js.map} +0 -0
  49. /package/dist/{install-deps-HXP2TM7G.js.map → install-deps-BMRONT2L.js.map} +0 -0
  50. /package/dist/{lint-FDZC77GL.js.map → lint-PRD2DO5K.js.map} +0 -0
  51. /package/dist/{open-US4XACLW.js.map → open-NVFYA5IM.js.map} +0 -0
  52. /package/dist/{plan-5S6355GF.js.map → plan-7M5WB7VT.js.map} +0 -0
  53. /package/dist/{rebase-JA3RW2XO.js.map → rebase-5B7WQQAY.js.map} +0 -0
  54. /package/dist/{recap-5TO42HN2.js.map → recap-7PSTJ3MF.js.map} +0 -0
  55. /package/dist/{run-KKCRBRLW.js.map → run-6ZCDG7MX.js.map} +0 -0
  56. /package/dist/{shell-GAB2FCXH.js.map → shell-MX3WRDQN.js.map} +0 -0
  57. /package/dist/{summary-P7QE3TNW.js.map → summary-WQ7QOAIQ.js.map} +0 -0
  58. /package/dist/{test-6LFB5WOO.js.map → test-LAIG62XM.js.map} +0 -0
  59. /package/dist/{vscode-HXIXRZ3A.js.map → vscode-VZCCFQRY.js.map} +0 -0
package/LICENSE CHANGED
@@ -20,7 +20,7 @@ it within your organization. What is prohibited is redistributing or offering
20
20
  access to this software (in original or modified form) as part of something
21
21
  you sell or provide to others.
22
22
 
23
- Change Date: 2030-03-11
23
+ Change Date: 2030-03-12
24
24
  Change License: Apache License 2.0
25
25
 
26
26
  For clarity, on or after the Change Date, the Licensed Work will
package/README.md CHANGED
@@ -880,7 +880,7 @@ License & Name
880
880
 
881
881
  * ❌ You cannot resell iloom itself as a product or SaaS.
882
882
 
883
- * Converts to Apache 2.0 on 2030-03-11.
883
+ * Converts to Apache 2.0 on 2030-03-12.
884
884
 
885
885
 
886
886
  See [LICENSE](https://raw.githubusercontent.com/iloom-ai/iloom-cli/main/LICENSE) for complete terms.
package/dist/README.md CHANGED
@@ -880,7 +880,7 @@ License & Name
880
880
 
881
881
  * ❌ You cannot resell iloom itself as a product or SaaS.
882
882
 
883
- * Converts to Apache 2.0 on 2030-03-11.
883
+ * Converts to Apache 2.0 on 2030-03-12.
884
884
 
885
885
 
886
886
  See [LICENSE](https://raw.githubusercontent.com/iloom-ai/iloom-cli/main/LICENSE) for complete terms.
@@ -83,6 +83,48 @@ Record each result as:
83
83
  }
84
84
  ```
85
85
 
86
+ ### Step 2.5: Post Initial Verification Report Comment
87
+
88
+ After verifying all must-haves, post the initial results as a comment on the verifier's own issue:
89
+
90
+ 1. Construct a markdown report using the same format as Step 5, but with only the "Initial" column populated (no "After Fix" column yet since fixes haven't been attempted):
91
+
92
+ ```markdown
93
+ ## Wave Verification Report
94
+
95
+ ### Summary
96
+ - **Total must-haves checked:** N
97
+ - **Passed (initial):** N
98
+ - **Failed (initial):** N
99
+
100
+ ### Results by Issue
101
+
102
+ #### Issue #NNN: [issue title]
103
+
104
+ | Must-Have | Type | Initial |
105
+ |-----------|------|---------|
106
+ | `src/Foo.tsx` | exists | ✅ PASS |
107
+ | `src/Foo.tsx` — exports default component | substantive | ❌ FAIL |
108
+
109
+ ### Overall Status: [ALL_PASSED | FAILURES_FOUND]
110
+
111
+ *Fix attempts will follow. This comment will be updated with final results.*
112
+ ```
113
+
114
+ 2. Call `mcp__issue_management__create_comment` with:
115
+ - `number`: your own issue number (from invocation prompt)
116
+ - `type`: `"issue"`
117
+ - `body`: the initial verification report markdown above
118
+ - `markupLanguage`: `"GFM"`
119
+
120
+ 3. Save the returned `commentId` — you will need it in Step 4 to update the comment with fix results
121
+
122
+ 4. Log the comment as a recap artifact:
123
+ - Call `recap.add_artifact` with `type: 'comment'`, `primaryUrl`: the returned comment URL, and `description`: `"Wave verification report"`
124
+ - If in swarm mode, include `worktreePath` in the recap call
125
+
126
+ **If all must-haves passed** (no failures), the initial report is already the final report. Skip Steps 3 and 4 entirely and proceed to Step 5. The comment does not need updating.
127
+
86
128
  ### Step 3: Fix Failures (if any)
87
129
 
88
130
  If any must-haves FAILED, invoke the fix skill to address them:
@@ -118,7 +160,7 @@ The skill runs inline and returns its result directly. Check the skill's output
118
160
  3. Run fix skill invocations sequentially (one per issue group), waiting for each to complete before starting the next
119
161
  4. Record fix action results: which issue, which failures were targeted, and whether the skill reported success
120
162
 
121
- ### Step 4: Re-Verify (Single Pass Only)
163
+ ### Step 4: Re-Verify and Update Report Comment (Single Pass Only)
122
164
 
123
165
  After ALL fix skill invocations have completed:
124
166
 
@@ -127,6 +169,16 @@ After ALL fix skill invocations have completed:
127
169
  3. **Do NOT invoke additional fix skills** — this is a single re-verification pass
128
170
  4. If a criterion still fails after the fix attempt, record `status: 'fail'` and note "Still failing after fix attempt"
129
171
 
172
+ **Update the verification report comment:**
173
+
174
+ 5. Construct the full report in the Step 5 format (with "After Fix" column populated for previously-failed criteria)
175
+ 6. Call `mcp__issue_management__update_comment` with:
176
+ - `commentId`: the ID saved from Step 2.5
177
+ - `number`: your own issue number
178
+ - `body`: the updated full report
179
+ - `markupLanguage`: `"GFM"`
180
+ 7. Update the recap artifact by calling `recap.add_artifact` again with the same `primaryUrl` (this replaces the existing entry)
181
+
130
182
  ### Step 5: Return Structured Report
131
183
 
132
184
  Return the verification report in this exact format:
@@ -183,4 +235,4 @@ Call `recap.set_loom_state` at these workflow boundaries, **always passing your
183
235
  - `done` — After returning the verification report (regardless of whether must-haves passed or failed — the verifier's job is complete)
184
236
  - `failed` — On any unrecoverable error
185
237
 
186
- **IMPORTANT:** Return the full report text as your output so the orchestrator can log it and determine whether to proceed to the next wave.
238
+ **IMPORTANT:** Return the full report text as your output so the orchestrator can log it and determine whether to proceed to the next wave. The report has already been posted (or posted and updated) as a comment on the verification issue — the orchestrator does not need to post it separately.
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ScriptCommandBase
4
- } from "./chunk-IHSA7VGI.js";
4
+ } from "./chunk-CTHB7345.js";
5
5
  import "./chunk-ZM2AYHMO.js";
6
6
  import "./chunk-VIQOQ463.js";
7
- import "./chunk-FV4KXBGO.js";
7
+ import "./chunk-6RINI7OL.js";
8
8
  import "./chunk-K3QGG4O2.js";
9
9
  import "./chunk-OPQC4OWM.js";
10
10
  import "./chunk-653XBU3L.js";
@@ -24,4 +24,4 @@ var BuildCommand = class extends ScriptCommandBase {
24
24
  export {
25
25
  BuildCommand
26
26
  };
27
- //# sourceMappingURL=build-DMWSIME6.js.map
27
+ //# sourceMappingURL=build-PKHPE34Y.js.map
@@ -323,7 +323,7 @@ var GitWorktreeManager = class {
323
323
  */
324
324
  async findWorktreeForIssue(issueNumber) {
325
325
  const worktrees = await this.listWorktrees({ porcelain: true });
326
- const pattern = new RegExp(`(?:^|[/_-])issue-${issueNumber}(?:-|__|$)`, "i");
326
+ const pattern = new RegExp(`(?:^|[/_-])issue[-/]${issueNumber}(?:-|__|$)`, "i");
327
327
  return worktrees.find((wt) => pattern.test(wt.branch)) ?? null;
328
328
  }
329
329
  /**
@@ -388,4 +388,4 @@ var GitWorktreeManager = class {
388
388
  export {
389
389
  GitWorktreeManager
390
390
  };
391
- //# sourceMappingURL=chunk-FV4KXBGO.js.map
391
+ //# sourceMappingURL=chunk-6RINI7OL.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/GitWorktreeManager.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport {\n type GitWorktree,\n type WorktreeCreateOptions,\n type WorktreeListOptions,\n type WorktreeValidation,\n type WorktreeStatus,\n type WorktreeCleanupOptions,\n} from '../types/worktree.js'\nimport {\n executeGitCommand,\n parseWorktreeList,\n isPRBranch,\n extractPRNumber,\n generateWorktreePath,\n isValidGitRepo,\n getCurrentBranch,\n getRepoRoot,\n hasUncommittedChanges,\n getDefaultBranch,\n findMainWorktreePathWithSettings,\n} from '../utils/git.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport type { SettingsManager } from './SettingsManager.js'\n\n/**\n * Manages Git worktrees for the iloom CLI\n * Ports functionality from bash scripts into TypeScript\n */\nexport class GitWorktreeManager {\n private readonly _workingDirectory: string\n\n constructor(workingDirectory: string = process.cwd()) {\n this._workingDirectory = workingDirectory\n }\n\n /**\n * Get the working directory for git operations (main worktree path)\n */\n get workingDirectory(): string {\n return this._workingDirectory\n }\n\n /**\n * List all worktrees in the repository\n * Defaults to porcelain format for reliable machine parsing\n * Equivalent to: git worktree list --porcelain\n */\n async listWorktrees(options: WorktreeListOptions = {}): Promise<GitWorktree[]> {\n const args = ['worktree', 'list']\n // Default to porcelain format for consistent parsing (can be disabled with porcelain: false)\n if (options.porcelain !== false) args.push('--porcelain')\n if (options.verbose) args.push('-v')\n\n const output = await executeGitCommand(args, { cwd: this._workingDirectory })\n return parseWorktreeList(output)\n }\n\n /**\n * Find worktree for a specific branch\n * Ports: find_worktree_for_branch() from find-worktree-for-branch.sh\n */\n async findWorktreeForBranch(branchName: string): Promise<GitWorktree | null> {\n const worktrees = await this.listWorktrees()\n return worktrees.find(wt => wt.branch === branchName) ?? null\n }\n\n /**\n * Check if a worktree is the main repository worktree\n * Uses findMainWorktreePathWithSettings to determine the main worktree based on settings.\n *\n * @param worktree - The worktree to check\n * @param settingsManager - SettingsManager instance for loading settings\n * @returns true if the worktree is the main worktree\n */\n async isMainWorktree(worktree: GitWorktree, settingsManager: SettingsManager): Promise<boolean> {\n const mainWorktreePath = await findMainWorktreePathWithSettings(worktree.path, settingsManager)\n return worktree.path === mainWorktreePath\n }\n\n /**\n * Check if a worktree is a PR worktree based on naming patterns\n * Ports: is_pr_worktree() from worktree-utils.sh\n */\n isPRWorktree(worktree: GitWorktree): boolean {\n return isPRBranch(worktree.branch)\n }\n\n /**\n * Get PR number from worktree branch name\n * Ports: get_pr_number_from_worktree() from worktree-utils.sh\n */\n getPRNumberFromWorktree(worktree: GitWorktree): number | null {\n return extractPRNumber(worktree.branch)\n }\n\n /**\n * Create a new worktree\n * Ports worktree creation logic from new-branch-workflow.sh\n * @returns The absolute path to the created worktree\n */\n async createWorktree(options: WorktreeCreateOptions): Promise<string> {\n // Validate inputs\n if (!options.branch) {\n throw new Error('Branch name is required')\n }\n\n // Ensure path is absolute\n const absolutePath = path.resolve(options.path)\n\n // Check if path already exists and handle force flag\n if (await fs.pathExists(absolutePath)) {\n if (!options.force) {\n throw new Error(`Path already exists: ${absolutePath}`)\n }\n // Remove existing directory if force is true\n await fs.remove(absolutePath)\n }\n\n // Build git worktree add command\n const args = ['worktree', 'add']\n\n if (options.createBranch) {\n args.push('-b', options.branch)\n }\n\n if (options.force) {\n args.push('--force')\n }\n\n args.push(absolutePath)\n\n // Add branch name if not creating new branch\n if (!options.createBranch) {\n args.push(options.branch)\n } else if (options.baseBranch) {\n args.push(options.baseBranch)\n }\n\n // 5 minute timeout for repos with LFS that need to download large files\n await executeGitCommand(args, { cwd: this._workingDirectory, timeout: 300000 })\n return absolutePath\n }\n\n /**\n * Remove a worktree and optionally clean up associated files\n * Ports worktree removal logic from cleanup-worktree.sh\n * @returns A message describing what was done (for dry-run mode)\n */\n async removeWorktree(\n worktreePath: string,\n options: WorktreeCleanupOptions = {}\n ): Promise<string | void> {\n // Validate worktree exists - use porcelain format for consistent parsing\n const worktrees = await this.listWorktrees({ porcelain: true })\n const worktree = worktrees.find(wt => wt.path === worktreePath)\n\n if (!worktree) {\n // Add debug logging to help diagnose the issue\n getLogger().debug(`Looking for worktree path: ${worktreePath}`)\n getLogger().debug(`Found ${worktrees.length} worktrees:`)\n worktrees.forEach((wt, i) => {\n getLogger().debug(` ${i}: path=\"${wt.path}\", branch=\"${wt.branch}\"`)\n })\n throw new Error(`Worktree not found: ${worktreePath}`)\n }\n\n // Check for uncommitted changes unless force is specified\n if (!options.force && !options.dryRun) {\n const hasChanges = await hasUncommittedChanges(worktreePath)\n if (hasChanges) {\n throw new Error(`Worktree has uncommitted changes: ${worktreePath}. Use --force to override.`)\n }\n }\n\n if (options.dryRun) {\n const actions = ['Remove worktree registration']\n if (options.removeDirectory) actions.push('Remove directory from disk')\n if (options.removeBranch) actions.push(`Remove branch: ${worktree.branch}`)\n\n return `Would perform: ${actions.join(', ')}`\n }\n\n // Remove worktree registration\n const args = ['worktree', 'remove']\n if (options.force) args.push('--force')\n args.push(worktreePath)\n\n await executeGitCommand(args, { cwd: this._workingDirectory })\n\n // Remove directory if requested\n if (options.removeDirectory && (await fs.pathExists(worktreePath))) {\n await fs.remove(worktreePath)\n }\n\n // Remove branch if requested and safe to do so\n if (options.removeBranch && !worktree.bare) {\n try {\n await executeGitCommand(['branch', '-D', worktree.branch], {\n cwd: this._workingDirectory,\n })\n } catch (error) {\n // Don't fail the whole operation if branch deletion fails\n // Just log a warning (caller can handle this)\n throw new Error(\n `Worktree removed but failed to delete branch ${worktree.branch}: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n }\n }\n\n /**\n * Validate worktree state and integrity\n */\n async validateWorktree(worktreePath: string): Promise<WorktreeValidation> {\n const issues: string[] = []\n let existsOnDisk = false\n let isValidRepo = false\n let hasValidBranch = false\n\n try {\n // Check if path exists on disk\n existsOnDisk = await fs.pathExists(worktreePath)\n if (!existsOnDisk) {\n issues.push('Worktree directory does not exist on disk')\n }\n\n // Check if it's a valid Git repository\n if (existsOnDisk) {\n isValidRepo = await isValidGitRepo(worktreePath)\n if (!isValidRepo) {\n issues.push('Directory is not a valid Git repository')\n }\n }\n\n // Check if branch reference is valid\n if (isValidRepo) {\n const currentBranch = await getCurrentBranch(worktreePath)\n hasValidBranch = currentBranch !== null\n if (!hasValidBranch) {\n issues.push('Could not determine current branch')\n }\n }\n\n // Check if worktree is registered with Git\n const worktrees = await this.listWorktrees()\n const isRegistered = worktrees.some(wt => wt.path === worktreePath)\n if (!isRegistered) {\n issues.push('Worktree is not registered with Git')\n }\n } catch (error) {\n issues.push(`Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n\n return {\n isValid: issues.length === 0,\n issues,\n existsOnDisk,\n isValidRepo,\n hasValidBranch,\n }\n }\n\n /**\n * Get detailed status information for a worktree\n */\n async getWorktreeStatus(worktreePath: string): Promise<WorktreeStatus> {\n const statusOutput = await executeGitCommand(['status', '--porcelain=v1'], {\n cwd: worktreePath,\n })\n\n let modified = 0\n let staged = 0\n let deleted = 0\n let untracked = 0\n\n const lines = statusOutput.trim().split('\\n').filter(Boolean)\n for (const line of lines) {\n const status = line.substring(0, 2)\n if (status[0] === 'M' || status[1] === 'M') modified++\n if (status[0] === 'A' || status[0] === 'D' || status[0] === 'R') staged++\n if (status[0] === 'D' || status[1] === 'D') deleted++\n if (status === '??') untracked++\n }\n\n const currentBranch = (await getCurrentBranch(worktreePath)) ?? 'unknown'\n const detached = currentBranch === 'unknown'\n\n // Get ahead/behind information\n let ahead = 0\n let behind = 0\n try {\n const aheadBehindOutput = await executeGitCommand(\n ['rev-list', '--left-right', '--count', `origin/${currentBranch}...HEAD`],\n { cwd: worktreePath }\n )\n const parts = aheadBehindOutput.trim().split('\\t')\n const behindStr = parts[0]\n const aheadStr = parts[1]\n behind = behindStr ? parseInt(behindStr, 10) || 0 : 0\n ahead = aheadStr ? parseInt(aheadStr, 10) || 0 : 0\n } catch {\n // Ignore errors for ahead/behind calculation\n }\n\n return {\n modified,\n staged,\n deleted,\n untracked,\n hasChanges: modified + staged + deleted + untracked > 0,\n branch: currentBranch,\n detached,\n ahead,\n behind,\n }\n }\n\n /**\n * Generate a suggested worktree path for a branch\n */\n generateWorktreePath(\n branchName: string,\n customRoot?: string,\n options?: { isPR?: boolean; prNumber?: number; prefix?: string }\n ): string {\n const root = customRoot ?? this._workingDirectory\n return generateWorktreePath(branchName, root, options)\n }\n\n /**\n * Sanitize a branch name for use as a directory name\n * Replaces slashes with dashes and removes invalid filesystem characters\n * Ports logic from bash script line 593: ${BRANCH_NAME//\\\\//-}\n */\n sanitizeBranchName(branchName: string): string {\n return branchName\n .replace(/\\//g, '-') // Replace slashes with dashes\n .replace(/[^a-zA-Z0-9-]/g, '-') // Replace invalid chars (including underscores) with dashes\n .replace(/-+/g, '-') // Collapse multiple dashes\n .replace(/^-|-$/g, '') // Remove leading/trailing dashes\n .toLowerCase()\n }\n\n /**\n * Check if repository is in a valid state for worktree operations\n */\n async isRepoReady(): Promise<boolean> {\n try {\n const repoRoot = await getRepoRoot(this._workingDirectory)\n return repoRoot !== null\n } catch {\n return false\n }\n }\n\n /**\n * Get repository information\n */\n async getRepoInfo(): Promise<{\n root: string | null\n defaultBranch: string\n currentBranch: string | null\n }> {\n const root = await getRepoRoot(this._workingDirectory)\n const defaultBranch = await getDefaultBranch(this._workingDirectory)\n const currentBranch = await getCurrentBranch(this._workingDirectory)\n\n return {\n root,\n defaultBranch,\n currentBranch,\n }\n }\n\n /**\n * Prune stale worktree entries (worktrees that no longer exist on disk)\n */\n async pruneWorktrees(): Promise<void> {\n await executeGitCommand(['worktree', 'prune', '-v'], { cwd: this._workingDirectory })\n }\n\n /**\n * Lock a worktree to prevent it from being pruned or moved\n */\n async lockWorktree(worktreePath: string, reason?: string): Promise<void> {\n const args = ['worktree', 'lock', worktreePath]\n if (reason) args.push('--reason', reason)\n\n await executeGitCommand(args, { cwd: this._workingDirectory })\n }\n\n /**\n * Unlock a previously locked worktree\n */\n async unlockWorktree(worktreePath: string): Promise<void> {\n await executeGitCommand(['worktree', 'unlock', worktreePath], { cwd: this._workingDirectory })\n }\n\n /**\n * Find worktrees matching an identifier (branch name, path, or PR number)\n */\n async findWorktreesByIdentifier(identifier: string): Promise<GitWorktree[]> {\n const worktrees = await this.listWorktrees({ porcelain: true })\n return worktrees.filter(\n wt =>\n wt.branch.includes(identifier) ||\n wt.path.includes(identifier) ||\n this.getPRNumberFromWorktree(wt)?.toString() === identifier\n )\n }\n\n /**\n * Find worktree for a specific issue number using exact pattern matching\n * Matches: issue-{N} at start OR after /, -, _ (but NOT issue-{N}X where X is a digit)\n * Supports patterns like: issue-44, feat/issue-44-feature, feat-issue-44, bugfix_issue-44, etc.\n * Avoids false matches like: tissue-44, myissue-44\n * Ports: find_existing_worktree() from bash script lines 131-165\n */\n async findWorktreeForIssue(issueNumber: string | number): Promise<GitWorktree | null> {\n const worktrees = await this.listWorktrees({ porcelain: true })\n\n // Pattern: starts with 'issue-{N}' OR has '/issue-{N}', '-issue-{N}', '_issue-{N}' but not 'issue-{N}{digit}'\n // Case-insensitive to handle Linear IDs (MARK-1 vs mark-1)\n const pattern = new RegExp(`(?:^|[/_-])issue-${issueNumber}(?:-|__|$)`, 'i')\n\n return worktrees.find(wt => pattern.test(wt.branch)) ?? null\n }\n\n /**\n * Find worktree for a specific PR by branch name\n * Ports: find_existing_worktree() for PR type from bash script lines 149-160\n */\n async findWorktreeForPR(prNumber: number, branchName: string): Promise<GitWorktree | null> {\n const worktrees = await this.listWorktrees({ porcelain: true })\n\n // Find by exact branch name match (prioritized)\n const byBranch = worktrees.find(wt => wt.branch === branchName)\n if (byBranch) return byBranch\n\n // Also check directory name pattern: *_pr_{N}\n const pathPattern = new RegExp(`_pr_${prNumber}$`)\n return worktrees.find(wt => pathPattern.test(wt.path)) ?? null\n }\n\n /**\n * Remove multiple worktrees\n * Returns a summary of successes and failures\n * Automatically filters out the main worktree\n *\n * @param worktrees - Array of worktrees to remove\n * @param settingsManager - SettingsManager instance for determining main worktree\n * @param options - Cleanup options\n */\n async removeWorktrees(\n worktrees: GitWorktree[],\n settingsManager: SettingsManager,\n options: WorktreeCleanupOptions = {}\n ): Promise<{\n successes: Array<{ worktree: GitWorktree }>\n failures: Array<{ worktree: GitWorktree; error: string }>\n skipped: Array<{ worktree: GitWorktree; reason: string }>\n }> {\n const successes: Array<{ worktree: GitWorktree }> = []\n const failures: Array<{ worktree: GitWorktree; error: string }> = []\n const skipped: Array<{ worktree: GitWorktree; reason: string }> = []\n\n for (const worktree of worktrees) {\n // Skip main worktree\n if (await this.isMainWorktree(worktree, settingsManager)) {\n skipped.push({ worktree, reason: 'Cannot remove main worktree' })\n continue\n }\n\n try {\n await this.removeWorktree(worktree.path, {\n ...options,\n removeDirectory: true,\n })\n successes.push({ worktree })\n } catch (error) {\n failures.push({\n worktree,\n error: error instanceof Error ? error.message : 'Unknown error',\n })\n }\n }\n\n return { successes, failures, skipped }\n }\n\n /**\n * Format worktree information for display\n */\n formatWorktree(worktree: GitWorktree): {\n title: string\n path: string\n commit: string\n } {\n const prNumber = this.getPRNumberFromWorktree(worktree)\n const prLabel = prNumber ? ` (PR #${prNumber})` : ''\n const bareLabel = worktree.bare ? ' [main]' : ''\n\n return {\n title: `${worktree.branch}${prLabel}${bareLabel}`,\n path: worktree.path,\n commit: worktree.commit.substring(0, 7),\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AA6BR,IAAM,qBAAN,MAAyB;AAAA,EAG9B,YAAY,mBAA2B,QAAQ,IAAI,GAAG;AACpD,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,mBAA2B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,UAA+B,CAAC,GAA2B;AAC7E,UAAM,OAAO,CAAC,YAAY,MAAM;AAEhC,QAAI,QAAQ,cAAc,MAAO,MAAK,KAAK,aAAa;AACxD,QAAI,QAAQ,QAAS,MAAK,KAAK,IAAI;AAEnC,UAAM,SAAS,MAAM,kBAAkB,MAAM,EAAE,KAAK,KAAK,kBAAkB,CAAC;AAC5E,WAAO,kBAAkB,MAAM;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,sBAAsB,YAAiD;AAC3E,UAAM,YAAY,MAAM,KAAK,cAAc;AAC3C,WAAO,UAAU,KAAK,QAAM,GAAG,WAAW,UAAU,KAAK;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,eAAe,UAAuB,iBAAoD;AAC9F,UAAM,mBAAmB,MAAM,iCAAiC,SAAS,MAAM,eAAe;AAC9F,WAAO,SAAS,SAAS;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,UAAgC;AAC3C,WAAO,WAAW,SAAS,MAAM;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,wBAAwB,UAAsC;AAC5D,WAAO,gBAAgB,SAAS,MAAM;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eAAe,SAAiD;AAEpE,QAAI,CAAC,QAAQ,QAAQ;AACnB,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAGA,UAAM,eAAe,KAAK,QAAQ,QAAQ,IAAI;AAG9C,QAAI,MAAM,GAAG,WAAW,YAAY,GAAG;AACrC,UAAI,CAAC,QAAQ,OAAO;AAClB,cAAM,IAAI,MAAM,wBAAwB,YAAY,EAAE;AAAA,MACxD;AAEA,YAAM,GAAG,OAAO,YAAY;AAAA,IAC9B;AAGA,UAAM,OAAO,CAAC,YAAY,KAAK;AAE/B,QAAI,QAAQ,cAAc;AACxB,WAAK,KAAK,MAAM,QAAQ,MAAM;AAAA,IAChC;AAEA,QAAI,QAAQ,OAAO;AACjB,WAAK,KAAK,SAAS;AAAA,IACrB;AAEA,SAAK,KAAK,YAAY;AAGtB,QAAI,CAAC,QAAQ,cAAc;AACzB,WAAK,KAAK,QAAQ,MAAM;AAAA,IAC1B,WAAW,QAAQ,YAAY;AAC7B,WAAK,KAAK,QAAQ,UAAU;AAAA,IAC9B;AAGA,UAAM,kBAAkB,MAAM,EAAE,KAAK,KAAK,mBAAmB,SAAS,IAAO,CAAC;AAC9E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,cACA,UAAkC,CAAC,GACX;AAExB,UAAM,YAAY,MAAM,KAAK,cAAc,EAAE,WAAW,KAAK,CAAC;AAC9D,UAAM,WAAW,UAAU,KAAK,QAAM,GAAG,SAAS,YAAY;AAE9D,QAAI,CAAC,UAAU;AAEb,gBAAU,EAAE,MAAM,8BAA8B,YAAY,EAAE;AAC9D,gBAAU,EAAE,MAAM,SAAS,UAAU,MAAM,aAAa;AACxD,gBAAU,QAAQ,CAAC,IAAI,MAAM;AAC3B,kBAAU,EAAE,MAAM,KAAK,CAAC,WAAW,GAAG,IAAI,cAAc,GAAG,MAAM,GAAG;AAAA,MACtE,CAAC;AACD,YAAM,IAAI,MAAM,uBAAuB,YAAY,EAAE;AAAA,IACvD;AAGA,QAAI,CAAC,QAAQ,SAAS,CAAC,QAAQ,QAAQ;AACrC,YAAM,aAAa,MAAM,sBAAsB,YAAY;AAC3D,UAAI,YAAY;AACd,cAAM,IAAI,MAAM,qCAAqC,YAAY,4BAA4B;AAAA,MAC/F;AAAA,IACF;AAEA,QAAI,QAAQ,QAAQ;AAClB,YAAM,UAAU,CAAC,8BAA8B;AAC/C,UAAI,QAAQ,gBAAiB,SAAQ,KAAK,4BAA4B;AACtE,UAAI,QAAQ,aAAc,SAAQ,KAAK,kBAAkB,SAAS,MAAM,EAAE;AAE1E,aAAO,kBAAkB,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC7C;AAGA,UAAM,OAAO,CAAC,YAAY,QAAQ;AAClC,QAAI,QAAQ,MAAO,MAAK,KAAK,SAAS;AACtC,SAAK,KAAK,YAAY;AAEtB,UAAM,kBAAkB,MAAM,EAAE,KAAK,KAAK,kBAAkB,CAAC;AAG7D,QAAI,QAAQ,mBAAoB,MAAM,GAAG,WAAW,YAAY,GAAI;AAClE,YAAM,GAAG,OAAO,YAAY;AAAA,IAC9B;AAGA,QAAI,QAAQ,gBAAgB,CAAC,SAAS,MAAM;AAC1C,UAAI;AACF,cAAM,kBAAkB,CAAC,UAAU,MAAM,SAAS,MAAM,GAAG;AAAA,UACzD,KAAK,KAAK;AAAA,QACZ,CAAC;AAAA,MACH,SAAS,OAAO;AAGd,cAAM,IAAI;AAAA,UACR,gDAAgD,SAAS,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,QAC9H;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,cAAmD;AACxE,UAAM,SAAmB,CAAC;AAC1B,QAAI,eAAe;AACnB,QAAI,cAAc;AAClB,QAAI,iBAAiB;AAErB,QAAI;AAEF,qBAAe,MAAM,GAAG,WAAW,YAAY;AAC/C,UAAI,CAAC,cAAc;AACjB,eAAO,KAAK,2CAA2C;AAAA,MACzD;AAGA,UAAI,cAAc;AAChB,sBAAc,MAAM,eAAe,YAAY;AAC/C,YAAI,CAAC,aAAa;AAChB,iBAAO,KAAK,yCAAyC;AAAA,QACvD;AAAA,MACF;AAGA,UAAI,aAAa;AACf,cAAM,gBAAgB,MAAM,iBAAiB,YAAY;AACzD,yBAAiB,kBAAkB;AACnC,YAAI,CAAC,gBAAgB;AACnB,iBAAO,KAAK,oCAAoC;AAAA,QAClD;AAAA,MACF;AAGA,YAAM,YAAY,MAAM,KAAK,cAAc;AAC3C,YAAM,eAAe,UAAU,KAAK,QAAM,GAAG,SAAS,YAAY;AAClE,UAAI,CAAC,cAAc;AACjB,eAAO,KAAK,qCAAqC;AAAA,MACnD;AAAA,IACF,SAAS,OAAO;AACd,aAAO,KAAK,qBAAqB,iBAAiB,QAAQ,MAAM,UAAU,eAAe,EAAE;AAAA,IAC7F;AAEA,WAAO;AAAA,MACL,SAAS,OAAO,WAAW;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,cAA+C;AACrE,UAAM,eAAe,MAAM,kBAAkB,CAAC,UAAU,gBAAgB,GAAG;AAAA,MACzE,KAAK;AAAA,IACP,CAAC;AAED,QAAI,WAAW;AACf,QAAI,SAAS;AACb,QAAI,UAAU;AACd,QAAI,YAAY;AAEhB,UAAM,QAAQ,aAAa,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAC5D,eAAW,QAAQ,OAAO;AACxB,YAAM,SAAS,KAAK,UAAU,GAAG,CAAC;AAClC,UAAI,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,IAAK;AAC5C,UAAI,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,IAAK;AACjE,UAAI,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,MAAM,IAAK;AAC5C,UAAI,WAAW,KAAM;AAAA,IACvB;AAEA,UAAM,gBAAiB,MAAM,iBAAiB,YAAY,KAAM;AAChE,UAAM,WAAW,kBAAkB;AAGnC,QAAI,QAAQ;AACZ,QAAI,SAAS;AACb,QAAI;AACF,YAAM,oBAAoB,MAAM;AAAA,QAC9B,CAAC,YAAY,gBAAgB,WAAW,UAAU,aAAa,SAAS;AAAA,QACxE,EAAE,KAAK,aAAa;AAAA,MACtB;AACA,YAAM,QAAQ,kBAAkB,KAAK,EAAE,MAAM,GAAI;AACjD,YAAM,YAAY,MAAM,CAAC;AACzB,YAAM,WAAW,MAAM,CAAC;AACxB,eAAS,YAAY,SAAS,WAAW,EAAE,KAAK,IAAI;AACpD,cAAQ,WAAW,SAAS,UAAU,EAAE,KAAK,IAAI;AAAA,IACnD,QAAQ;AAAA,IAER;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,WAAW,SAAS,UAAU,YAAY;AAAA,MACtD,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBACE,YACA,YACA,SACQ;AACR,UAAM,OAAO,cAAc,KAAK;AAChC,WAAO,qBAAqB,YAAY,MAAM,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,YAA4B;AAC7C,WAAO,WACJ,QAAQ,OAAO,GAAG,EAClB,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE,EACpB,YAAY;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgC;AACpC,QAAI;AACF,YAAM,WAAW,MAAM,YAAY,KAAK,iBAAiB;AACzD,aAAO,aAAa;AAAA,IACtB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAIH;AACD,UAAM,OAAO,MAAM,YAAY,KAAK,iBAAiB;AACrD,UAAM,gBAAgB,MAAM,iBAAiB,KAAK,iBAAiB;AACnE,UAAM,gBAAgB,MAAM,iBAAiB,KAAK,iBAAiB;AAEnE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAgC;AACpC,UAAM,kBAAkB,CAAC,YAAY,SAAS,IAAI,GAAG,EAAE,KAAK,KAAK,kBAAkB,CAAC;AAAA,EACtF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,cAAsB,QAAgC;AACvE,UAAM,OAAO,CAAC,YAAY,QAAQ,YAAY;AAC9C,QAAI,OAAQ,MAAK,KAAK,YAAY,MAAM;AAExC,UAAM,kBAAkB,MAAM,EAAE,KAAK,KAAK,kBAAkB,CAAC;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,cAAqC;AACxD,UAAM,kBAAkB,CAAC,YAAY,UAAU,YAAY,GAAG,EAAE,KAAK,KAAK,kBAAkB,CAAC;AAAA,EAC/F;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,0BAA0B,YAA4C;AAC1E,UAAM,YAAY,MAAM,KAAK,cAAc,EAAE,WAAW,KAAK,CAAC;AAC9D,WAAO,UAAU;AAAA,MACf,QAAG;AAtZT;AAuZQ,kBAAG,OAAO,SAAS,UAAU,KAC7B,GAAG,KAAK,SAAS,UAAU,OAC3B,UAAK,wBAAwB,EAAE,MAA/B,mBAAkC,gBAAe;AAAA;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,qBAAqB,aAA2D;AACpF,UAAM,YAAY,MAAM,KAAK,cAAc,EAAE,WAAW,KAAK,CAAC;AAI9D,UAAM,UAAU,IAAI,OAAO,oBAAoB,WAAW,cAAc,GAAG;AAE3E,WAAO,UAAU,KAAK,QAAM,QAAQ,KAAK,GAAG,MAAM,CAAC,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAkB,UAAkB,YAAiD;AACzF,UAAM,YAAY,MAAM,KAAK,cAAc,EAAE,WAAW,KAAK,CAAC;AAG9D,UAAM,WAAW,UAAU,KAAK,QAAM,GAAG,WAAW,UAAU;AAC9D,QAAI,SAAU,QAAO;AAGrB,UAAM,cAAc,IAAI,OAAO,OAAO,QAAQ,GAAG;AACjD,WAAO,UAAU,KAAK,QAAM,YAAY,KAAK,GAAG,IAAI,CAAC,KAAK;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,gBACJ,WACA,iBACA,UAAkC,CAAC,GAKlC;AACD,UAAM,YAA8C,CAAC;AACrD,UAAM,WAA4D,CAAC;AACnE,UAAM,UAA4D,CAAC;AAEnE,eAAW,YAAY,WAAW;AAEhC,UAAI,MAAM,KAAK,eAAe,UAAU,eAAe,GAAG;AACxD,gBAAQ,KAAK,EAAE,UAAU,QAAQ,8BAA8B,CAAC;AAChE;AAAA,MACF;AAEA,UAAI;AACF,cAAM,KAAK,eAAe,SAAS,MAAM;AAAA,UACvC,GAAG;AAAA,UACH,iBAAiB;AAAA,QACnB,CAAC;AACD,kBAAU,KAAK,EAAE,SAAS,CAAC;AAAA,MAC7B,SAAS,OAAO;AACd,iBAAS,KAAK;AAAA,UACZ;AAAA,UACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,EAAE,WAAW,UAAU,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,UAIb;AACA,UAAM,WAAW,KAAK,wBAAwB,QAAQ;AACtD,UAAM,UAAU,WAAW,SAAS,QAAQ,MAAM;AAClD,UAAM,YAAY,SAAS,OAAO,YAAY;AAE9C,WAAO;AAAA,MACL,OAAO,GAAG,SAAS,MAAM,GAAG,OAAO,GAAG,SAAS;AAAA,MAC/C,MAAM,SAAS;AAAA,MACf,QAAQ,SAAS,OAAO,UAAU,GAAG,CAAC;AAAA,IACxC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/lib/GitWorktreeManager.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport {\n type GitWorktree,\n type WorktreeCreateOptions,\n type WorktreeListOptions,\n type WorktreeValidation,\n type WorktreeStatus,\n type WorktreeCleanupOptions,\n} from '../types/worktree.js'\nimport {\n executeGitCommand,\n parseWorktreeList,\n isPRBranch,\n extractPRNumber,\n generateWorktreePath,\n isValidGitRepo,\n getCurrentBranch,\n getRepoRoot,\n hasUncommittedChanges,\n getDefaultBranch,\n findMainWorktreePathWithSettings,\n} from '../utils/git.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport type { SettingsManager } from './SettingsManager.js'\n\n/**\n * Manages Git worktrees for the iloom CLI\n * Ports functionality from bash scripts into TypeScript\n */\nexport class GitWorktreeManager {\n private readonly _workingDirectory: string\n\n constructor(workingDirectory: string = process.cwd()) {\n this._workingDirectory = workingDirectory\n }\n\n /**\n * Get the working directory for git operations (main worktree path)\n */\n get workingDirectory(): string {\n return this._workingDirectory\n }\n\n /**\n * List all worktrees in the repository\n * Defaults to porcelain format for reliable machine parsing\n * Equivalent to: git worktree list --porcelain\n */\n async listWorktrees(options: WorktreeListOptions = {}): Promise<GitWorktree[]> {\n const args = ['worktree', 'list']\n // Default to porcelain format for consistent parsing (can be disabled with porcelain: false)\n if (options.porcelain !== false) args.push('--porcelain')\n if (options.verbose) args.push('-v')\n\n const output = await executeGitCommand(args, { cwd: this._workingDirectory })\n return parseWorktreeList(output)\n }\n\n /**\n * Find worktree for a specific branch\n * Ports: find_worktree_for_branch() from find-worktree-for-branch.sh\n */\n async findWorktreeForBranch(branchName: string): Promise<GitWorktree | null> {\n const worktrees = await this.listWorktrees()\n return worktrees.find(wt => wt.branch === branchName) ?? null\n }\n\n /**\n * Check if a worktree is the main repository worktree\n * Uses findMainWorktreePathWithSettings to determine the main worktree based on settings.\n *\n * @param worktree - The worktree to check\n * @param settingsManager - SettingsManager instance for loading settings\n * @returns true if the worktree is the main worktree\n */\n async isMainWorktree(worktree: GitWorktree, settingsManager: SettingsManager): Promise<boolean> {\n const mainWorktreePath = await findMainWorktreePathWithSettings(worktree.path, settingsManager)\n return worktree.path === mainWorktreePath\n }\n\n /**\n * Check if a worktree is a PR worktree based on naming patterns\n * Ports: is_pr_worktree() from worktree-utils.sh\n */\n isPRWorktree(worktree: GitWorktree): boolean {\n return isPRBranch(worktree.branch)\n }\n\n /**\n * Get PR number from worktree branch name\n * Ports: get_pr_number_from_worktree() from worktree-utils.sh\n */\n getPRNumberFromWorktree(worktree: GitWorktree): number | null {\n return extractPRNumber(worktree.branch)\n }\n\n /**\n * Create a new worktree\n * Ports worktree creation logic from new-branch-workflow.sh\n * @returns The absolute path to the created worktree\n */\n async createWorktree(options: WorktreeCreateOptions): Promise<string> {\n // Validate inputs\n if (!options.branch) {\n throw new Error('Branch name is required')\n }\n\n // Ensure path is absolute\n const absolutePath = path.resolve(options.path)\n\n // Check if path already exists and handle force flag\n if (await fs.pathExists(absolutePath)) {\n if (!options.force) {\n throw new Error(`Path already exists: ${absolutePath}`)\n }\n // Remove existing directory if force is true\n await fs.remove(absolutePath)\n }\n\n // Build git worktree add command\n const args = ['worktree', 'add']\n\n if (options.createBranch) {\n args.push('-b', options.branch)\n }\n\n if (options.force) {\n args.push('--force')\n }\n\n args.push(absolutePath)\n\n // Add branch name if not creating new branch\n if (!options.createBranch) {\n args.push(options.branch)\n } else if (options.baseBranch) {\n args.push(options.baseBranch)\n }\n\n // 5 minute timeout for repos with LFS that need to download large files\n await executeGitCommand(args, { cwd: this._workingDirectory, timeout: 300000 })\n return absolutePath\n }\n\n /**\n * Remove a worktree and optionally clean up associated files\n * Ports worktree removal logic from cleanup-worktree.sh\n * @returns A message describing what was done (for dry-run mode)\n */\n async removeWorktree(\n worktreePath: string,\n options: WorktreeCleanupOptions = {}\n ): Promise<string | void> {\n // Validate worktree exists - use porcelain format for consistent parsing\n const worktrees = await this.listWorktrees({ porcelain: true })\n const worktree = worktrees.find(wt => wt.path === worktreePath)\n\n if (!worktree) {\n // Add debug logging to help diagnose the issue\n getLogger().debug(`Looking for worktree path: ${worktreePath}`)\n getLogger().debug(`Found ${worktrees.length} worktrees:`)\n worktrees.forEach((wt, i) => {\n getLogger().debug(` ${i}: path=\"${wt.path}\", branch=\"${wt.branch}\"`)\n })\n throw new Error(`Worktree not found: ${worktreePath}`)\n }\n\n // Check for uncommitted changes unless force is specified\n if (!options.force && !options.dryRun) {\n const hasChanges = await hasUncommittedChanges(worktreePath)\n if (hasChanges) {\n throw new Error(`Worktree has uncommitted changes: ${worktreePath}. Use --force to override.`)\n }\n }\n\n if (options.dryRun) {\n const actions = ['Remove worktree registration']\n if (options.removeDirectory) actions.push('Remove directory from disk')\n if (options.removeBranch) actions.push(`Remove branch: ${worktree.branch}`)\n\n return `Would perform: ${actions.join(', ')}`\n }\n\n // Remove worktree registration\n const args = ['worktree', 'remove']\n if (options.force) args.push('--force')\n args.push(worktreePath)\n\n await executeGitCommand(args, { cwd: this._workingDirectory })\n\n // Remove directory if requested\n if (options.removeDirectory && (await fs.pathExists(worktreePath))) {\n await fs.remove(worktreePath)\n }\n\n // Remove branch if requested and safe to do so\n if (options.removeBranch && !worktree.bare) {\n try {\n await executeGitCommand(['branch', '-D', worktree.branch], {\n cwd: this._workingDirectory,\n })\n } catch (error) {\n // Don't fail the whole operation if branch deletion fails\n // Just log a warning (caller can handle this)\n throw new Error(\n `Worktree removed but failed to delete branch ${worktree.branch}: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n }\n }\n\n /**\n * Validate worktree state and integrity\n */\n async validateWorktree(worktreePath: string): Promise<WorktreeValidation> {\n const issues: string[] = []\n let existsOnDisk = false\n let isValidRepo = false\n let hasValidBranch = false\n\n try {\n // Check if path exists on disk\n existsOnDisk = await fs.pathExists(worktreePath)\n if (!existsOnDisk) {\n issues.push('Worktree directory does not exist on disk')\n }\n\n // Check if it's a valid Git repository\n if (existsOnDisk) {\n isValidRepo = await isValidGitRepo(worktreePath)\n if (!isValidRepo) {\n issues.push('Directory is not a valid Git repository')\n }\n }\n\n // Check if branch reference is valid\n if (isValidRepo) {\n const currentBranch = await getCurrentBranch(worktreePath)\n hasValidBranch = currentBranch !== null\n if (!hasValidBranch) {\n issues.push('Could not determine current branch')\n }\n }\n\n // Check if worktree is registered with Git\n const worktrees = await this.listWorktrees()\n const isRegistered = worktrees.some(wt => wt.path === worktreePath)\n if (!isRegistered) {\n issues.push('Worktree is not registered with Git')\n }\n } catch (error) {\n issues.push(`Validation error: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n\n return {\n isValid: issues.length === 0,\n issues,\n existsOnDisk,\n isValidRepo,\n hasValidBranch,\n }\n }\n\n /**\n * Get detailed status information for a worktree\n */\n async getWorktreeStatus(worktreePath: string): Promise<WorktreeStatus> {\n const statusOutput = await executeGitCommand(['status', '--porcelain=v1'], {\n cwd: worktreePath,\n })\n\n let modified = 0\n let staged = 0\n let deleted = 0\n let untracked = 0\n\n const lines = statusOutput.trim().split('\\n').filter(Boolean)\n for (const line of lines) {\n const status = line.substring(0, 2)\n if (status[0] === 'M' || status[1] === 'M') modified++\n if (status[0] === 'A' || status[0] === 'D' || status[0] === 'R') staged++\n if (status[0] === 'D' || status[1] === 'D') deleted++\n if (status === '??') untracked++\n }\n\n const currentBranch = (await getCurrentBranch(worktreePath)) ?? 'unknown'\n const detached = currentBranch === 'unknown'\n\n // Get ahead/behind information\n let ahead = 0\n let behind = 0\n try {\n const aheadBehindOutput = await executeGitCommand(\n ['rev-list', '--left-right', '--count', `origin/${currentBranch}...HEAD`],\n { cwd: worktreePath }\n )\n const parts = aheadBehindOutput.trim().split('\\t')\n const behindStr = parts[0]\n const aheadStr = parts[1]\n behind = behindStr ? parseInt(behindStr, 10) || 0 : 0\n ahead = aheadStr ? parseInt(aheadStr, 10) || 0 : 0\n } catch {\n // Ignore errors for ahead/behind calculation\n }\n\n return {\n modified,\n staged,\n deleted,\n untracked,\n hasChanges: modified + staged + deleted + untracked > 0,\n branch: currentBranch,\n detached,\n ahead,\n behind,\n }\n }\n\n /**\n * Generate a suggested worktree path for a branch\n */\n generateWorktreePath(\n branchName: string,\n customRoot?: string,\n options?: { isPR?: boolean; prNumber?: number; prefix?: string }\n ): string {\n const root = customRoot ?? this._workingDirectory\n return generateWorktreePath(branchName, root, options)\n }\n\n /**\n * Sanitize a branch name for use as a directory name\n * Replaces slashes with dashes and removes invalid filesystem characters\n * Ports logic from bash script line 593: ${BRANCH_NAME//\\\\//-}\n */\n sanitizeBranchName(branchName: string): string {\n return branchName\n .replace(/\\//g, '-') // Replace slashes with dashes\n .replace(/[^a-zA-Z0-9-]/g, '-') // Replace invalid chars (including underscores) with dashes\n .replace(/-+/g, '-') // Collapse multiple dashes\n .replace(/^-|-$/g, '') // Remove leading/trailing dashes\n .toLowerCase()\n }\n\n /**\n * Check if repository is in a valid state for worktree operations\n */\n async isRepoReady(): Promise<boolean> {\n try {\n const repoRoot = await getRepoRoot(this._workingDirectory)\n return repoRoot !== null\n } catch {\n return false\n }\n }\n\n /**\n * Get repository information\n */\n async getRepoInfo(): Promise<{\n root: string | null\n defaultBranch: string\n currentBranch: string | null\n }> {\n const root = await getRepoRoot(this._workingDirectory)\n const defaultBranch = await getDefaultBranch(this._workingDirectory)\n const currentBranch = await getCurrentBranch(this._workingDirectory)\n\n return {\n root,\n defaultBranch,\n currentBranch,\n }\n }\n\n /**\n * Prune stale worktree entries (worktrees that no longer exist on disk)\n */\n async pruneWorktrees(): Promise<void> {\n await executeGitCommand(['worktree', 'prune', '-v'], { cwd: this._workingDirectory })\n }\n\n /**\n * Lock a worktree to prevent it from being pruned or moved\n */\n async lockWorktree(worktreePath: string, reason?: string): Promise<void> {\n const args = ['worktree', 'lock', worktreePath]\n if (reason) args.push('--reason', reason)\n\n await executeGitCommand(args, { cwd: this._workingDirectory })\n }\n\n /**\n * Unlock a previously locked worktree\n */\n async unlockWorktree(worktreePath: string): Promise<void> {\n await executeGitCommand(['worktree', 'unlock', worktreePath], { cwd: this._workingDirectory })\n }\n\n /**\n * Find worktrees matching an identifier (branch name, path, or PR number)\n */\n async findWorktreesByIdentifier(identifier: string): Promise<GitWorktree[]> {\n const worktrees = await this.listWorktrees({ porcelain: true })\n return worktrees.filter(\n wt =>\n wt.branch.includes(identifier) ||\n wt.path.includes(identifier) ||\n this.getPRNumberFromWorktree(wt)?.toString() === identifier\n )\n }\n\n /**\n * Find worktree for a specific issue number using exact pattern matching\n * Matches: issue-{N} at start OR after /, -, _ (but NOT issue-{N}X where X is a digit)\n * Supports patterns like: issue-44, feat/issue-44-feature, feat-issue-44, bugfix_issue-44, etc.\n * Avoids false matches like: tissue-44, myissue-44\n * Ports: find_existing_worktree() from bash script lines 131-165\n */\n async findWorktreeForIssue(issueNumber: string | number): Promise<GitWorktree | null> {\n const worktrees = await this.listWorktrees({ porcelain: true })\n\n // Pattern: starts with 'issue-{N}' or 'issue/{N}' OR has '/issue-{N}', '-issue-{N}', '_issue-{N}' etc.\n // Uses [-/] after 'issue' to match both dash (feat/issue-42__desc) and slash (issue/42) conventions\n // Case-insensitive to handle Linear IDs (MARK-1 vs mark-1)\n const pattern = new RegExp(`(?:^|[/_-])issue[-/]${issueNumber}(?:-|__|$)`, 'i')\n\n return worktrees.find(wt => pattern.test(wt.branch)) ?? null\n }\n\n /**\n * Find worktree for a specific PR by branch name\n * Ports: find_existing_worktree() for PR type from bash script lines 149-160\n */\n async findWorktreeForPR(prNumber: number, branchName: string): Promise<GitWorktree | null> {\n const worktrees = await this.listWorktrees({ porcelain: true })\n\n // Find by exact branch name match (prioritized)\n const byBranch = worktrees.find(wt => wt.branch === branchName)\n if (byBranch) return byBranch\n\n // Also check directory name pattern: *_pr_{N}\n const pathPattern = new RegExp(`_pr_${prNumber}$`)\n return worktrees.find(wt => pathPattern.test(wt.path)) ?? null\n }\n\n /**\n * Remove multiple worktrees\n * Returns a summary of successes and failures\n * Automatically filters out the main worktree\n *\n * @param worktrees - Array of worktrees to remove\n * @param settingsManager - SettingsManager instance for determining main worktree\n * @param options - Cleanup options\n */\n async removeWorktrees(\n worktrees: GitWorktree[],\n settingsManager: SettingsManager,\n options: WorktreeCleanupOptions = {}\n ): Promise<{\n successes: Array<{ worktree: GitWorktree }>\n failures: Array<{ worktree: GitWorktree; error: string }>\n skipped: Array<{ worktree: GitWorktree; reason: string }>\n }> {\n const successes: Array<{ worktree: GitWorktree }> = []\n const failures: Array<{ worktree: GitWorktree; error: string }> = []\n const skipped: Array<{ worktree: GitWorktree; reason: string }> = []\n\n for (const worktree of worktrees) {\n // Skip main worktree\n if (await this.isMainWorktree(worktree, settingsManager)) {\n skipped.push({ worktree, reason: 'Cannot remove main worktree' })\n continue\n }\n\n try {\n await this.removeWorktree(worktree.path, {\n ...options,\n removeDirectory: true,\n })\n successes.push({ worktree })\n } catch (error) {\n failures.push({\n worktree,\n error: error instanceof Error ? error.message : 'Unknown error',\n })\n }\n }\n\n return { successes, failures, skipped }\n }\n\n /**\n * Format worktree information for display\n */\n formatWorktree(worktree: GitWorktree): {\n title: string\n path: string\n commit: string\n } {\n const prNumber = this.getPRNumberFromWorktree(worktree)\n const prLabel = prNumber ? ` (PR #${prNumber})` : ''\n const bareLabel = worktree.bare ? ' [main]' : ''\n\n return {\n title: `${worktree.branch}${prLabel}${bareLabel}`,\n path: worktree.path,\n commit: worktree.commit.substring(0, 7),\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VIQOQ463.js";
8
8
  import {
9
9
  GitWorktreeManager
10
- } from "./chunk-FV4KXBGO.js";
10
+ } from "./chunk-6RINI7OL.js";
11
11
  import {
12
12
  getPackageScripts
13
13
  } from "./chunk-K3QGG4O2.js";
@@ -156,4 +156,4 @@ var ScriptCommandBase = class {
156
156
  export {
157
157
  ScriptCommandBase
158
158
  };
159
- //# sourceMappingURL=chunk-IHSA7VGI.js.map
159
+ //# sourceMappingURL=chunk-CTHB7345.js.map
@@ -828,4 +828,4 @@ export {
828
828
  UserAbortedCommitError,
829
829
  CommitManager
830
830
  };
831
- //# sourceMappingURL=chunk-XVCGPTEQ.js.map
831
+ //# sourceMappingURL=chunk-GDDRANOZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ValidationRunner.ts","../src/types/index.ts","../src/utils/vscode.ts","../src/lib/CommitManager.ts"],"sourcesContent":["import { getLogger } from '../utils/logger-context.js'\nimport { detectPackageManager, runScript } from '../utils/package-manager.js'\nimport { getPackageConfig, hasScript } from '../utils/package-json.js'\nimport { detectClaudeCli, launchClaude } from '../utils/claude.js'\nimport type {\n\tValidationOptions,\n\tValidationResult,\n\tValidationStepResult,\n} from '../types/index.js'\n\n/**\n * ValidationRunner orchestrates pre-merge validation pipeline\n * Runs typecheck, lint, and tests in sequence with fail-fast behavior\n */\nexport class ValidationRunner {\n\tconstructor() {\n\t\t// Uses getLogger() for all logging operations\n\t}\n\n\t/**\n\t * Run all validations in sequence: typecheck → lint → test\n\t * Fails fast on first error\n\t */\n\tasync runValidations(\n\t\tworktreePath: string,\n\t\toptions: ValidationOptions = {}\n\t): Promise<ValidationResult> {\n\t\tconst startTime = Date.now()\n\t\tconst steps: ValidationStepResult[] = []\n\n\t\tconst { jsonStream } = options\n\n\t\t// Run typecheck\n\t\tif (!options.skipTypecheck) {\n\t\t\tconst typecheckResult = await this.runTypecheck(\n\t\t\t\tworktreePath,\n\t\t\t\toptions.dryRun ?? false,\n\t\t\t\t{ jsonStream }\n\t\t\t)\n\t\t\tsteps.push(typecheckResult)\n\n\t\t\tif (!typecheckResult.passed && !typecheckResult.skipped) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tsteps,\n\t\t\t\t\ttotalDuration: Date.now() - startTime,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Run lint\n\t\tif (!options.skipLint) {\n\t\t\tconst lintResult = await this.runLint(worktreePath, options.dryRun ?? false, { jsonStream })\n\t\t\tsteps.push(lintResult)\n\n\t\t\tif (!lintResult.passed && !lintResult.skipped) {\n\t\t\t\treturn { success: false, steps, totalDuration: Date.now() - startTime }\n\t\t\t}\n\t\t}\n\n\t\t// Run tests\n\t\tif (!options.skipTests) {\n\t\t\tconst testResult = await this.runTests(\n\t\t\t\tworktreePath,\n\t\t\t\toptions.dryRun ?? false,\n\t\t\t\t{ jsonStream }\n\t\t\t)\n\t\t\tsteps.push(testResult)\n\n\t\t\tif (!testResult.passed && !testResult.skipped) {\n\t\t\t\treturn { success: false, steps, totalDuration: Date.now() - startTime }\n\t\t\t}\n\t\t}\n\n\t\treturn { success: true, steps, totalDuration: Date.now() - startTime }\n\t}\n\n\t/**\n\t * Run typecheck validation\n\t * Prefers 'compile' script over 'typecheck' if both exist\n\t */\n\tprivate async runTypecheck(\n\t\tworktreePath: string,\n\t\tdryRun: boolean,\n\t\toptions: { jsonStream?: boolean | undefined } = {}\n\t): Promise<ValidationStepResult> {\n\t\tconst stepStartTime = Date.now()\n\n\t\tlet scriptToRun: 'compile' | 'typecheck' | null = null\n\n\t\ttry {\n\t\t\t// Check for compile and typecheck scripts - prefer compile if both exist\n\t\t\tconst pkgJson = await getPackageConfig(worktreePath)\n\t\t\tconst hasCompileScript = hasScript(pkgJson, 'compile')\n\t\t\tconst hasTypecheckScript = hasScript(pkgJson, 'typecheck')\n\n\t\t\tif (hasCompileScript) {\n\t\t\t\tscriptToRun = 'compile'\n\t\t\t} else if (hasTypecheckScript) {\n\t\t\t\tscriptToRun = 'typecheck'\n\t\t\t}\n\n\t\t\tif (!scriptToRun) {\n\t\t\t\tgetLogger().debug('Skipping typecheck - no compile or typecheck script found')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'typecheck',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip validation for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tgetLogger().debug('Skipping typecheck - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'typecheck',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\tconst packageManager = await detectPackageManager(worktreePath)\n\n\t\tif (dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm'\n\t\t\t\t\t? `npm run ${scriptToRun}`\n\t\t\t\t\t: `${packageManager} ${scriptToRun}`\n\t\t\tgetLogger().info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tstep: scriptToRun,\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t}\n\n\t\tgetLogger().info(`Running ${scriptToRun}...`)\n\n\t\ttry {\n\t\t\tawait runScript(scriptToRun, worktreePath, [], { quiet: true })\n\t\t\tgetLogger().success(`${scriptToRun.charAt(0).toUpperCase() + scriptToRun.slice(1)} passed`)\n\n\t\t\treturn {\n\t\t\t\tstep: scriptToRun,\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Attempt Claude-assisted fix before failing\n\t\t\tconst fixed = await this.attemptClaudeFix(\n\t\t\t\tscriptToRun,\n\t\t\t\tworktreePath,\n\t\t\t\tpackageManager,\n\t\t\t\t{ jsonStream: options.jsonStream }\n\t\t\t)\n\n\t\t\tif (fixed) {\n\t\t\t\treturn {\n\t\t\t\t\tstep: scriptToRun,\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: false,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Claude couldn't fix - throw original error\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm'\n\t\t\t\t\t? `npm run ${scriptToRun}`\n\t\t\t\t\t: `${packageManager} ${scriptToRun}`\n\n\t\t\tconst stepLabel = scriptToRun.charAt(0).toUpperCase() + scriptToRun.slice(1)\n\t\t\tthrow new Error(\n\t\t\t\t`Error: ${stepLabel} failed.\\n` +\n\t\t\t\t\t`Fix type errors before merging.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Run lint validation\n\t */\n\tprivate async runLint(\n\t\tworktreePath: string,\n\t\tdryRun: boolean,\n\t\toptions: { jsonStream?: boolean | undefined } = {}\n\t): Promise<ValidationStepResult> {\n\t\tconst stepStartTime = Date.now()\n\n\t\ttry {\n\t\t\t// Check if lint script exists\n\t\t\tconst pkgJson = await getPackageConfig(worktreePath)\n\t\t\tconst hasLintScript = hasScript(pkgJson, 'lint')\n\n\t\t\tif (!hasLintScript) {\n\t\t\t\tgetLogger().debug('Skipping lint - no lint script found')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'lint',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip validation for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tgetLogger().debug('Skipping lint - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'lint',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\tconst packageManager = await detectPackageManager(worktreePath)\n\n\t\tif (dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm' ? 'npm run lint' : `${packageManager} lint`\n\t\t\tgetLogger().info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tstep: 'lint',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t}\n\n\t\tgetLogger().info('Running lint...')\n\n\t\ttry {\n\t\t\tawait runScript('lint', worktreePath, [], { quiet: true })\n\t\t\tgetLogger().success('Linting passed')\n\n\t\t\treturn {\n\t\t\t\tstep: 'lint',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Attempt Claude-assisted fix before failing\n\t\t\tconst fixed = await this.attemptClaudeFix(\n\t\t\t\t'lint',\n\t\t\t\tworktreePath,\n\t\t\t\tpackageManager,\n\t\t\t\t{ jsonStream: options.jsonStream }\n\t\t\t)\n\n\t\t\tif (fixed) {\n\t\t\t\t// logger.success('Linting passed after Claude auto-fix')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'lint',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: false,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Claude couldn't fix - throw original error\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm' ? 'npm run lint' : `${packageManager} lint`\n\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Linting failed.\\n` +\n\t\t\t\t\t`Fix linting errors before merging.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Run test validation\n\t */\n\tprivate async runTests(\n\t\tworktreePath: string,\n\t\tdryRun: boolean,\n\t\toptions: { jsonStream?: boolean | undefined } = {}\n\t): Promise<ValidationStepResult> {\n\t\tconst stepStartTime = Date.now()\n\n\t\ttry {\n\t\t\t// Check if test script exists\n\t\t\tconst pkgJson = await getPackageConfig(worktreePath)\n\t\t\tconst hasTestScript = hasScript(pkgJson, 'test')\n\n\t\t\tif (!hasTestScript) {\n\t\t\t\tgetLogger().debug('Skipping tests - no test script found')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'test',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip validation for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tgetLogger().debug('Skipping tests - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'test',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\tconst packageManager = await detectPackageManager(worktreePath)\n\n\t\tif (dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm' ? 'npm run test' : `${packageManager} test`\n\t\t\tgetLogger().info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tstep: 'test',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t}\n\n\t\tgetLogger().info('Running tests...')\n\n\t\ttry {\n\t\t\tawait runScript('test', worktreePath, [], { quiet: true })\n\t\t\tgetLogger().success('Tests passed')\n\n\t\t\treturn {\n\t\t\t\tstep: 'test',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Attempt Claude-assisted fix before failing\n\t\t\tconst fixed = await this.attemptClaudeFix(\n\t\t\t\t'test',\n\t\t\t\tworktreePath,\n\t\t\t\tpackageManager,\n\t\t\t\t{ jsonStream: options.jsonStream }\n\t\t\t)\n\n\t\t\tif (fixed) {\n\t\t\t\t// logger.success('Tests passed after Claude auto-fix')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'test',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: false,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Claude couldn't fix - throw original error\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm' ? 'npm run test' : `${packageManager} test`\n\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Tests failed.\\n` +\n\t\t\t\t\t`Fix test failures before merging.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Attempt to fix validation errors using Claude\n\t * Pattern based on MergeManager.attemptClaudeConflictResolution\n\t *\n\t * @param validationType - Type of validation that failed ('compile' | 'typecheck' | 'lint' | 'test')\n\t * @param worktreePath - Path to the worktree\n\t * @param packageManager - Detected package manager\n\t * @returns true if Claude fixed the issue, false otherwise\n\t */\n\tprivate async attemptClaudeFix(\n\t\tvalidationType: 'compile' | 'typecheck' | 'lint' | 'test',\n\t\tworktreePath: string,\n\t\tpackageManager: string,\n\t\toptions: { jsonStream?: boolean | undefined } = {}\n\t): Promise<boolean> {\n\t\t// Check if Claude CLI is available\n\t\tconst isClaudeAvailable = await detectClaudeCli()\n\t\tif (!isClaudeAvailable) {\n\t\t\tgetLogger().debug('Claude CLI not available, skipping auto-fix')\n\t\t\treturn false\n\t\t}\n\n\t\t// Build validation command for the prompt\n\t\tconst validationCommand = this.getValidationCommand(validationType, packageManager)\n\n\t\t// Build prompt based on validation type (matching bash script prompts)\n\t\tconst prompt = this.getClaudePrompt(validationType, validationCommand)\n\n\t\tconst validationTypeCapitalized = validationType.charAt(0).toUpperCase() + validationType.slice(1)\n\t\tgetLogger().info(`Launching Claude to help fix ${validationTypeCapitalized} errors...`)\n\n\t\ttry {\n\t\t\t// When jsonStream is true, run Claude headless with stdout passthrough for JSONL streaming\n\t\t\t// Otherwise, launch interactively in the current terminal\n\t\t\tawait launchClaude(prompt, {\n\t\t\t\taddDir: worktreePath,\n\t\t\t\theadless: !!options.jsonStream,\n\t\t\t\tpermissionMode: options.jsonStream ? 'bypassPermissions' : 'acceptEdits',\n\t\t\t\tmodel: 'sonnet',\n\t\t\t\tnoSessionPersistence: true,\n\t\t\t\t...(options.jsonStream && { passthroughStdout: true }),\n\t\t\t})\n\n\t\t\t// After Claude completes, re-run validation to verify fix\n\t\t\tgetLogger().info(`Re-running ${validationTypeCapitalized} after Claude's fixes...`)\n\n\t\t\ttry {\n\t\t\t\tawait runScript(validationType, worktreePath, [], { quiet: true })\n\t\t\t\t// Validation passed after Claude fix\n\t\t\t\tgetLogger().success(`${validationTypeCapitalized} passed after Claude auto-fix`)\n\t\t\t\treturn true\n\t\t\t} catch {\n\t\t\t\t// Validation still failing after Claude's attempt\n\t\t\t\tgetLogger().warn(`${validationTypeCapitalized} still failing after Claude's help`)\n\t\t\t\treturn false\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Claude launch failed or crashed\n\t\t\tgetLogger().warn('Claude auto-fix failed', {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t})\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Get validation command string for prompts\n\t * Uses il commands for multi-language project support\n\t */\n\tprivate getValidationCommand(\n\t\tvalidationType: 'compile' | 'typecheck' | 'lint' | 'test',\n\t\t_packageManager: string\n\t): string {\n\t\t// Use il commands for consistent multi-language project support\n\t\treturn `il ${validationType}`\n\t}\n\n\t/**\n\t * Get Claude prompt for specific validation type\n\t * Matches bash script prompts exactly\n\t */\n\tprivate getClaudePrompt(\n\t\tvalidationType: 'compile' | 'typecheck' | 'lint' | 'test',\n\t\tvalidationCommand: string\n\t): string {\n\t\tswitch (validationType) {\n\t\t\tcase 'compile':\n\t\t\tcase 'typecheck':\n\t\t\t\treturn (\n\t\t\t\t\t`There are compilation errors in this codebase. ` +\n\t\t\t\t\t`Please analyze the ${validationType} output, identify all type errors, and fix them. ` +\n\t\t\t\t\t`Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all type issues. ` +\n\t\t\t\t\t`When you are done, tell the user to quit using /exit to continue the validation process.`\n\t\t\t\t)\n\t\t\tcase 'lint':\n\t\t\t\treturn (\n\t\t\t\t\t`There are Lint errors in this codebase. ` +\n\t\t\t\t\t`Please analyze the linting output, identify all linting issues, and fix them. ` +\n\t\t\t\t\t`Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all linting issues. ` +\n\t\t\t\t\t`Focus on code quality, consistency, and following the project's linting rules. ` +\n\t\t\t\t\t`When you are done, tell the user to quit using /exit to continue the validation process.`\n\t\t\t\t)\n\t\t\tcase 'test':\n\t\t\t\treturn (\n\t\t\t\t\t`There are unit test failures in this codebase. ` +\n\t\t\t\t\t`Please analyze the test output to understand what's failing, then fix the issues. ` +\n\t\t\t\t\t`This might involve updating test code, fixing bugs in the source code, or updating tests to match new behavior. ` +\n\t\t\t\t\t`Run '${validationCommand}' to see the detailed test failures, then make the necessary changes to get all tests passing. ` +\n\t\t\t\t\t`When you are done, tell the user to quit using /exit to continue the validation process.`\n\t\t\t\t)\n\t\t}\n\t}\n}\n","// Core types\nexport interface Workspace {\n id: string\n path: string\n branch: string\n issueNumber?: string | number\n prNumber?: number\n port: number\n databaseBranch?: string\n createdAt: Date\n lastAccessed: Date\n}\n\nexport interface WorkspaceInput {\n identifier: string\n type: 'issue' | 'pr' | 'branch'\n skipClaude?: boolean\n}\n\nexport interface WorkspaceSummary {\n id: string\n issueNumber?: string | number\n prNumber?: number\n title: string\n branch: string\n port: number\n status: 'active' | 'stale' | 'error'\n lastAccessed: string\n}\n\n// Git types\nexport interface Worktree {\n path: string\n branch: string\n commit: string\n isPR: boolean\n prNumber?: number\n issueNumber?: string | number\n port?: number\n}\n\nexport interface GitStatus {\n hasUncommittedChanges: boolean\n unstagedFiles: string[]\n stagedFiles: string[]\n currentBranch: string\n isAheadOfRemote: boolean\n isBehindRemote: boolean\n}\n\n// GitHub types\nexport interface Issue {\n number: string | number\n title: string\n body: string\n state: 'open' | 'closed'\n labels: string[]\n assignees: string[]\n url: string\n}\n\nexport interface PullRequest {\n number: number\n title: string\n body: string\n state: 'open' | 'closed' | 'merged'\n branch: string\n baseBranch: string\n url: string\n isDraft: boolean\n isFork?: boolean\n}\n\n// Issue Tracker types\n/**\n * Generic input detection result for issue trackers\n * String-based identifier to support non-numeric IDs (e.g., Linear \"ENG-123\")\n */\nexport interface IssueTrackerInputDetection {\n\ttype: 'issue' | 'pr' | 'unknown'\n\tidentifier: string | null\n\trawInput: string\n}\n\n/**\n * Re-export branch naming types from branch-naming module\n * These types are provider-agnostic and support all issue trackers\n */\nexport type { BranchNameStrategy, BranchGenerationOptions } from './branch-naming.js'\n\n// Database types\n\n/**\n * Result of database branch deletion operation\n * Distinguishes between successful deletion, branch not found, and errors\n */\nexport interface DatabaseDeletionResult {\n /** Overall operation succeeded (true even if branch didn't exist) */\n success: boolean\n /** True only if a branch was actually deleted */\n deleted: boolean\n /** True if branch didn't exist (not an error, just nothing to do) */\n notFound: boolean\n /** Error message if operation failed */\n error?: string\n /** User declined deletion (for preview databases) */\n userDeclined?: boolean\n /** Name of the branch that was processed */\n branchName?: string\n}\n\nexport interface DatabaseProvider {\n // Core operations\n createBranch(name: string, fromBranch?: string, cwd?: string): Promise<string>\n deleteBranch(name: string, isPreview?: boolean, cwd?: string): Promise<DatabaseDeletionResult>\n getConnectionString(branch: string, cwd?: string): Promise<string>\n listBranches(cwd?: string): Promise<string[]>\n branchExists(name: string, cwd?: string): Promise<boolean>\n\n // Additional operations for Vercel integration and validation\n findPreviewBranch(branchName: string, cwd?: string): Promise<string | null>\n getBranchNameFromEndpoint(endpointId: string, cwd?: string): Promise<string | null>\n sanitizeBranchName(branchName: string): string\n isAuthenticated(cwd?: string): Promise<boolean>\n isCliAvailable(): Promise<boolean>\n\n // Configuration validation\n isConfigured(): boolean\n}\n\n// Configuration types\nexport interface Config {\n defaultPort: number\n databaseProvider?: 'neon' | 'supabase' | 'planetscale'\n claudeModel?: 'opus' | 'sonnet' | 'haiku'\n skipClaude?: boolean\n customWorkspaceRoot?: string\n}\n\n// One-shot automation mode type\nexport type OneShotMode = 'default' | 'noReview' | 'bypassPermissions'\n\n// Complexity override type\nexport type ComplexityOverride = 'trivial' | 'simple' | 'complex'\n\n// Command option types\nexport interface StartOptions {\n // Individual component flags (can be combined)\n claude?: boolean\n code?: boolean\n devServer?: boolean\n terminal?: boolean\n // Child loom control flag\n childLoom?: boolean\n // Epic loom control flag (for issues with child issues)\n epic?: boolean\n // Create-only mode: skip Claude, IDE, terminal, dev server, and epic\n createOnly?: boolean\n // One-shot automation mode\n oneShot?: OneShotMode\n // Complexity override (skips complexity evaluation)\n complexity?: ComplexityOverride\n // Optional body text for issue creation\n body?: string\n // Output result as JSON\n json?: boolean\n}\n\nexport interface AddIssueOptions {\n // Optional body text for issue (skips AI enhancement)\n body?: string\n // Output result as JSON\n json?: boolean\n}\n\nexport interface FeedbackOptions {\n // Optional body text for feedback (added after diagnostics)\n body?: string\n}\n\nexport interface EnhanceOptions {\n noBrowser?: boolean // --no-browser flag - skip browser opening prompt\n json?: boolean // --json flag - output result as JSON\n}\n\nexport interface FinishOptions {\n force?: boolean // -f, --force - Skip confirmation prompts\n dryRun?: boolean // -n, --dry-run - Preview actions without executing\n pr?: number // --pr <number> - Treat input as PR number\n skipBuild?: boolean // --skip-build - Skip post-merge build verification\n noBrowser?: boolean // --no-browser - Skip opening PR in browser (pr mode only)\n cleanup?: boolean // --cleanup / --no-cleanup - Control worktree cleanup after finishing\n json?: boolean // --json - Output result as JSON\n skipToPr?: boolean // --skip-to-pr - Skip rebase/validation/commit, go directly to PR creation (debug)\n jsonStream?: boolean // --json-stream - Stream JSONL output for Claude conflict resolution\n review?: boolean // --review - Review commit message before committing (default: auto-commit without review)\n}\n\n/**\n * Options for the cleanup command\n * All flags are optional and can be combined (subject to validation)\n */\nexport interface CleanupOptions {\n /** List all worktrees without removing anything */\n list?: boolean\n /** Remove all worktrees (interactive confirmation required unless --force) */\n all?: boolean\n /** Cleanup by specific issue identifier (numeric or alphanumeric like RANDOM-13) */\n issue?: string | number\n /** Skip confirmations and force removal */\n force?: boolean\n /** Show what would be done without actually doing it */\n dryRun?: boolean\n /** Output result as JSON */\n json?: boolean\n /** Wait specified milliseconds before cleanup execution */\n defer?: number\n /** Archive metadata instead of deleting (preserves loom in il list --finished) */\n archive?: boolean\n}\n\nexport interface ListOptions {\n json?: boolean\n}\n\n// JSON output result types for add-issue and enhance commands\nexport interface AddIssueResult {\n url: string\n id: number\n title: string\n created_at: string\n}\n\nexport interface EnhanceResult {\n url: string\n id: number\n title: string\n created_at: string\n enhanced: boolean\n}\n\nexport interface StartResult {\n id: string\n path: string\n branch: string\n port?: number\n type: 'issue' | 'pr' | 'branch' | 'epic'\n identifier: string | number\n title?: string\n capabilities?: string[]\n childIssueNumbers?: string[]\n}\n\nexport interface FinishResult {\n success: boolean\n type: 'issue' | 'pr' | 'branch' | 'epic'\n identifier: string | number\n /** Whether this was a dry-run operation */\n dryRun?: boolean\n operations: Array<{\n type: 'validation' | 'commit' | 'rebase' | 'merge' | 'cleanup' | 'pr-creation' | 'pr-ready' | 'build'\n message: string\n success: boolean\n error?: string\n }>\n prUrl?: string\n cleanupResult?: import('./cleanup.js').CleanupResult\n}\n\nexport interface SummaryResult {\n summary: string\n sessionId: string\n issueNumber?: string | number\n branchName: string\n loomType: 'issue' | 'pr' | 'branch' | 'epic'\n}\n\nexport interface RebaseResult {\n success: boolean\n conflictsDetected: boolean\n claudeLaunched: boolean\n conflictsResolved?: boolean\n error?: string\n}\n\nexport interface RebaseOutcome {\n conflictsDetected: boolean\n claudeLaunched: boolean\n conflictsResolved: boolean\n}\n\n// Deprecated: Result types - use exception-based error handling instead\n// export type Result<T, E = Error> = { success: true; data: T } | { success: false; error: E }\n\n// Mock factory types for testing\nexport interface MockOptions {\n scenario: 'empty' | 'existing' | 'conflicts' | 'error'\n data?: unknown\n}\n\n// Worktree management types\nexport * from './worktree.js'\n\n// Environment management types\nexport * from './environment.js'\n\n// Loom types\nexport * from './loom.js'\n\n// Cleanup types\nexport * from './cleanup.js'\n\n// Process types (excluding Platform which is already defined above)\nexport type { ProcessInfo } from './process.js'\n\n// Color synchronization types\nexport interface RgbColor {\n\tr: number\n\tg: number\n\tb: number\n}\n\nexport interface ColorData {\n\trgb: RgbColor\n\thex: string\n\tindex: number\n}\n\nexport type Platform = 'darwin' | 'linux' | 'win32' | 'unsupported'\n\n// Validation types\nexport interface ValidationOptions {\n\tdryRun?: boolean\n\tskipTypecheck?: boolean\n\tskipLint?: boolean\n\tskipTests?: boolean\n\tjsonStream?: boolean\n}\n\nexport interface ValidationStepResult {\n\tstep: 'typecheck' | 'compile' | 'lint' | 'test'\n\tpassed: boolean\n\tskipped: boolean\n\toutput?: string\n\terror?: string\n\tduration?: number\n}\n\nexport interface ValidationResult {\n\tsuccess: boolean\n\tsteps: ValidationStepResult[]\n\ttotalDuration: number\n}\n\n// Commit management types\nexport interface CommitOptions {\n\tdryRun?: boolean\n\tissueNumber?: string | number // For \"Fixes #N\" or \"Refs #N\" trailer\n\tissuePrefix: string // \"#\" for GitHub, \"\" for Linear\n\tmessage?: string // Custom message override\n\tnoReview?: boolean // Skip user review of commit message\n\tskipVerify?: boolean // Skip pre-commit hooks (--no-verify flag)\n\tskipVerifySilent?: boolean // Skip without warning (for --wip-commit)\n\ttrailerType?: 'Refs' | 'Fixes' // Trailer type: \"Refs\" references issue, \"Fixes\" closes it (default: 'Fixes' for backward compat)\n\ttimeout?: number // Timeout in milliseconds for commit operation\n}\n\n/**\n * Error thrown when user aborts a commit operation\n * Used by CommitManager when user selects 'abort' at the commit prompt\n */\nexport class UserAbortedCommitError extends Error {\n\tconstructor(message = 'User aborted the commit') {\n\t\tsuper(message)\n\t\tthis.name = 'UserAbortedCommitError'\n\t}\n}\n\n// Merge management types\nexport interface MergeOptions {\n\tdryRun?: boolean // Preview actions without executing\n\tforce?: boolean // Skip confirmation prompts\n\trepoRoot?: string // Repository root path (optional, auto-detected if not provided)\n\tjsonStream?: boolean // When true, run Claude headless and stream JSONL for conflict resolution\n}\n\nexport interface MergeResult {\n\tsuccess: boolean\n\tbranchName: string\n\tcommitsMerged: number\n\trebaseCompleted: boolean\n\tmergeCompleted: boolean\n}\n\n// Update notification types\nexport interface UpdateCheckCache {\n\tlastCheck: number // Unix timestamp\n\tlatestVersion: string\n}\n\nexport interface UpdateCheckResult {\n\tcurrentVersion: string\n\tlatestVersion: string\n\tupdateAvailable: boolean\n}\n\nexport type InstallationMethod = 'global' | 'local' | 'linked' | 'unknown'\n\n// Telemetry types\nexport * from './telemetry.js'\n","import { execa } from 'execa'\nimport { logger } from './logger.js'\n\n/**\n * Check if running inside VSCode's integrated terminal\n * VSCode sets TERM_PROGRAM=vscode in its integrated terminal\n */\nexport function isRunningInVSCode(): boolean {\n\treturn process.env.TERM_PROGRAM === 'vscode'\n}\n\n/**\n * Check if running inside Cursor's integrated terminal\n * Cursor sets CURSOR_TRACE_ID environment variable in its terminal\n * Note: Cursor may also set TERM_PROGRAM=vscode, so this check should be done first\n */\nexport function isRunningInCursor(): boolean {\n\treturn !!process.env.CURSOR_TRACE_ID\n}\n\n/**\n * Check if running inside Antigravity's integrated terminal\n * Antigravity sets ANTIGRAVITY_CLI_ALIAS environment variable\n * Note: This check should be done FIRST before Cursor and VSCode\n */\nexport function isRunningInAntigravity(): boolean {\n\treturn !!process.env.ANTIGRAVITY_CLI_ALIAS\n}\n\n/**\n * Check if VSCode command-line tool is available\n */\nexport async function isVSCodeAvailable(): Promise<boolean> {\n\ttry {\n\t\tawait execa('command', ['-v', 'code'], {\n\t\t\tshell: true,\n\t\t\ttimeout: 5000,\n\t\t})\n\t\treturn true\n\t} catch (error) {\n\t\tlogger.debug('VSCode CLI not available', { error })\n\t\treturn false\n\t}\n}\n\n/**\n * Check if Cursor command-line tool is available\n */\nexport async function isCursorAvailable(): Promise<boolean> {\n\ttry {\n\t\tawait execa('command', ['-v', 'cursor'], {\n\t\t\tshell: true,\n\t\t\ttimeout: 5000,\n\t\t})\n\t\treturn true\n\t} catch (error) {\n\t\tlogger.debug('Cursor CLI not available', { error })\n\t\treturn false\n\t}\n}\n\n/**\n * Check if Antigravity command-line tool is available\n */\nexport async function isAntigravityAvailable(): Promise<boolean> {\n\ttry {\n\t\tawait execa('command', ['-v', 'agy'], {\n\t\t\tshell: true,\n\t\t\ttimeout: 5000,\n\t\t})\n\t\treturn true\n\t} catch (error) {\n\t\tlogger.debug('Antigravity CLI not available', { error })\n\t\treturn false\n\t}\n}\n\n/**\n * Open VSCode window for workspace\n * Throws error if VSCode not available\n */\nexport async function openVSCodeWindow(workspacePath: string): Promise<void> {\n\t// Check availability first\n\tconst available = await isVSCodeAvailable()\n\tif (!available) {\n\t\tthrow new Error(\n\t\t\t'VSCode is not available. Please install VSCode and ensure the \"code\" command is in your PATH.\\n' +\n\t\t\t\t'Install command-line tools: Open VSCode > Command Palette > \"Shell Command: Install \\'code\\' command in PATH\"'\n\t\t)\n\t}\n\n\ttry {\n\t\t// Launch VSCode with workspace path\n\t\tawait execa('code', [workspacePath])\n\t\tlogger.debug(`Opened VSCode for workspace: ${workspacePath}`)\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to open VSCode: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t)\n\t}\n}\n","import { executeGitCommand } from '../utils/git.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport { launchClaude, detectClaudeCli } from '../utils/claude.js'\nimport { promptCommitAction } from '../utils/prompt.js'\nimport { isRunningInVSCode, isVSCodeAvailable, isRunningInCursor, isCursorAvailable, isRunningInAntigravity, isAntigravityAvailable } from '../utils/vscode.js'\nimport { UserAbortedCommitError } from '../types/index.js'\nimport type { GitStatus, CommitOptions } from '../types/index.js'\nimport { writeFile, readFile, unlink } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { execa } from 'execa'\n\n/**\n * CommitManager handles uncommitted changes detection and auto-commit\n * Ports logic from bash/merge-and-clean.sh lines 610-643\n */\nexport class CommitManager {\n constructor() {\n // Uses getLogger() for all logging operations\n }\n\n /**\n * Detect uncommitted changes in a worktree\n * Parses git status --porcelain output into structured GitStatus\n */\n async detectUncommittedChanges(worktreePath: string): Promise<GitStatus> {\n // Execute: git status --porcelain\n const porcelainOutput = await executeGitCommand(['status', '--porcelain'], {\n cwd: worktreePath,\n })\n\n // Parse output to get staged and unstaged files\n const { stagedFiles, unstagedFiles } = this.parseGitStatus(porcelainOutput)\n\n // Get current branch name\n const currentBranch = await executeGitCommand(['branch', '--show-current'], {\n cwd: worktreePath,\n })\n\n return {\n hasUncommittedChanges: stagedFiles.length > 0 || unstagedFiles.length > 0,\n unstagedFiles,\n stagedFiles,\n currentBranch: currentBranch.trim(),\n // Defer these to future enhancement\n isAheadOfRemote: false,\n isBehindRemote: false,\n }\n }\n\n\n /**\n * Stage all changes and commit with Claude-generated or simple message\n * Tries Claude first, falls back to simple message if Claude unavailable or fails\n * Returns the commit message that was used\n */\n async commitChanges(worktreePath: string, options: CommitOptions): Promise<{ message: string }> {\n // Step 1: Check dry-run mode\n if (options.dryRun) {\n getLogger().info('[DRY RUN] Would run: git add -A')\n getLogger().info('[DRY RUN] Would generate commit message with Claude (if available)')\n const fallbackMessage = this.generateFallbackMessage(options)\n const verifyFlag = options.skipVerify ? ' --no-verify' : ''\n getLogger().info(`[DRY RUN] Would commit with message${verifyFlag}: ${fallbackMessage}`)\n return { message: fallbackMessage }\n }\n\n // Step 2: Stage all changes\n await executeGitCommand(['add', '-A'], { cwd: worktreePath })\n\n // Step 3: Generate commit message (try Claude first, fallback to simple)\n let message: string | null = null\n\n // Skip Claude if custom message provided\n if (!options.message) {\n try {\n message = await this.generateClaudeCommitMessage(worktreePath, options.issueNumber, options.issuePrefix, options.trailerType)\n } catch (error) {\n getLogger().debug('Claude commit message generation failed, using fallback', { error })\n }\n }\n\n // Fallback to simple message if Claude failed or unavailable\n message ??= this.generateFallbackMessage(options)\n\n // Step 4: Log warning if --no-verify is configured (but not for silent skip like --wip-commit)\n if (options.skipVerify && !options.skipVerifySilent) {\n getLogger().warn('Skipping pre-commit hooks (--no-verify configured in settings)')\n }\n\n // Step 5: Commit with user review via prompt (unless noReview specified)\n try {\n if (options.noReview || options.message) {\n // Direct commit without review (custom message or noReview flag)\n const commitArgs = ['commit', '-m', message]\n if (options.skipVerify) {\n commitArgs.push('--no-verify')\n }\n await executeGitCommand(commitArgs, { cwd: worktreePath, ...(options.timeout !== undefined && { timeout: options.timeout }) })\n } else {\n // Prompt user for action instead of going straight to editor\n const action = await promptCommitAction(message)\n\n if (action === 'abort') {\n throw new UserAbortedCommitError()\n }\n\n if (action === 'accept') {\n // Direct commit with -m flag (no editor)\n const commitArgs = ['commit', '-m', message]\n if (options.skipVerify) {\n commitArgs.push('--no-verify')\n }\n await executeGitCommand(commitArgs, { cwd: worktreePath, ...(options.timeout !== undefined && { timeout: options.timeout }) })\n } else {\n // action === 'edit': Use git editor for user review\n getLogger().info('Opening editor for commit message review...')\n\n // Check for Antigravity FIRST as it takes priority\n if (isRunningInAntigravity() && await isAntigravityAvailable()) {\n await this.commitWithExternalEditor(worktreePath, message, options, 'agy', 'Antigravity')\n // Check for Cursor SECOND since it may also set TERM_PROGRAM=vscode\n // Use Cursor-specific flow when running in Cursor terminal\n } else if (isRunningInCursor() && await isCursorAvailable()) {\n await this.commitWithExternalEditor(worktreePath, message, options, 'cursor', 'Cursor')\n // Use VSCode-specific flow when running in VSCode terminal\n // This opens the file in the current VSCode window instead of a random one\n } else if (isRunningInVSCode() && await isVSCodeAvailable()) {\n await this.commitWithExternalEditor(worktreePath, message, options, 'code', 'VSCode')\n } else {\n // Standard git editor flow for non-VSCode/Cursor/Antigravity environments\n const commitArgs = ['commit', '-e', '-m', message]\n if (options.skipVerify) {\n commitArgs.push('--no-verify')\n }\n await executeGitCommand(commitArgs, {\n cwd: worktreePath,\n stdio: 'inherit',\n timeout: Math.max(options.timeout ?? 0, 300000) // Use the larger of configured timeout or 5 minutes for interactive editing\n })\n }\n }\n }\n return { message }\n } catch (error) {\n // Re-throw UserAbortedCommitError as-is\n if (error instanceof UserAbortedCommitError) {\n throw error\n }\n // Handle \"nothing to commit\" scenario gracefully\n if (error instanceof Error && error.message.includes('nothing to commit')) {\n getLogger().info('No changes to commit')\n return { message: '' }\n }\n // Re-throw all other errors (including pre-commit hook failures)\n throw error\n }\n }\n\n\n /**\n * Commit with external editor CLI (VSCode, Cursor, Antigravity, etc.)\n * Handles file creation, editing, and commit to ensure the file opens\n * in the current editor window (preserves IPC context)\n */\n private async commitWithExternalEditor(\n worktreePath: string,\n message: string,\n options: CommitOptions,\n cliCommand: string,\n editorName: string\n ): Promise<void> {\n // Put the commit message file in the worktree root so the editor opens it\n // in the correct window (files within a workspace folder open in that workspace's window)\n const commitMsgPath = join(worktreePath, '.COMMIT_EDITMSG')\n\n // Write the initial commit message (with git-style comments)\n const initialContent = `${message}\n\n# Please enter the commit message for your changes. Lines starting\n# with '#' will be ignored, and an empty message aborts the commit.\n#\n# Save and close the file to complete the commit.\n`\n await writeFile(commitMsgPath, initialContent, 'utf-8')\n\n try {\n getLogger().debug(`Opening commit message in ${editorName}: ${commitMsgPath}`)\n\n // Open the file with --wait flag so we block until the user closes it\n await execa(cliCommand, ['--wait', commitMsgPath], {\n cwd: worktreePath,\n stdio: 'inherit'\n })\n\n // Read the edited message\n const editedContent = await readFile(commitMsgPath, 'utf-8')\n\n // Strip comment lines and trim\n const finalMessage = editedContent\n .split('\\n')\n .filter(line => !line.startsWith('#'))\n .join('\\n')\n .trim()\n\n // Check for empty message (user aborted)\n if (!finalMessage) {\n throw new UserAbortedCommitError()\n }\n\n // Commit with the edited message\n const commitArgs = ['commit', '-F', commitMsgPath]\n if (options.skipVerify) {\n commitArgs.push('--no-verify')\n }\n\n // Rewrite the file without comments for git commit -F\n await writeFile(commitMsgPath, finalMessage, 'utf-8')\n await executeGitCommand(commitArgs, { cwd: worktreePath, ...(options.timeout !== undefined && { timeout: options.timeout }) })\n\n } finally {\n // Clean up - git normally handles this but we should be safe\n try {\n await unlink(commitMsgPath)\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n\n /**\n * Generate simple fallback commit message when Claude unavailable\n * Used as fallback for Claude-powered commit messages\n */\n private generateFallbackMessage(options: CommitOptions): string {\n // If custom message provided, use it\n if (options.message) {\n return options.message\n }\n\n // Generate WIP message\n if (options.issueNumber) {\n const trailer = options.trailerType ?? 'Fixes'\n return `WIP: Auto-commit for issue ${options.issuePrefix}${options.issueNumber}\\n\\n${trailer} ${options.issuePrefix}${options.issueNumber}`\n } else {\n return 'WIP: Auto-commit uncommitted changes'\n }\n }\n\n /**\n * Parse git status --porcelain output\n * Format: \"XY filename\" where X=index, Y=worktree\n * Examples:\n * \"M file.ts\" - staged modification\n * \" M file.ts\" - unstaged modification\n * \"MM file.ts\" - both staged and unstaged\n * \"?? file.ts\" - untracked\n */\n private parseGitStatus(porcelainOutput: string): {\n stagedFiles: string[]\n unstagedFiles: string[]\n } {\n const stagedFiles: string[] = []\n const unstagedFiles: string[] = []\n\n if (!porcelainOutput.trim()) {\n return { stagedFiles, unstagedFiles }\n }\n\n const lines = porcelainOutput.split('\\n').filter((line) => line.trim())\n\n for (const line of lines) {\n if (line.length < 3) continue\n\n const indexStatus = line[0] // First character - staging area status\n const worktreeStatus = line[1] // Second character - working tree status\n const filename = line.substring(3) // Everything after \"XY \"\n\n // Check if file is staged\n // First char != ' ' and != '?' → staged\n if (indexStatus !== ' ' && indexStatus !== '?') {\n stagedFiles.push(filename)\n }\n\n // Check if file is unstaged\n // Second char != ' ' or line starts with '??' → unstaged\n if (worktreeStatus !== ' ' || line.startsWith('??')) {\n unstagedFiles.push(filename)\n }\n }\n\n return { stagedFiles, unstagedFiles }\n }\n\n /**\n * Generate commit message using Claude Code\n * Claude examines the git repository directly via --add-dir option\n * Returns null if Claude unavailable or fails validation\n */\n private async generateClaudeCommitMessage(\n worktreePath: string,\n issueNumber: string | number | undefined,\n issuePrefix: string,\n trailerType?: 'Refs' | 'Fixes'\n ): Promise<string | null> {\n const startTime = Date.now()\n\n if (getLogger().isDebugEnabled()) {\n getLogger().debug('Claude commit message generation started', {\n worktreePath: worktreePath.split('/').pop(), // Just show the folder name for privacy\n issueNumber\n })\n } else {\n getLogger().info('Generating commit message with Claude...')\n }\n\n // Check if Claude CLI is available\n getLogger().debug('Checking Claude CLI availability...')\n const isClaudeAvailable = await detectClaudeCli()\n if (!isClaudeAvailable) {\n getLogger().info('Claude CLI not available, skipping Claude commit message generation')\n return null\n }\n getLogger().debug('Claude CLI is available')\n\n // Build XML-based structured prompt\n getLogger().debug('Building commit message prompt...')\n const prompt = this.buildCommitMessagePrompt(issueNumber, issuePrefix, trailerType)\n getLogger().debug('Prompt built', { promptLength: prompt.length })\n\n // Debug log the actual prompt content for troubleshooting\n getLogger().debug('Claude prompt content:', {\n prompt: prompt,\n truncatedPreview: prompt.substring(0, 500) + (prompt.length > 500 ? '...[truncated]' : '')\n })\n\n try {\n const claudeStartTime = Date.now()\n\n // Debug log the Claude call parameters\n const claudeOptions = {\n headless: true,\n addDir: worktreePath,\n model: 'claude-haiku-4-5-20251001', // Fast, cost-effective model\n timeout: 120000, // 120 second timeout\n appendSystemPrompt: 'Output only the requested content. Never include preamble, analysis, or meta-commentary. Your response is used verbatim.',\n noSessionPersistence: true, // Utility operation - don't persist session\n env: { CLAUDE_CODE_SIMPLE: '1' }, // Minimal mode - no MCP, hooks, or CLAUDE.md loading\n }\n getLogger().debug('Claude CLI call parameters:', {\n options: claudeOptions,\n worktreePathForAnalysis: worktreePath,\n addDirContents: 'Will include entire worktree directory for analysis'\n })\n\n // Launch Claude in headless mode with repository access and shorter timeout for commit messages\n const result = await launchClaude(prompt, claudeOptions)\n\n const claudeDuration = Date.now() - claudeStartTime\n getLogger().debug('Claude API call completed', { duration: `${claudeDuration}ms` })\n\n if (typeof result !== 'string') {\n getLogger().warn('Claude returned non-string result', { resultType: typeof result })\n return null\n }\n\n getLogger().debug('Raw Claude output received', {\n outputLength: result.length,\n preview: result.substring(0, 200) + (result.length > 200 ? '...' : '')\n })\n\n\n // Sanitize output - remove meta-commentary and clean formatting\n getLogger().debug('Sanitizing Claude output...')\n const sanitized = this.sanitizeClaudeOutput(result)\n getLogger().debug('Output sanitized', {\n originalLength: result.length,\n sanitizedLength: sanitized.length,\n sanitized: sanitized.substring(0, 200) + (sanitized.length > 200 ? '...' : '')\n })\n\n // Ensure empty strings are rejected\n if (!sanitized) {\n getLogger().warn('Claude returned empty message after sanitization')\n return null\n }\n\n // Append trailer (e.g., \"Fixes #N\" or \"Refs #N\") if issue number provided\n let finalMessage = sanitized\n if (issueNumber) {\n const trailer = trailerType ?? 'Fixes'\n const trailerRef = `${trailer} ${issuePrefix}${issueNumber}`\n // Add trailer if not already present\n if (!finalMessage.includes(trailerRef)) {\n finalMessage = `${finalMessage}\\n\\n${trailerRef}`\n getLogger().debug(`Added \"${trailerRef}\" trailer to commit message`)\n } else {\n getLogger().debug(`\"${trailerRef}\" already present in commit message`)\n }\n }\n\n const totalDuration = Date.now() - startTime\n if (getLogger().isDebugEnabled()) {\n getLogger().debug('Claude commit message generated', {\n message: finalMessage,\n totalDuration: `${totalDuration}ms`,\n claudeApiDuration: `${claudeDuration}ms`\n })\n } else {\n getLogger().info('Commit message generated')\n }\n\n return finalMessage\n } catch (error) {\n const totalDuration = Date.now() - startTime\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\n if (errorMessage.includes('timed out') || errorMessage.includes('timeout')) {\n getLogger().warn('Claude commit message generation timed out after 45 seconds', {\n totalDuration: `${totalDuration}ms`,\n worktreePath: worktreePath.split('/').pop()\n })\n } else {\n getLogger().warn('Failed to generate commit message with Claude', {\n error: errorMessage,\n totalDuration: `${totalDuration}ms`,\n worktreePath: worktreePath.split('/').pop()\n })\n }\n return null\n }\n }\n\n /**\n * Build structured XML prompt for commit message generation\n * Uses XML format for clear task definition and output expectations\n */\n private buildCommitMessagePrompt(\n issueNumber: string | number | undefined,\n issuePrefix: string,\n trailerType?: 'Refs' | 'Fixes'\n ): string {\n const trailer = trailerType ?? 'Fixes'\n const issueContext = issueNumber\n ? `\\n<IssueContext>\nThis commit is associated with issue ${issuePrefix}${issueNumber}.\n${trailer === 'Fixes' ? 'If the changes appear to resolve the issue, include' : 'Include'} \"${trailer} ${issuePrefix}${issueNumber}\" at the end of the first line of commit message.\n</IssueContext>`\n : ''\n\n const examplePrefix = issuePrefix || '' // Use empty string for Linear examples\n return `<Task>\nYou are a software engineer writing a commit message for this repository.\nExamine the staged changes in the git repository and generate a concise, meaningful commit message.\n</Task>\n\n<Requirements>\n<Format>The first line must be a brief summary of the changes made as a full sentence. If it references an issue, include \"${trailer} ${examplePrefix}N\" at the end of this line.\n\nAdd 2 newlines, then add a bullet-point form description of the changes made, each change on a new line.</Format>\n<Mood>Use imperative mood (e.g., \"Add feature\" not \"Added feature\")</Mood>\n<Focus>Be specific about what was changed and why</Focus>\n<Conciseness>Keep message under 72 characters for subject line when possible</Conciseness>\n<NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw commit message.</NoMeta>\n<Examples>\nGood: \"Add user authentication with JWT tokens. ${trailer} ${examplePrefix}42\n\n- Implement login and registration endpoints\n- Secure routes with JWT middleware\n- Update user model to store hashed passwords\"\nGood: \"Fix navigation bug in sidebar menu.\"\nBad: \"Based on the changes, I'll create: Add user authentication\"\nBad: \"Looking at the files, this commit should be: Fix navigation bug\"\n</Examples>\n${issueContext}\n</Requirements>\n\n<Output>\nIMPORTANT: Your entire response will be used directly as the git commit message.\nDo not include any explanatory text before or after the commit message.\nStart your response immediately with the commit message text.\n</Output>`\n }\n\n /**\n * Sanitize Claude output to remove meta-commentary and clean formatting\n * Handles cases where Claude includes explanatory text despite instructions\n */\n private sanitizeClaudeOutput(rawOutput: string): string {\n let cleaned = rawOutput.trim()\n\n // Remove common meta-commentary patterns (case-insensitive)\n const metaPatterns = [\n /^.*?based on.*?changes.*?:/i,\n /^.*?looking at.*?files.*?:/i,\n /^.*?examining.*?:/i,\n /^.*?analyzing.*?:/i,\n /^.*?i'll.*?generate.*?:/i,\n /^.*?let me.*?:/i,\n /^.*?the commit message.*?should be.*?:/i,\n /^.*?here.*?is.*?commit.*?message.*?:/i,\n ]\n\n for (const pattern of metaPatterns) {\n cleaned = cleaned.replace(pattern, '').trim()\n }\n\n // Extract content after separators only if it looks like meta-commentary\n // Only split on colons if there's clear meta-commentary before it\n if (cleaned.includes(':')) {\n const colonIndex = cleaned.indexOf(':')\n const beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase()\n\n // Only split if the text before colon looks like meta-commentary\n const metaIndicators = [\n 'here is the commit message',\n 'commit message',\n 'here is',\n 'the message should be',\n 'i suggest',\n 'my suggestion'\n ]\n\n const isMetaCommentary = metaIndicators.some(indicator => beforeColon.includes(indicator))\n\n if (isMetaCommentary) {\n const afterColon = cleaned.substring(colonIndex + 1).trim()\n if (afterColon && afterColon.length > 10) {\n cleaned = afterColon\n }\n }\n }\n\n // Remove quotes if the entire message is wrapped in them\n if ((cleaned.startsWith('\"') && cleaned.endsWith('\"')) ||\n (cleaned.startsWith(\"'\") && cleaned.endsWith(\"'\"))) {\n cleaned = cleaned.slice(1, -1).trim()\n }\n\n return cleaned\n }\n}\n"],"mappings":"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","names":["execa"]}
@@ -34,7 +34,7 @@ import {
34
34
  } from "./chunk-VIQOQ463.js";
35
35
  import {
36
36
  GitWorktreeManager
37
- } from "./chunk-FV4KXBGO.js";
37
+ } from "./chunk-6RINI7OL.js";
38
38
  import {
39
39
  PromptTemplateManager,
40
40
  buildReviewTemplateVariables
@@ -1615,4 +1615,4 @@ export {
1615
1615
  WorktreeValidationError,
1616
1616
  IgniteCommand
1617
1617
  };
1618
- //# sourceMappingURL=chunk-UVXB6O24.js.map
1618
+ //# sourceMappingURL=chunk-H2M62IKR.js.map
@@ -32,7 +32,7 @@ import {
32
32
  } from "./chunk-CQHHEW2M.js";
33
33
  import {
34
34
  GitWorktreeManager
35
- } from "./chunk-FV4KXBGO.js";
35
+ } from "./chunk-6RINI7OL.js";
36
36
  import {
37
37
  ClaudeContextManager
38
38
  } from "./chunk-QF2DROQR.js";
@@ -148,7 +148,7 @@ async function launchFirstRunSetup() {
148
148
  logger.info("");
149
149
  logger.info("iloom will now launch an interactive configuration session with Claude.");
150
150
  await waitForKeypress("Press any key to start configuration...");
151
- const { InitCommand } = await import("./init-LWU2M53W.js");
151
+ const { InitCommand } = await import("./init-6FUPISD7.js");
152
152
  const initCommand = new InitCommand();
153
153
  await initCommand.execute(
154
154
  "Help me configure iloom settings for this project. This is my first time using iloom here. Note: Your iloom command will execute once we are done with configuration changes."
@@ -672,4 +672,4 @@ export {
672
672
  launchFirstRunSetup,
673
673
  StartCommand
674
674
  };
675
- //# sourceMappingURL=chunk-DY6MUWQW.js.map
675
+ //# sourceMappingURL=chunk-UMZ2CIDW.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  GitWorktreeManager
4
- } from "./chunk-FV4KXBGO.js";
4
+ } from "./chunk-6RINI7OL.js";
5
5
  import {
6
6
  logger
7
7
  } from "./chunk-VRPPI6GU.js";
@@ -299,4 +299,4 @@ Please consult your shell's documentation for setting up custom completions.
299
299
  export {
300
300
  ShellCompletion
301
301
  };
302
- //# sourceMappingURL=chunk-HIGWKLQR.js.map
302
+ //# sourceMappingURL=chunk-VZ55H5X6.js.map
@@ -30,7 +30,7 @@ import "./chunk-4232AHNQ.js";
30
30
  import "./chunk-VIQOQ463.js";
31
31
  import {
32
32
  GitWorktreeManager
33
- } from "./chunk-FV4KXBGO.js";
33
+ } from "./chunk-6RINI7OL.js";
34
34
  import "./chunk-WEBMMJKL.js";
35
35
  import "./chunk-K3QGG4O2.js";
36
36
  import "./chunk-DMSL5BAP.js";
@@ -544,4 +544,4 @@ var CleanupCommand = class {
544
544
  export {
545
545
  CleanupCommand
546
546
  };
547
- //# sourceMappingURL=cleanup-RLBLNQZN.js.map
547
+ //# sourceMappingURL=cleanup-QTZU46OP.js.map