@iloom/cli 0.5.3 → 0.5.4

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 (56) hide show
  1. package/dist/{chunk-66BMJ25W.js → chunk-6YSFTPKW.js} +8 -192
  2. package/dist/chunk-6YSFTPKW.js.map +1 -0
  3. package/dist/{chunk-XNNXAAZT.js → chunk-E4F7KASE.js} +2 -2
  4. package/dist/{chunk-HMMO2LDS.js → chunk-ESP2FF52.js} +2 -2
  5. package/dist/chunk-NKRQNER7.js +197 -0
  6. package/dist/chunk-NKRQNER7.js.map +1 -0
  7. package/dist/{chunk-Z5BM4JWB.js → chunk-NRDY6XO3.js} +4 -4
  8. package/dist/{chunk-53OMUNUN.js → chunk-TKL7RBEF.js} +7 -2
  9. package/dist/chunk-TKL7RBEF.js.map +1 -0
  10. package/dist/{chunk-YU5HVI6B.js → chunk-YPOG7WY4.js} +2 -2
  11. package/dist/{chunk-VV66DH6T.js → chunk-ZXWTOJXA.js} +26 -7
  12. package/dist/chunk-ZXWTOJXA.js.map +1 -0
  13. package/dist/{cleanup-Y5W3CNUV.js → cleanup-H5QUWBWE.js} +6 -6
  14. package/dist/cli.js +30 -30
  15. package/dist/cli.js.map +1 -1
  16. package/dist/{contribute-SMIPMWCH.js → contribute-VP73TPAL.js} +2 -2
  17. package/dist/{dev-server-HNBRWGCD.js → dev-server-H5FFXIVX.js} +4 -4
  18. package/dist/{git-OV6ADVO7.js → git-UHUNQZBA.js} +2 -2
  19. package/dist/{ignite-3HB3ZBEW.js → ignite-VPP4PMF4.js} +7 -5
  20. package/dist/{ignite-3HB3ZBEW.js.map → ignite-VPP4PMF4.js.map} +1 -1
  21. package/dist/index.js +6 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/{init-CMIRHFSR.js → init-4ZR2XXZA.js} +5 -4
  24. package/dist/{open-AXE225Z5.js → open-6HBQHPUL.js} +4 -4
  25. package/dist/{projects-GVEMCN5R.js → projects-SA76I4TZ.js} +14 -7
  26. package/dist/projects-SA76I4TZ.js.map +1 -0
  27. package/dist/prompts/issue-prompt.txt +12 -6
  28. package/dist/{rebase-6UIHMUWS.js → rebase-SRBOVC4M.js} +4 -4
  29. package/dist/{recap-XTBNMEMO.js → recap-X7FTTKPP.js} +4 -4
  30. package/dist/{run-H375EYRB.js → run-5FU76FFE.js} +4 -4
  31. package/dist/{shell-33FJCWJQ.js → shell-UQJDI36V.js} +4 -4
  32. package/dist/{summary-JUMOCNLR.js → summary-MOKN7RM2.js} +3 -3
  33. package/dist/{test-git-CO3BA4BV.js → test-git-GB3B6QNT.js} +2 -2
  34. package/dist/{test-prefix-HZYSDQYT.js → test-prefix-YQNNTCY3.js} +2 -2
  35. package/package.json +1 -1
  36. package/dist/chunk-53OMUNUN.js.map +0 -1
  37. package/dist/chunk-66BMJ25W.js.map +0 -1
  38. package/dist/chunk-VV66DH6T.js.map +0 -1
  39. package/dist/projects-GVEMCN5R.js.map +0 -1
  40. /package/dist/{chunk-XNNXAAZT.js.map → chunk-E4F7KASE.js.map} +0 -0
  41. /package/dist/{chunk-HMMO2LDS.js.map → chunk-ESP2FF52.js.map} +0 -0
  42. /package/dist/{chunk-Z5BM4JWB.js.map → chunk-NRDY6XO3.js.map} +0 -0
  43. /package/dist/{chunk-YU5HVI6B.js.map → chunk-YPOG7WY4.js.map} +0 -0
  44. /package/dist/{cleanup-Y5W3CNUV.js.map → cleanup-H5QUWBWE.js.map} +0 -0
  45. /package/dist/{contribute-SMIPMWCH.js.map → contribute-VP73TPAL.js.map} +0 -0
  46. /package/dist/{dev-server-HNBRWGCD.js.map → dev-server-H5FFXIVX.js.map} +0 -0
  47. /package/dist/{git-OV6ADVO7.js.map → git-UHUNQZBA.js.map} +0 -0
  48. /package/dist/{init-CMIRHFSR.js.map → init-4ZR2XXZA.js.map} +0 -0
  49. /package/dist/{open-AXE225Z5.js.map → open-6HBQHPUL.js.map} +0 -0
  50. /package/dist/{rebase-6UIHMUWS.js.map → rebase-SRBOVC4M.js.map} +0 -0
  51. /package/dist/{recap-XTBNMEMO.js.map → recap-X7FTTKPP.js.map} +0 -0
  52. /package/dist/{run-H375EYRB.js.map → run-5FU76FFE.js.map} +0 -0
  53. /package/dist/{shell-33FJCWJQ.js.map → shell-UQJDI36V.js.map} +0 -0
  54. /package/dist/{summary-JUMOCNLR.js.map → summary-MOKN7RM2.js.map} +0 -0
  55. /package/dist/{test-git-CO3BA4BV.js.map → test-git-GB3B6QNT.js.map} +0 -0
  56. /package/dist/{test-prefix-HZYSDQYT.js.map → test-prefix-YQNNTCY3.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/git.ts"],"sourcesContent":["import path from 'path'\nimport { execa, type ExecaError } from 'execa'\nimport { type GitWorktree } from '../types/worktree.js'\nimport { SettingsManager, type SettingsManager as SettingsManagerType } from '../lib/SettingsManager.js'\nimport { MetadataManager } from '../lib/MetadataManager.js'\nimport { logger } from './logger.js'\n\n/**\n * Execute a Git command and return the stdout result\n * Throws an error if the command fails\n */\nexport async function executeGitCommand(\n args: string[],\n options?: { cwd?: string; timeout?: number; stdio?: 'inherit' | 'pipe'; env?: NodeJS.ProcessEnv }\n): Promise<string> {\n try {\n const result = await execa('git', args, {\n cwd: options?.cwd ?? process.cwd(),\n timeout: options?.timeout ?? 30000,\n encoding: 'utf8',\n stdio: options?.stdio ?? 'pipe',\n verbose: logger.isDebugEnabled(),\n // Spread env conditionally - only include if defined\n ...(options?.env && { env: options.env }),\n })\n\n return result.stdout\n } catch (error) {\n const execaError = error as ExecaError\n const stderr = execaError.stderr ?? execaError.message ?? 'Unknown Git error'\n throw new Error(`Git command failed: ${stderr}`)\n }\n}\n\n/**\n * Parse git worktree list output into structured data\n * @param output - The output from git worktree list --porcelain\n * @param defaultBranch - Default branch name to use for bare repositories (defaults to 'main')\n */\nexport function parseWorktreeList(output: string, defaultBranch?: string): GitWorktree[] {\n const worktrees: GitWorktree[] = []\n const lines = output.trim().split('\\n')\n\n let i = 0\n while (i < lines.length) {\n const pathLine = lines[i]\n if (!pathLine?.startsWith('worktree ')) {\n i++\n continue\n }\n\n // Parse path line: \"worktree /path/to/worktree\"\n const pathMatch = pathLine.match(/^worktree (.+)$/)\n if (!pathMatch) {\n i++\n continue\n }\n\n let branch = ''\n let commit = ''\n let detached = false\n let bare = false\n let locked = false\n let lockReason: string | undefined\n\n // Process subsequent lines for this worktree\n i++\n while (i < lines.length && !lines[i]?.startsWith('worktree ')) {\n const line = lines[i]?.trim()\n if (!line) {\n i++\n continue\n }\n\n if (line === 'bare') {\n bare = true\n branch = defaultBranch ?? 'main' // Default assumption for bare repo\n } else if (line === 'detached') {\n detached = true\n branch = 'HEAD'\n } else if (line.startsWith('locked')) {\n locked = true\n const lockMatch = line.match(/^locked (.+)$/)\n lockReason = lockMatch?.[1]\n branch = branch || 'unknown'\n } else if (line.startsWith('HEAD ')) {\n // Parse commit line: \"HEAD abc123def456...\"\n const commitMatch = line.match(/^HEAD ([a-f0-9]+)/)\n if (commitMatch) {\n commit = commitMatch[1] ?? ''\n }\n } else if (line.startsWith('branch ')) {\n // Parse branch line: \"branch refs/heads/feature-branch\"\n const branchMatch = line.match(/^branch refs\\/heads\\/(.+)$/)\n branch = branchMatch?.[1] ?? line.replace('branch ', '')\n }\n\n i++\n }\n\n const worktree: GitWorktree = {\n path: pathMatch[1] ?? '',\n branch,\n commit,\n bare,\n detached,\n locked,\n }\n\n if (lockReason !== undefined) {\n worktree.lockReason = lockReason\n }\n\n worktrees.push(worktree)\n }\n\n return worktrees\n}\n\n/**\n * Check if a branch name follows PR naming patterns\n */\nexport function isPRBranch(branchName: string): boolean {\n const prPatterns = [\n /^pr\\/\\d+/i, // pr/123, pr/123-feature-name\n /^pull\\/\\d+/i, // pull/123\n /^\\d+[-_]/, // 123-feature-name, 123_feature_name\n /^feature\\/pr[-_]?\\d+/i, // feature/pr123, feature/pr-123\n /^hotfix\\/pr[-_]?\\d+/i, // hotfix/pr123\n ]\n\n return prPatterns.some(pattern => pattern.test(branchName))\n}\n\n/**\n * Extract PR number from branch name\n */\nexport function extractPRNumber(branchName: string): number | null {\n const patterns = [\n /^pr\\/(\\d+)/i, // pr/123\n /^pull\\/(\\d+)/i, // pull/123\n /^(\\d+)[-_]/, // 123-feature-name\n /^feature\\/pr[-_]?(\\d+)/i, // feature/pr123\n /^hotfix\\/pr[-_]?(\\d+)/i, // hotfix/pr123\n /pr[-_]?(\\d+)/i, // anywhere with pr123 or pr-123\n ]\n\n for (const pattern of patterns) {\n const match = branchName.match(pattern)\n if (match?.[1]) {\n const num = parseInt(match[1], 10)\n if (!isNaN(num)) return num\n }\n }\n\n return null\n}\n\n/**\n * Extract issue number from branch name\n * Supports both new format (issue-{issueId}__{slug}) and old format (issue-{number}-{slug})\n * @returns string issue ID (alphanumeric) or null if not found\n */\nexport function extractIssueNumber(branchName: string): string | null {\n // Priority 1: New format - issue-{issueId}__ (alphanumeric ID with double underscore)\n const newFormatPattern = /issue-([^_]+)__/i\n const newMatch = branchName.match(newFormatPattern)\n if (newMatch?.[1]) return newMatch[1]\n\n // Priority 2: Old format - issue-{number}- or issue-{number}$ (numeric only, dash or end)\n const oldFormatPattern = /issue-(\\d+)(?:-|$)/i\n const oldMatch = branchName.match(oldFormatPattern)\n if (oldMatch?.[1]) return oldMatch[1]\n\n // Priority 3: Alphanumeric ID at end (either format without description)\n const alphanumericEndPattern = /issue-([^_\\s/]+)$/i\n const alphanumericMatch = branchName.match(alphanumericEndPattern)\n if (alphanumericMatch?.[1]) return alphanumericMatch[1]\n\n // Priority 4: Legacy patterns (issue_N, leading number)\n const legacyPatterns = [\n /issue_(\\d+)/i, // issue_42\n /^(\\d+)-/, // 42-feature-name\n ]\n for (const pattern of legacyPatterns) {\n const match = branchName.match(pattern)\n if (match?.[1]) return match[1]\n }\n\n return null\n}\n\n/**\n * Check if a path follows worktree naming patterns\n */\nexport function isWorktreePath(path: string): boolean {\n const worktreePatterns = [\n /\\/worktrees?\\//i, // Contains /worktree/ or /worktrees/\n /\\/workspace[-_]?\\d+/i, // workspace123, workspace-123\n /\\/issue[-_]?\\d+/i, // issue123, issue-123\n /\\/pr[-_]?\\d+/i, // pr123, pr-123\n /-worktree$/i, // ends with -worktree\n /\\.worktree$/i, // ends with .worktree\n ]\n\n return worktreePatterns.some(pattern => pattern.test(path))\n}\n\n/**\n * Generate a worktree path based on branch name and root directory\n * For PRs, adds _pr_<PR_NUM> suffix to distinguish from issue branches\n */\nexport function generateWorktreePath(\n branchName: string,\n rootDir: string = process.cwd(),\n options?: { isPR?: boolean; prNumber?: number; prefix?: string }\n): string {\n // Replace slashes with dashes (matches bash line 593)\n let sanitized = branchName.replace(/\\//g, '-')\n\n // Add PR suffix if this is a PR (matches bash lines 595-597)\n if (options?.isPR && options?.prNumber) {\n sanitized = `${sanitized}_pr_${options.prNumber}`\n }\n\n const parentDir = path.dirname(rootDir)\n\n // Handle prefix logic\n let prefix: string\n\n if (options?.prefix === undefined) {\n // No prefix in options - calculate default: <basename>-looms\n const mainFolderName = path.basename(rootDir)\n prefix = mainFolderName ? `${mainFolderName}-looms/` : 'looms/'\n } else if (options.prefix === '') {\n // Empty string = no prefix mode\n prefix = ''\n } else {\n // Custom prefix provided\n prefix = options.prefix\n\n // Check if prefix contains forward slashes (nested directory structure)\n const hasNestedPath = prefix.includes('/')\n\n if (hasNestedPath) {\n // Check if it ends with a separator character (dash, underscore, or slash)\n const endsWithSeparator = /[-_/]$/.test(prefix)\n\n if (!endsWithSeparator) {\n // Has nested path but no trailing separator: auto-append hyphen\n // Example: \"temp/looms\" becomes \"temp/looms-\"\n prefix = `${prefix}-`\n }\n // If it already ends with -, _, or /, keep as-is\n } else {\n // Single-level prefix: auto-append separator if it doesn't end with one\n const endsWithSeparator = /[-_]$/.test(prefix)\n if (!endsWithSeparator) {\n prefix = `${prefix}-`\n }\n }\n }\n\n // Apply prefix (or not, if empty)\n if (prefix === '') {\n return path.join(parentDir, sanitized)\n } else if (prefix.endsWith('/')) {\n // Forward slash = nested directory, use path.join for proper handling\n return path.join(parentDir, prefix, sanitized)\n } else if (prefix.includes('/')) {\n // Contains slash but doesn't end with slash = nested with separator (e.g., \"looms/myprefix-\")\n // Split and handle: last part is prefix with separator, rest is directory path\n const lastSlashIndex = prefix.lastIndexOf('/')\n const dirPath = prefix.substring(0, lastSlashIndex)\n const prefixWithSeparator = prefix.substring(lastSlashIndex + 1)\n return path.join(parentDir, dirPath, `${prefixWithSeparator}${sanitized}`)\n } else {\n // Dash/underscore separator = single directory name\n return path.join(parentDir, `${prefix}${sanitized}`)\n }\n}\n\n/**\n * Validate that a directory is a valid Git repository\n */\nexport async function isValidGitRepo(path: string): Promise<boolean> {\n try {\n await executeGitCommand(['rev-parse', '--git-dir'], { cwd: path })\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Get the current branch name for a repository\n */\nexport async function getCurrentBranch(path: string = process.cwd()): Promise<string | null> {\n try {\n const result = await executeGitCommand(['branch', '--show-current'], { cwd: path })\n return result.trim()\n } catch {\n return null\n }\n}\n\n/**\n * Check if a branch exists (local or remote)\n */\nexport async function branchExists(\n branchName: string,\n path: string = process.cwd(),\n includeRemote = true\n): Promise<boolean> {\n try {\n // Check local branches\n const localResult = await executeGitCommand(['branch', '--list', branchName], { cwd: path })\n if (localResult.trim()) {\n return true\n }\n\n // Check remote branches if requested\n if (includeRemote) {\n const remoteResult = await executeGitCommand(['branch', '-r', '--list', `*/${branchName}`], {\n cwd: path,\n })\n if (remoteResult.trim()) {\n return true\n }\n }\n\n return false\n } catch {\n return false\n }\n}\n\n/**\n * Get the root directory of the current worktree\n * Returns the worktree root when in a linked worktree, or main repo root when in main worktree\n */\nexport async function getWorktreeRoot(path: string = process.cwd()): Promise<string | null> {\n try {\n const result = await executeGitCommand(['rev-parse', '--show-toplevel'], { cwd: path })\n return result.trim()\n } catch {\n return null\n }\n}\n\n/**\n * Get the main repository root directory\n * Returns the main repo root even when called from a linked worktree\n */\nexport async function getRepoRoot(path: string = process.cwd()): Promise<string | null> {\n try {\n // Get the common git directory (shared by all worktrees)\n const gitCommonDir = await executeGitCommand(\n ['rev-parse', '--path-format=absolute', '--git-common-dir'],\n { cwd: path }\n )\n const trimmedPath = gitCommonDir.trim()\n\n // Handle linked worktree: /path/to/repo/.git/worktrees/worktree-name -> /path/to/repo\n // Handle main worktree: /path/to/repo/.git -> /path/to/repo\n const repoRoot = trimmedPath\n .replace(/\\/\\.git\\/worktrees\\/[^/]+$/, '') // Remove /.git/worktrees/name suffix\n .replace(/\\/\\.git$/, '') // Remove /.git suffix\n\n return repoRoot\n } catch(error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n // \"not a git repository\" is expected when running outside a git repo - use debug level\n if (errorMessage.includes('not a git repository')) {\n logger.info(`Note: No git repository detected: ${path}`)\n } else {\n logger.warn(`Failed to determine repo root from git-common-dir: ${path}`, errorMessage)\n }\n return null\n }\n}\n\n/**\n * Find the worktree path where main branch is checked out\n * Copies bash script approach: parse git worktree list to find main\n */\nexport async function findMainWorktreePath(\n path: string = process.cwd(),\n options?: { mainBranch?: string }\n): Promise<string> {\n try {\n const output = await executeGitCommand(['worktree', 'list', '--porcelain'], { cwd: path })\n const worktrees = parseWorktreeList(output, options?.mainBranch)\n\n // Guard: empty worktree list\n if (worktrees.length === 0) {\n throw new Error('No worktrees found in repository')\n }\n\n // Tier 1: Check for specified mainBranch in options\n if (options?.mainBranch) {\n const specified = worktrees.find(wt => wt.branch === options.mainBranch)\n if (!specified?.path) {\n throw new Error(\n `No worktree found with branch '${options.mainBranch}' (specified in settings). Available worktrees: ${worktrees.map(wt => `${wt.path} (${wt.branch})`).join(', ')}`\n )\n }\n return specified.path\n }\n\n // Tier 2: Look for \"main\" branch\n const mainBranch = worktrees.find(wt => wt.branch === 'main')\n if (mainBranch?.path) {\n return mainBranch.path\n }\n\n // Tier 3: Use first worktree (primary worktree)\n const firstWorktree = worktrees[0]\n if (!firstWorktree?.path) {\n throw new Error('Failed to determine primary worktree path')\n }\n return firstWorktree.path\n } catch (error) {\n if (\n error instanceof Error &&\n (error.message.includes('No worktree found with branch') ||\n error.message.includes('No worktrees found') ||\n error.message.includes('Failed to determine primary worktree'))\n ) {\n // Re-throw our specific errors\n throw error\n }\n throw new Error(`Failed to find main worktree: ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n\n/**\n * Find main worktree path with automatic settings loading\n *\n * This is a convenience wrapper that:\n * 1. Loads project settings from .iloom/settings.json\n * 2. Extracts mainBranch configuration if present\n * 3. Calls findMainWorktreePath with appropriate options\n *\n * @param path - Path to search from (defaults to process.cwd())\n * @param settingsManager - Optional SettingsManager instance (for DI/testing)\n * @returns Path to main worktree\n * @throws Error if main worktree cannot be found\n */\nexport async function findMainWorktreePathWithSettings(\n path?: string,\n settingsManager?: SettingsManagerType\n): Promise<string> {\n // Lazy load SettingsManager to avoid circular dependencies\n settingsManager ??= new SettingsManager()\n\n const settings = await settingsManager.loadSettings(path)\n const findOptions = settings.mainBranch ? { mainBranch: settings.mainBranch } : undefined\n return findMainWorktreePath(path, findOptions)\n}\n\n/**\n * Find the worktree path where a specific branch is checked out\n *\n * Used by MergeManager to find the correct worktree for child loom merges.\n * When finishing a child loom, we need to find where the PARENT branch is\n * checked out (the merge target), not where settings.mainBranch is checked out.\n *\n * @param branchName - The branch name to find\n * @param path - Path to search from (defaults to process.cwd())\n * @returns Path to worktree where the branch is checked out\n * @throws Error if no worktree has the specified branch checked out\n */\nexport async function findWorktreeForBranch(\n branchName: string,\n path: string = process.cwd()\n): Promise<string> {\n try {\n const output = await executeGitCommand(['worktree', 'list', '--porcelain'], { cwd: path })\n const worktrees = parseWorktreeList(output, branchName)\n\n // Guard: empty worktree list\n if (worktrees.length === 0) {\n throw new Error('No worktrees found in repository')\n }\n\n // Find the worktree with the specified branch\n const targetWorktree = worktrees.find(wt => wt.branch === branchName)\n if (!targetWorktree?.path) {\n throw new Error(\n `No worktree found with branch '${branchName}' checked out. ` +\n `Available worktrees: ${worktrees.map(wt => `${wt.path} (${wt.branch})`).join(', ')}`\n )\n }\n return targetWorktree.path\n } catch (error) {\n if (\n error instanceof Error &&\n (error.message.includes('No worktree found with branch') ||\n error.message.includes('No worktrees found'))\n ) {\n // Re-throw our specific errors\n throw error\n }\n throw new Error(`Failed to find worktree for branch '${branchName}': ${error instanceof Error ? error.message : String(error)}`)\n }\n}\n\n/**\n * Check if there are uncommitted changes in a repository\n */\nexport async function hasUncommittedChanges(path: string = process.cwd()): Promise<boolean> {\n try {\n const result = await executeGitCommand(['status', '--porcelain'], { cwd: path })\n return result.trim().length > 0\n } catch {\n return false\n }\n}\n\n/**\n * Get the default branch name for a repository\n */\nexport async function getDefaultBranch(path: string = process.cwd()): Promise<string> {\n try {\n // Try to get from remote\n const remoteResult = await executeGitCommand(['symbolic-ref', 'refs/remotes/origin/HEAD'], {\n cwd: path,\n })\n const match = remoteResult.match(/refs\\/remotes\\/origin\\/(.+)/)\n if (match) return match[1] ?? 'main'\n\n // Fallback to common default branch names\n const commonDefaults = ['main', 'master', 'develop']\n for (const branch of commonDefaults) {\n if (await branchExists(branch, path)) {\n return branch\n }\n }\n\n return 'main' // Final fallback\n } catch {\n return 'main'\n }\n}\n\n/**\n * Find all branches related to a GitHub issue or PR number\n * Matches patterns like:\n * - Issue patterns: issue-25, issue/25, 25-feature, feat-25, feat/issue-25\n * - PR patterns: pr/25, pull/25, pr-25, feature/pr-25\n *\n * Based on bash cleanup-worktree.sh find_issue_branches() (lines 133-154)\n *\n * @param issueNumber - The issue or PR number to search for\n * @param path - Working directory to search from (defaults to process.cwd())\n * @param settingsManager - Optional SettingsManager instance (for DI/testing)\n */\nexport async function findAllBranchesForIssue(\n issueNumber: string | number,\n path: string = process.cwd(),\n settingsManager?: SettingsManagerType\n): Promise<string[]> {\n // Lazy load SettingsManager to avoid circular dependencies\n if (!settingsManager) {\n const { SettingsManager: SM } = await import('../lib/SettingsManager.js')\n settingsManager = new SM()\n }\n\n // Get protected branches list from centralized method\n const protectedBranches = await settingsManager.getProtectedBranches(path)\n\n // Get all branches (local and remote)\n const output = await executeGitCommand(['branch', '-a'], { cwd: path })\n\n const branches: string[] = []\n const lines = output.split('\\n').filter(Boolean)\n\n for (const line of lines) {\n // Skip remotes/origin/HEAD pointer\n if (line.includes('remotes/origin/HEAD')) {\n continue\n }\n\n // Clean the branch name:\n // 1. Remove git status markers (* + spaces at start)\n let cleanBranch = line.replace(/^[*+ ]+/, '')\n\n // 2. Remove 'origin/' prefix if present\n cleanBranch = cleanBranch.replace(/^origin\\//, '')\n\n // 3. Remove 'remotes/origin/' prefix if present\n cleanBranch = cleanBranch.replace(/^remotes\\/origin\\//, '')\n\n // 4. Trim any remaining whitespace\n cleanBranch = cleanBranch.trim()\n\n // Skip protected branches\n if (protectedBranches.includes(cleanBranch)) {\n continue\n }\n\n // Check if branch contains issue number with strict word boundary pattern\n // The issue number must NOT be:\n // - Part of a larger number (preceded or followed by a digit)\n // - After an unknown word (like \"tissue-25\")\n // The issue number CAN be:\n // - At start: \"25-feature\"\n // - After known prefix + separator: \"issue-25\", \"feat-25\", \"fix-25\", \"pr-25\"\n // - After just a separator with no prefix: test_25 (separator at start)\n\n // First check: not part of a larger number\n const notPartOfNumber = new RegExp(`(?<!\\\\d)${issueNumber}(?!\\\\d)`)\n if (!notPartOfNumber.test(cleanBranch)) {\n continue\n }\n\n // Second check: if preceded by letters, validate they're known issue-related prefixes\n // This prevents \"tissue-25\" but allows \"issue-25\", \"feat-25\", etc.\n const beforeNumber = cleanBranch.substring(0, cleanBranch.indexOf(String(issueNumber)))\n\n if (beforeNumber) {\n // Extract the last word (letters) before the number\n const lastWord = beforeNumber.match(/([a-zA-Z]+)[-_/\\s]*$/)\n if (lastWord?.[1]) {\n const word = lastWord[1].toLowerCase()\n // Known prefixes for issue-related branches\n const knownPrefixes = [\n 'issue', 'issues',\n 'feat', 'feature', 'features',\n 'fix', 'fixes', 'bugfix', 'hotfix',\n 'pr', 'pull',\n 'test', 'tests',\n 'chore',\n 'docs',\n 'refactor',\n 'perf',\n 'style',\n 'ci',\n 'build',\n 'revert'\n ]\n\n // If we found a word and it's NOT in the known list, skip this branch\n if (!knownPrefixes.includes(word)) {\n continue\n }\n }\n }\n\n // Passed all checks - add to results\n if (!branches.includes(cleanBranch)) {\n branches.push(cleanBranch)\n }\n }\n\n return branches\n}\n\n/**\n * Check if a repository is empty (has no commits yet)\n * @param path - Repository path to check (defaults to process.cwd())\n * @returns true if repository has no commits, false otherwise\n */\nexport async function isEmptyRepository(path: string = process.cwd()): Promise<boolean> {\n try {\n await executeGitCommand(['rev-parse', '--verify', 'HEAD'], { cwd: path })\n return false // HEAD exists, repo has commits\n } catch {\n return true // HEAD doesn't exist, repo is empty\n }\n}\n\n/**\n * Ensure repository has at least one commit\n * Creates an initial empty commit if repository is empty\n * @param path - Repository path (defaults to process.cwd())\n */\nexport async function ensureRepositoryHasCommits(path: string = process.cwd()): Promise<void> {\n const isEmpty = await isEmptyRepository(path)\n if (isEmpty) {\n await executeGitCommand(['commit', '--no-verify', '--allow-empty', '-m', 'Initial commit'], { cwd: path })\n }\n}\n\n/**\n * Push a branch to remote repository\n * Used for PR workflow to push changes to remote without merging locally\n *\n * @param branchName - The branch name to push\n * @param worktreePath - The worktree path where the branch is checked out\n * @param options - Push options\n * @throws Error if push fails\n */\nexport async function pushBranchToRemote(\n branchName: string,\n worktreePath: string,\n options?: { dryRun?: boolean }\n): Promise<void> {\n if (options?.dryRun) {\n // In dry-run mode, just log what would be done\n return\n }\n\n try {\n // Execute: git push origin <branch-name>\n // This matches the bash script behavior (merge-and-clean.sh line 359)\n await executeGitCommand(['push', 'origin', branchName], {\n cwd: worktreePath,\n timeout: 120000, // 120 second timeout for push operations\n })\n } catch (error) {\n // Provide helpful error message based on common push failures\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n // Check for common error patterns and provide context, but ALWAYS include original error\n if (errorMessage.includes('failed to push') || errorMessage.includes('rejected')) {\n throw new Error(\n `Failed to push changes to origin/${branchName}\\n\\n` +\n ` Git error: ${errorMessage}\\n\\n` +\n ` Possible causes:\\n` +\n ` • Remote branch was deleted\\n` +\n ` • Push was rejected (non-fast-forward)\\n` +\n ` • Network connectivity issues\\n\\n` +\n ` To retry: il finish --pr <number>\\n` +\n ` To force push: git push origin ${branchName} --force`\n )\n }\n\n if (errorMessage.includes('Could not resolve host') || errorMessage.includes('network')) {\n throw new Error(\n `Failed to push changes to origin/${branchName}: Network connectivity issues\\n\\n` +\n ` Git error: ${errorMessage}\\n\\n` +\n ` Check your internet connection and try again.`\n )\n }\n\n if (errorMessage.includes('No such remote')) {\n throw new Error(\n `Failed to push changes: Remote 'origin' not found\\n\\n` +\n ` Git error: ${errorMessage}\\n\\n` +\n ` Configure remote: git remote add origin <url>`\n )\n }\n\n // For other errors, re-throw with original message\n throw new Error(`Failed to push to remote: ${errorMessage}`)\n }\n}\n\n/**\n * Check if a file is tracked by git\n * Uses git ls-files to check if file is in the index\n * @param filePath - Absolute or relative path to the file\n * @param cwd - Working directory (defaults to process.cwd())\n * @returns true if file is tracked, false otherwise\n */\nexport async function isFileTrackedByGit(\n filePath: string,\n cwd: string = process.cwd()\n): Promise<boolean> {\n try {\n const result = await executeGitCommand(\n ['ls-files', '--error-unmatch', filePath],\n { cwd }\n )\n return result.trim().length > 0\n } catch (error) {\n // Only return false if it's the specific \"pathspec did not match\" error\n const errorMessage = error instanceof Error ? error.message : String(error)\n if (errorMessage.includes('pathspec') && errorMessage.includes('did not match')) {\n return false\n }\n // Re-throw other errors\n throw error\n }\n}\n\n/**\n * Check if a file is gitignored\n * Uses `git check-ignore` which handles nested gitignore files and global patterns\n *\n * @param filePath - Path to file to check (relative to repo root)\n * @param cwd - Working directory (defaults to process.cwd())\n * @returns true if file IS ignored, false if NOT ignored or on error\n */\nexport async function isFileGitignored(\n filePath: string,\n cwd: string = process.cwd()\n): Promise<boolean> {\n try {\n await executeGitCommand(['check-ignore', '-q', filePath], { cwd })\n return true // Exit 0 = file IS ignored\n } catch {\n return false // Exit 1 = NOT ignored (or error)\n }\n}\n\n/**\n * Check if a branch is merged into the main branch\n *\n * Uses `git merge-base --is-ancestor` which is more reliable than `git branch -d`'s check.\n * The `-d` flag checks against current HEAD, which can give false positives when:\n * - Running from a worktree where main isn't checked out\n * - Squash or rebase merges were used\n *\n * This function explicitly checks if the branch tip is an ancestor of the main branch,\n * providing consistent results regardless of which worktree the command runs from.\n *\n * @param branchName - The branch to check\n * @param mainBranch - The main branch to check against (defaults to 'main')\n * @param cwd - Working directory (defaults to process.cwd())\n * @returns true if branch is merged into main, false otherwise\n */\nexport async function isBranchMergedIntoMain(\n branchName: string,\n mainBranch: string = 'main',\n cwd: string = process.cwd()\n): Promise<boolean> {\n try {\n // git merge-base --is-ancestor exits 0 if branchName is ancestor of mainBranch, 1 if not\n await executeGitCommand(['merge-base', '--is-ancestor', branchName, mainBranch], { cwd })\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Check if a branch exists on the remote (origin) and is up-to-date with local\n * Useful for GitHub-PR workflows to ensure branch has been pushed and is current\n *\n * @param branchName - Name of the branch to check\n * @param cwd - Working directory to run git command in\n * @returns Promise<boolean> - true if remote branch exists and matches local HEAD, false otherwise\n */\nexport async function isRemoteBranchUpToDate(\n branchName: string,\n cwd: string\n): Promise<boolean> {\n try {\n // First, check if remote branch exists and get its commit hash\n const remoteResult = await executeGitCommand(['ls-remote', '--heads', 'origin', branchName], { cwd })\n\n if (remoteResult.trim().length === 0) {\n // Remote branch doesn't exist\n return false\n }\n\n // Extract the commit hash from ls-remote output (format: \"hash\\trefs/heads/branchname\")\n const remoteCommit = remoteResult.trim().split('\\t')[0]\n\n // Get the local branch's HEAD commit\n const localCommit = await executeGitCommand(['rev-parse', branchName], { cwd })\n\n // Both must exist and match\n return localCommit.trim() === remoteCommit\n } catch {\n return false\n }\n}\n\n/**\n * Result of checking remote branch status for safety validation\n */\nexport interface RemoteBranchStatus {\n /** Whether the remote branch exists */\n exists: boolean\n /** Whether the remote is ahead of local (has commits not present locally) */\n remoteAhead: boolean\n /** Whether local is ahead of remote (has unpushed commits) */\n localAhead: boolean\n /** Whether a network error occurred during the check */\n networkError: boolean\n /** Error message if network error occurred */\n errorMessage?: string\n}\n\n/**\n * Check the status of a remote branch for safety validation during cleanup\n * This function provides detailed status needed for the 5-point safety check:\n *\n * The key insight: we care about DATA LOSS, not about remote state\n * - Remote ahead of local is SAFE (commits exist on remote, no data loss)\n * - Local ahead of remote is DANGEROUS (unpushed commits would be lost)\n *\n * 5-point safety logic:\n * 1. Network error -> BLOCK (can't verify safety)\n * 2. Remote ahead of local -> OK (no data loss - commits exist on remote)\n * 3. Local ahead of remote (unpushed commits) -> BLOCK (data loss risk)\n * 4. No remote, merged to main -> OK (work is in main)\n * 5. No remote, NOT merged to main -> BLOCK (unmerged work would be lost)\n *\n * @param branchName - Name of the branch to check\n * @param cwd - Working directory to run git command in\n * @returns Promise<RemoteBranchStatus> - Detailed status of the remote branch\n */\nexport async function checkRemoteBranchStatus(\n branchName: string,\n cwd: string\n): Promise<RemoteBranchStatus> {\n try {\n // First, fetch to ensure we have the latest remote refs\n // This is important to accurately detect if remote is ahead\n try {\n await executeGitCommand(['fetch', 'origin', branchName], { cwd, timeout: 30000 })\n } catch (fetchError) {\n // Fetch failing for a specific branch is OK - branch might not exist on remote\n // We'll detect this in the ls-remote call\n const fetchErrorMessage = fetchError instanceof Error ? fetchError.message : String(fetchError)\n\n // Check if this is a network error vs branch not found\n if (fetchErrorMessage.includes('Could not resolve host') ||\n fetchErrorMessage.includes('unable to access') ||\n fetchErrorMessage.includes('network') ||\n fetchErrorMessage.includes('Connection refused') ||\n fetchErrorMessage.includes('Connection timed out')) {\n return {\n exists: false,\n remoteAhead: false,\n localAhead: false,\n networkError: true,\n errorMessage: fetchErrorMessage\n }\n }\n // Otherwise continue - branch might just not exist on remote\n }\n\n // Check if remote branch exists using ls-remote\n const remoteResult = await executeGitCommand(['ls-remote', '--heads', 'origin', branchName], { cwd })\n\n if (remoteResult.trim().length === 0) {\n // Remote branch doesn't exist\n return {\n exists: false,\n remoteAhead: false,\n localAhead: false,\n networkError: false\n }\n }\n\n // Remote branch exists - check if it's ahead of local\n // Extract the remote commit hash\n const remoteCommit = remoteResult.trim().split('\\t')[0]\n\n // Guard against undefined (shouldn't happen but TypeScript wants it)\n if (!remoteCommit) {\n return {\n exists: false,\n remoteAhead: false,\n localAhead: false,\n networkError: false\n }\n }\n\n // Get the local branch's HEAD commit\n const localCommit = await executeGitCommand(['rev-parse', branchName], { cwd })\n const localCommitTrimmed = localCommit.trim()\n\n if (remoteCommit === localCommitTrimmed) {\n // Remote and local are at the same commit - safe (no unpushed commits)\n return {\n exists: true,\n remoteAhead: false,\n localAhead: false,\n networkError: false\n }\n }\n\n // Commits differ - check if remote is ahead of local\n // Use merge-base to find common ancestor, then compare\n try {\n // Check if localCommit is an ancestor of remoteCommit (meaning remote is ahead)\n await executeGitCommand(['merge-base', '--is-ancestor', localCommitTrimmed, remoteCommit], { cwd })\n // If we get here, local IS an ancestor of remote, meaning remote is ahead\n // This is SAFE - no data loss because commits exist on remote\n return {\n exists: true,\n remoteAhead: true,\n localAhead: false,\n networkError: false\n }\n } catch {\n // Local is NOT an ancestor of remote\n // This means local is ahead or branches have diverged\n // Either way, local has unpushed commits - this is DANGEROUS (data loss risk)\n return {\n exists: true,\n remoteAhead: false,\n localAhead: true,\n networkError: false\n }\n }\n } catch (error) {\n // Check if this is a network error\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n if (errorMessage.includes('Could not resolve host') ||\n errorMessage.includes('unable to access') ||\n errorMessage.includes('network') ||\n errorMessage.includes('Connection refused') ||\n errorMessage.includes('Connection timed out')) {\n return {\n exists: false,\n remoteAhead: false,\n localAhead: false,\n networkError: true,\n errorMessage\n }\n }\n\n // For other errors, assume remote doesn't exist\n return {\n exists: false,\n remoteAhead: false,\n localAhead: false,\n networkError: false\n }\n }\n}\n\n/**\n * Get the merge target branch for a loom\n * Priority: parent loom metadata (parentLoom.branchName) > configured main branch > 'main'\n *\n * This is the shared utility for determining where a branch should merge to.\n * Child looms merge to their parent branch, standalone looms merge to main.\n *\n * @param worktreePath - Path to load metadata/settings from (defaults to process.cwd())\n * @param options - Optional dependency injection for testing\n * @returns The branch name to merge into\n */\nexport async function getMergeTargetBranch(\n worktreePath: string = process.cwd(),\n options?: {\n settingsManager?: SettingsManagerType\n metadataManager?: MetadataManager\n }\n): Promise<string> {\n const settingsManager = options?.settingsManager ?? new SettingsManager()\n const metadataManager = options?.metadataManager ?? new MetadataManager()\n\n // Check for parent loom metadata first (child looms merge to parent)\n logger.debug(`Checking for parent loom metadata at: ${worktreePath}`)\n const metadata = await metadataManager.readMetadata(worktreePath)\n if (metadata?.parentLoom?.branchName) {\n logger.debug(`Using parent branch as merge target: ${metadata.parentLoom.branchName}`)\n return metadata.parentLoom.branchName\n }\n logger.debug('No parent loom metadata found, falling back to settings')\n\n // Fall back to configured main branch\n const settings = await settingsManager.loadSettings(worktreePath)\n const mainBranch = settings.mainBranch ?? 'main'\n logger.debug(`Using configured main branch as merge target: ${mainBranch}`)\n return mainBranch\n}\n\n/**\n * Placeholder commit prefix used by github-draft-pr mode.\n * Created during il start to enable draft PR creation (GitHub requires at least one commit ahead of base).\n * Removed during il finish before the final push to maintain clean commit history.\n */\nexport const PLACEHOLDER_COMMIT_PREFIX = '[iloom-temp]'\n\n/**\n * Check if HEAD commit is a placeholder commit\n * @param cwd - Working directory (defaults to process.cwd())\n * @returns true if HEAD is a placeholder commit\n */\nexport async function isPlaceholderCommit(cwd: string = process.cwd()): Promise<boolean> {\n try {\n const subject = await executeGitCommand(['log', '-1', '--format=%s', 'HEAD'], { cwd })\n return subject.trim().startsWith(PLACEHOLDER_COMMIT_PREFIX)\n } catch {\n // No HEAD (empty repo) or other error - not a placeholder\n return false\n }\n}\n\n/**\n * Find placeholder commit SHA in history using git log --grep\n * @param worktreePath - Working directory\n * @returns SHA of placeholder commit if found, null otherwise\n */\nexport async function findPlaceholderCommitSha(worktreePath: string): Promise<string | null> {\n try {\n // Search commit history for placeholder prefix\n // Use --fixed-strings to treat the pattern literally (brackets are regex special chars)\n const log = await executeGitCommand(\n ['log', '--format=%H', '--fixed-strings', '--grep', PLACEHOLDER_COMMIT_PREFIX, '-n', '1'],\n { cwd: worktreePath }\n )\n const sha = log.trim()\n if (sha.length === 0) {\n return null\n }\n\n // Verify the found commit actually has the placeholder prefix in its subject\n // This guards against git grep matching in commit body instead of subject\n const subject = await executeGitCommand(\n ['log', '-1', '--format=%s', sha],\n { cwd: worktreePath }\n )\n if (!subject.trim().startsWith(PLACEHOLDER_COMMIT_PREFIX)) {\n return null\n }\n\n return sha\n } catch {\n return null\n }\n}\n\n/**\n * Remove placeholder commit when it's HEAD\n * Uses soft reset to preserve any staged changes\n * @param worktreePath - Working directory\n * @returns true if placeholder was removed\n */\nexport async function removePlaceholderCommitFromHead(worktreePath: string): Promise<boolean> {\n if (!await isPlaceholderCommit(worktreePath)) {\n return false\n }\n await executeGitCommand(['reset', '--soft', 'HEAD~1'], { cwd: worktreePath })\n return true\n}\n\n/**\n * Remove placeholder commit from history using rebase\n * Used when user has made commits on top of placeholder\n * @param worktreePath - Working directory\n * @param placeholderSha - SHA of the placeholder commit to remove\n * @throws Error if rebase fails\n */\nexport async function removePlaceholderCommitFromHistory(\n worktreePath: string,\n placeholderSha: string\n): Promise<void> {\n // Get parent of placeholder commit\n const parentSha = await executeGitCommand(\n ['rev-parse', `${placeholderSha}^`],\n { cwd: worktreePath }\n )\n\n // Rebase to drop the placeholder: rebase --onto parent^ placeholder\n await executeGitCommand(\n ['rebase', '--onto', parentSha.trim(), placeholderSha],\n { cwd: worktreePath }\n )\n}\n"],"mappings":"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","names":["path"]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  extractIssueNumber,
4
4
  extractPRNumber
5
- } from "./chunk-53OMUNUN.js";
5
+ } from "./chunk-TKL7RBEF.js";
6
6
 
7
7
  // src/utils/IdentifierParser.ts
8
8
  var IdentifierParser = class {
@@ -85,4 +85,4 @@ var IdentifierParser = class {
85
85
  export {
86
86
  IdentifierParser
87
87
  };
88
- //# sourceMappingURL=chunk-YU5HVI6B.js.map
88
+ //# sourceMappingURL=chunk-YPOG7WY4.js.map
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ FirstRunManager
4
+ } from "./chunk-NKRQNER7.js";
2
5
  import {
3
6
  SettingsMigrationManager
4
7
  } from "./chunk-F2PWIRV4.js";
5
8
  import {
6
9
  GitWorktreeManager
7
- } from "./chunk-HMMO2LDS.js";
10
+ } from "./chunk-ESP2FF52.js";
8
11
  import {
9
12
  parseGitRemotes
10
13
  } from "./chunk-FXDYIV3K.js";
@@ -12,8 +15,9 @@ import {
12
15
  PromptTemplateManager
13
16
  } from "./chunk-K5G5SFWY.js";
14
17
  import {
18
+ getRepoRoot,
15
19
  isFileGitignored
16
- } from "./chunk-53OMUNUN.js";
20
+ } from "./chunk-TKL7RBEF.js";
17
21
  import {
18
22
  detectClaudeCli,
19
23
  launchClaude
@@ -338,7 +342,20 @@ var InitCommand = class {
338
342
  logger.info(chalk.bold("Welcome to iloom setup"));
339
343
  logger.info(chalk.bold("Verifying current setup..."));
340
344
  await this.setupProjectConfiguration();
341
- await this.launchGuidedInit(customInitialMessage);
345
+ const guidedInitSucceeded = await this.launchGuidedInit(customInitialMessage);
346
+ if (guidedInitSucceeded) {
347
+ const projectRoot = await getRepoRoot() ?? process.cwd();
348
+ const firstRunManager = new FirstRunManager();
349
+ const alreadyConfigured = await firstRunManager.isProjectConfigured(projectRoot);
350
+ if (!alreadyConfigured) {
351
+ await firstRunManager.markProjectAsConfigured(projectRoot);
352
+ logger.debug("Project marked as configured", { projectRoot });
353
+ } else {
354
+ logger.debug("Project already marked as configured, skipping", { projectRoot });
355
+ }
356
+ } else {
357
+ logger.debug("Skipping project marker - guided init did not complete successfully");
358
+ }
342
359
  logger.info(chalk.green("Setup complete! Enjoy using iloom CLI."));
343
360
  } catch (error) {
344
361
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -417,6 +434,7 @@ var InitCommand = class {
417
434
  /**
418
435
  * Launch interactive Claude-guided configuration
419
436
  * @param customInitialMessage Optional custom initial message to send to Claude
437
+ * @returns true if Claude session completed successfully, false otherwise
420
438
  */
421
439
  async launchGuidedInit(customInitialMessage) {
422
440
  logger.debug("launchGuidedInit() starting", { hasCustomInitialMessage: !!customInitialMessage });
@@ -428,7 +446,7 @@ var InitCommand = class {
428
446
  logger.warn("Claude Code not detected. Skipping guided configuration.");
429
447
  logger.info("iloom won't be able to help you much without Claude Code, so please install it: npm install -g @anthropic-ai/claude-code");
430
448
  logger.debug("Exiting launchGuidedInit() due to missing Claude CLI");
431
- return;
449
+ return false;
432
450
  }
433
451
  try {
434
452
  const __filename = fileURLToPath(import.meta.url);
@@ -660,14 +678,15 @@ var InitCommand = class {
660
678
  });
661
679
  const initialMessage = customInitialMessage ?? "Help me configure iloom settings.";
662
680
  await launchClaude(initialMessage, claudeOptions);
663
- logger.debug("Claude session completed");
681
+ logger.debug("Claude session completed successfully");
682
+ return true;
664
683
  } catch (error) {
665
684
  const message = error instanceof Error ? error.message : "Unknown error";
666
685
  logger.warn(`Guided configuration failed: ${message}`);
667
686
  logger.debug("launchGuidedInit() error details", error instanceof Error ? error.stack : { error });
668
687
  logger.info("You can manually edit .iloom/settings.json to configure iloom.");
688
+ return false;
669
689
  }
670
- logger.debug("launchGuidedInit() completed");
671
690
  }
672
691
  /**
673
692
  * Load README.md content for init prompt
@@ -699,4 +718,4 @@ export {
699
718
  ShellCompletion,
700
719
  InitCommand
701
720
  };
702
- //# sourceMappingURL=chunk-VV66DH6T.js.map
721
+ //# sourceMappingURL=chunk-ZXWTOJXA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/ShellCompletion.ts","../src/commands/init.ts"],"sourcesContent":["import omelette from 'omelette'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport { logger } from '../utils/logger.js'\nimport { readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\nimport os from 'os'\n\nexport type ShellType = 'bash' | 'zsh' | 'fish' | 'unknown'\n\n/**\n * Manages shell autocomplete functionality for the iloom CLI\n * Uses omelette to provide tab-completion for commands in bash/zsh/fish\n */\nexport class ShellCompletion {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private completion: any // omelette instance - no types available\n private readonly COMPLETION_TIMEOUT = 1000 // ms - prevent blocking\n private readonly commandName: string\n\n constructor(commandName?: string) {\n // Detect command name from process.argv[1] if not provided\n this.commandName = commandName ?? this.detectCommandName()\n\n // Initialize omelette with both command names using pipe syntax\n // This registers completion for both 'iloom' and 'il' aliases\n // Template covers: <commandName> <command> <arg>\n // This allows for two-level completion: command completion + argument completion\n this.completion = omelette('iloom|il <command> <arg>')\n this.setupHandlers()\n }\n\n private detectCommandName(): string {\n // Get the actual command name used to invoke this script\n const scriptPath = process.argv[1] ?? 'il'\n const baseName = scriptPath.split('/').pop() ?? 'il'\n\n // Remove .js extension if present\n return baseName.replace(/\\.js$/, '')\n }\n\n private setupHandlers(): void {\n // Handler for command-level completion\n // When user types: il <TAB>\n this.completion.on('command', ({ reply }: { reply: (suggestions: string[]) => void }) => {\n reply([\n 'start',\n 'finish',\n 'spin',\n 'ignite',\n 'open',\n 'run',\n 'cleanup',\n 'list',\n 'init',\n // Intentionally exclude test-* commands from autocomplete\n ])\n })\n\n // Handler for argument-level completion\n // When user types: il <command> <TAB>\n this.completion.on('arg', async ({ line, reply }: { line: string; reply: (suggestions: string[]) => void }) => {\n // Check if the command is 'cleanup' to provide dynamic branch suggestions\n if (line.includes('cleanup')) {\n // Use timeout to prevent blocking if worktree listing is slow\n const suggestions = await this.getBranchSuggestionsWithTimeout()\n reply(suggestions)\n } else {\n // For other commands, no argument suggestions\n reply([])\n }\n })\n }\n\n /**\n * Get branch suggestions with timeout to prevent blocking\n */\n private async getBranchSuggestionsWithTimeout(): Promise<string[]> {\n try {\n return await Promise.race([\n this.getBranchSuggestions(),\n this.timeout(this.COMPLETION_TIMEOUT, []),\n ])\n } catch (error) {\n logger.debug(`Autocomplete branch suggestions failed: ${error}`)\n return []\n }\n }\n\n private async timeout<T>(ms: number, defaultValue: T): Promise<T> {\n return new Promise((resolve) => {\n // eslint-disable-next-line no-undef\n setTimeout(() => resolve(defaultValue), ms)\n })\n }\n\n async getBranchSuggestions(): Promise<string[]> {\n // Retrieve worktree branches for dynamic completion\n // Used by cleanup command autocomplete\n try {\n const manager = new GitWorktreeManager()\n const worktrees = await manager.listWorktrees({ porcelain: true })\n const repoInfo = await manager.getRepoInfo()\n\n // Filter out:\n // 1. Main worktree (at repo root) - can't be cleaned up\n // 2. Current worktree (where we're working) - shouldn't clean up current location\n const repoRoot = repoInfo.root\n const currentBranch = repoInfo.currentBranch\n\n return worktrees\n .filter((wt) => wt.path !== repoRoot) // Not the main worktree\n .filter((wt) => wt.branch !== currentBranch) // Not current worktree\n .map((wt) => wt.branch)\n } catch (error) {\n // Silently fail - autocomplete should never break the CLI\n logger.debug(`Failed to get branch suggestions: ${error}`)\n return []\n }\n }\n\n /**\n * Initialize completion - must be called before program.parseAsync()\n */\n init(): void {\n this.completion.init()\n }\n\n /**\n * Detect user's current shell\n */\n detectShell(): ShellType {\n const shell = process.env.SHELL ?? ''\n\n if (shell.includes('bash')) return 'bash'\n if (shell.includes('zsh')) return 'zsh'\n if (shell.includes('fish')) return 'fish'\n\n return 'unknown'\n }\n\n /**\n * Get completion script for a specific shell\n */\n getCompletionScript(shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return this.completion.setupShellInitFile('bash')\n case 'zsh':\n return this.completion.setupShellInitFile('zsh')\n case 'fish':\n return this.completion.setupShellInitFile('fish')\n default:\n throw new Error(`Unsupported shell type: ${shell}`)\n }\n }\n\n /**\n * Get setup instructions for manual installation\n */\n getSetupInstructions(shell: ShellType): string {\n const binaryName = this.commandName\n\n switch (shell) {\n case 'bash':\n return `\nAdd the following to your ~/.bashrc or ~/.bash_profile:\n\n eval \"$(${binaryName} --completion)\"\n\nThen reload your shell:\n\n source ~/.bashrc\n`\n case 'zsh':\n return `\nAdd the following to your ~/.zshrc:\n\n eval \"$(${binaryName} --completion)\"\n\nThen reload your shell:\n\n source ~/.zshrc\n`\n case 'fish':\n return `\nAdd the following to your ~/.config/fish/config.fish:\n\n ${binaryName} --completion | source\n\nThen reload your shell:\n\n source ~/.config/fish/config.fish\n`\n default:\n return `\nShell autocomplete is supported for bash, zsh, and fish.\nYour current shell (${shell}) may not be supported.\n\nPlease consult your shell's documentation for setting up custom completions.\n`\n }\n }\n\n /**\n * Generate completion script and print to stdout\n * Used by: il --completion\n */\n printCompletionScript(shell?: ShellType): void {\n const detectedShell = shell ?? this.detectShell()\n\n if (detectedShell === 'unknown') {\n logger.error('Could not detect shell type. Please specify --shell bash|zsh|fish')\n process.exit(1)\n }\n\n try {\n const script = this.getCompletionScript(detectedShell)\n // eslint-disable-next-line no-console\n console.log(script)\n } catch (error) {\n logger.error(`Failed to generate completion script: ${error}`)\n process.exit(1)\n }\n }\n\n /**\n * Get the shell configuration file path for the given shell type\n */\n getShellConfigPath(shell: ShellType): string | null {\n const homeDir = os.homedir()\n\n switch (shell) {\n case 'bash': {\n // Prefer .bashrc, fall back to .bash_profile\n const bashrcPath = path.join(homeDir, '.bashrc')\n const bashProfilePath = path.join(homeDir, '.bash_profile')\n\n if (existsSync(bashrcPath)) {\n return bashrcPath\n } else if (existsSync(bashProfilePath)) {\n return bashProfilePath\n }\n // Return .bashrc path even if it doesn't exist (for creation)\n return bashrcPath\n }\n\n case 'zsh':\n return path.join(homeDir, '.zshrc')\n\n case 'fish':\n return path.join(homeDir, '.config', 'fish', 'config.fish')\n\n default:\n return null\n }\n }\n\n /**\n * Read the shell configuration file contents\n */\n async readShellConfig(shell: ShellType): Promise<{ path: string; content: string } | null> {\n const configPath = this.getShellConfigPath(shell)\n\n if (!configPath) {\n return null\n }\n\n try {\n let content = ''\n if (existsSync(configPath)) {\n content = await readFile(configPath, 'utf-8')\n }\n // Return the path and content (empty string if file doesn't exist)\n return {\n path: configPath,\n content\n }\n } catch (error) {\n logger.debug(`Failed to read shell config file ${configPath}: ${error}`)\n return {\n path: configPath,\n content: ''\n }\n }\n }\n\n /**\n * Grep for completion-related content in shell configuration file\n * Returns only lines containing '--completion' with 2 lines of context before and after\n * Properly handles overlapping matches\n */\n async grepCompletionConfig(shell: ShellType): Promise<{ path: string; content: string } | null> {\n const configPath = this.getShellConfigPath(shell)\n\n if (!configPath) {\n return null\n }\n\n try {\n let content = ''\n if (existsSync(configPath)) {\n const fullContent = await readFile(configPath, 'utf-8')\n const lines = fullContent.split(/\\r?\\n/)\n\n // Find all matching line indices\n const matchingIndices: number[] = []\n lines.forEach((line, index) => {\n if (line.includes('--completion')) {\n matchingIndices.push(index)\n }\n })\n\n if (matchingIndices.length === 0) {\n content = ''\n } else {\n // Create ranges with context, handling overlaps\n const ranges: { start: number; end: number }[] = []\n\n matchingIndices.forEach(matchIndex => {\n const start = Math.max(0, matchIndex - 2)\n const end = Math.min(lines.length - 1, matchIndex + 2)\n ranges.push({ start, end })\n })\n\n // Merge overlapping ranges\n const mergedRanges = this.mergeOverlappingRanges(ranges)\n\n // Extract lines for each merged range\n const resultSections = mergedRanges.map(range =>\n lines.slice(range.start, range.end + 1).join('\\n')\n )\n\n content = resultSections.join('\\n--\\n')\n }\n }\n\n return {\n path: configPath,\n content\n }\n } catch (error) {\n logger.debug(`Failed to grep shell config file ${configPath}: ${error}`)\n return {\n path: configPath,\n content: ''\n }\n }\n }\n\n /**\n * Merge overlapping ranges to avoid duplicate lines\n */\n private mergeOverlappingRanges(ranges: { start: number; end: number }[]): { start: number; end: number }[] {\n if (ranges.length === 0) return []\n\n // Sort ranges by start position\n const sorted = [...ranges].sort((a, b) => a.start - b.start)\n const firstRange = sorted[0]\n if (!firstRange) return []\n\n const merged: { start: number; end: number }[] = [firstRange]\n\n for (let i = 1; i < sorted.length; i++) {\n const current = sorted[i]\n const last = merged[merged.length - 1]\n\n // Both current and last should exist, but TypeScript needs explicit checks\n if (!current || !last) continue\n\n // If current range overlaps or is adjacent to the last merged range\n if (current.start <= last.end + 1) {\n // Merge ranges by extending the end\n last.end = Math.max(last.end, current.end)\n } else {\n // No overlap, add as new range\n merged.push(current)\n }\n }\n\n return merged\n }\n\n}\n","import { logger } from '../utils/logger.js'\nimport { ShellCompletion } from '../lib/ShellCompletion.js'\nimport chalk from 'chalk'\nimport { mkdir, writeFile, readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { detectClaudeCli, launchClaude } from '../utils/claude.js'\nimport { PromptTemplateManager } from '../lib/PromptTemplateManager.js'\nimport { fileURLToPath } from 'url'\nimport { GitRemote, parseGitRemotes } from '../utils/remote.js'\nimport { SettingsMigrationManager } from '../lib/SettingsMigrationManager.js'\nimport { isFileGitignored, getRepoRoot } from '../utils/git.js'\nimport { FirstRunManager } from '../utils/FirstRunManager.js'\n\n/**\n * Initialize iloom configuration\n * Implements the `il init` command requested in issue #94\n */\nexport class InitCommand {\n private readonly shellCompletion: ShellCompletion\n private readonly templateManager: PromptTemplateManager\n\n constructor(shellCompletion?: ShellCompletion, templateManager?: PromptTemplateManager) {\n this.shellCompletion = shellCompletion ?? new ShellCompletion()\n this.templateManager = templateManager ?? new PromptTemplateManager()\n }\n\n /**\n * Main entry point for the init command\n * @param customInitialMessage Optional custom initial message to send to Claude (defaults to \"Help me configure iloom settings.\")\n */\n public async execute(customInitialMessage?: string): Promise<void> {\n try {\n logger.debug('InitCommand.execute() starting', {\n cwd: process.cwd(),\n nodeVersion: process.version,\n hasCustomInitialMessage: !!customInitialMessage\n })\n\n logger.info(chalk.bold('Welcome to iloom setup'))\n\n // Setup project configuration\n logger.info(chalk.bold('Verifying current setup...'))\n\n await this.setupProjectConfiguration()\n\n // Launch guided Claude configuration if available\n const guidedInitSucceeded = await this.launchGuidedInit(customInitialMessage)\n\n // Only mark project as configured if guided init succeeded and not already marked\n // This enables VSCode extension detection and ensures project appears in `il projects` list\n if (guidedInitSucceeded) {\n const projectRoot = await getRepoRoot() ?? process.cwd()\n const firstRunManager = new FirstRunManager()\n const alreadyConfigured = await firstRunManager.isProjectConfigured(projectRoot)\n if (!alreadyConfigured) {\n await firstRunManager.markProjectAsConfigured(projectRoot)\n logger.debug('Project marked as configured', { projectRoot })\n } else {\n logger.debug('Project already marked as configured, skipping', { projectRoot })\n }\n } else {\n logger.debug('Skipping project marker - guided init did not complete successfully')\n }\n\n logger.info(chalk.green('Setup complete! Enjoy using iloom CLI.'))\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n logger.error(`Initialization failed: ${message}`)\n throw error\n }\n }\n\n /**\n * Setup project configuration files\n * Creates settings.local.json and updates .gitignore\n */\n private async setupProjectConfiguration(): Promise<void> {\n logger.debug('setupProjectConfiguration() starting')\n\n // Migrate legacy .hatchbox settings to .iloom (BEFORE creating new files)\n try {\n logger.debug('Loading SettingsMigrationManager for legacy migration')\n const migrationManager = new SettingsMigrationManager()\n logger.debug('Running settings migration check')\n await migrationManager.migrateSettingsIfNeeded()\n logger.debug('Settings migration check completed')\n } catch (error) {\n // Log warning but don't fail\n logger.warn(`Settings migration failed: ${error instanceof Error ? error.message : 'Unknown'}`)\n logger.debug('Settings migration error details', { error })\n }\n\n // Update .gitignore\n logger.debug('Starting .gitignore update')\n await this.updateGitignore()\n logger.debug('setupProjectConfiguration() completed')\n\n // Ensure .iloom directory exists\n const iloomDir = path.join(process.cwd(), '.iloom')\n logger.debug('Creating .iloom directory', { iloomDir })\n await mkdir(iloomDir, { recursive: true })\n logger.debug('.iloom directory created/verified')\n\n // // Create settings.local.json if it doesn't exist\n // const settingsLocalPath = path.join(iloomDir, 'settings.local.json')\n // logger.debug('Checking for existing settings.local.json', { settingsLocalPath })\n\n // if (!existsSync(settingsLocalPath)) {\n // logger.debug('Creating settings.local.json file')\n // await writeFile(settingsLocalPath, '{}\\n', 'utf-8')\n // logger.info('Created .iloom/settings.local.json')\n // logger.debug('settings.local.json file created successfully')\n // } else {\n // logger.debug('settings.local.json file already exists, skipping')\n // }\n }\n\n /**\n * Add settings.local.json to .gitignore if not already present\n */\n private async updateGitignore(): Promise<void> {\n const gitignorePath = path.join(process.cwd(), '.gitignore')\n const entryToAdd = '.iloom/settings.local.json'\n\n logger.debug('updateGitignore() starting', {\n gitignorePath,\n entryToAdd\n })\n\n // Read existing .gitignore or create empty\n let content = ''\n if (existsSync(gitignorePath)) {\n logger.debug('.gitignore file exists, reading content')\n content = await readFile(gitignorePath, 'utf-8')\n logger.debug('Read .gitignore content', {\n contentLength: content.length,\n lineCount: content.split('\\n').length\n })\n } else {\n logger.debug('.gitignore file does not exist, will create new one')\n }\n\n // Check if entry already exists\n const lines = content.split('\\n')\n const entryExists = lines.some(line => line.trim() === entryToAdd)\n logger.debug('Checking if entry already exists', {\n entryExists,\n totalLines: lines.length\n })\n\n if (entryExists) {\n logger.debug('Entry already exists, skipping .gitignore update')\n return\n }\n\n // Add entry with comment\n const commentLine = '\\n# Added by iloom CLI'\n const separator = content.endsWith('\\n') || content === '' ? '' : '\\n'\n const newContent = content + separator + commentLine + '\\n' + entryToAdd + '\\n'\n\n logger.debug('Writing updated .gitignore', {\n originalLength: content.length,\n newLength: newContent.length,\n addedLines: 3 // comment + entry + newline\n })\n\n await writeFile(gitignorePath, newContent, 'utf-8')\n logger.info('Added .iloom/settings.local.json to .gitignore')\n logger.debug('.gitignore update completed successfully')\n }\n\n /**\n * Launch interactive Claude-guided configuration\n * @param customInitialMessage Optional custom initial message to send to Claude\n * @returns true if Claude session completed successfully, false otherwise\n */\n private async launchGuidedInit(customInitialMessage?: string): Promise<boolean> {\n logger.debug('launchGuidedInit() starting', { hasCustomInitialMessage: !!customInitialMessage })\n logger.info(chalk.bold('Starting interactive Claude-guided configuration...'))\n\n // Check if Claude CLI is available\n logger.debug('Checking Claude CLI availability')\n const claudeAvailable = await detectClaudeCli()\n logger.debug('Claude CLI availability check result', { claudeAvailable })\n\n if (!claudeAvailable) {\n logger.warn('Claude Code not detected. Skipping guided configuration.')\n logger.info('iloom won\\'t be able to help you much without Claude Code, so please install it: npm install -g @anthropic-ai/claude-code')\n logger.debug('Exiting launchGuidedInit() due to missing Claude CLI')\n return false\n }\n\n try {\n // Load schema from dist/schema/settings.schema.json\n // Use similar approach to PromptTemplateManager for path resolution\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = path.dirname(__filename)\n\n // Walk up to find the schema directory (in case of chunked files)\n let schemaPath = path.join(__dirname, 'schema', 'settings.schema.json')\n\n logger.debug('Loading settings schema', {\n __filename,\n __dirname,\n schemaPath,\n schemaExists: existsSync(schemaPath)\n })\n\n let schemaContent = ''\n if (existsSync(schemaPath)) {\n logger.debug('Reading schema file')\n schemaContent = await readFile(schemaPath, 'utf-8')\n logger.debug('Schema file loaded', {\n contentLength: schemaContent.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(schemaContent)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.warn('Schema file not found - Claude will work without schema validation')\n logger.debug('Schema file not found at expected path', { schemaPath })\n }\n\n // Check for existing settings - read ALL three files if they exist (global, project, local)\n const settingsGlobalPath = path.join(os.homedir(), '.config', 'iloom-ai', 'settings.json')\n const settingsLocalPath = path.join(process.cwd(), '.iloom', 'settings.local.json')\n const settingsCommittedPath = path.join(process.cwd(), '.iloom', 'settings.json')\n\n let settingsGlobalJson = ''\n let settingsJson = ''\n let settingsLocalJson = ''\n\n logger.debug('Checking for settings files', {\n settingsGlobalPath,\n settingsLocalPath,\n settingsCommittedPath,\n globalExists: existsSync(settingsGlobalPath),\n localExists: existsSync(settingsLocalPath),\n committedExists: existsSync(settingsCommittedPath)\n })\n\n // Read global settings.json if it exists\n if (existsSync(settingsGlobalPath)) {\n logger.debug('Reading global settings.json')\n const content = await readFile(settingsGlobalPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsGlobalJson = content\n logger.debug('global settings.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('global settings.json is empty, skipping')\n }\n } else {\n logger.debug('global settings.json does not exist')\n }\n\n // Read settings.json if it exists\n if (existsSync(settingsCommittedPath)) {\n logger.debug('Reading settings.json')\n const content = await readFile(settingsCommittedPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsJson = content\n logger.debug('settings.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('settings.json is empty, skipping')\n }\n } else {\n logger.debug('settings.json does not exist')\n }\n\n // Read settings.local.json if it exists\n if (existsSync(settingsLocalPath)) {\n logger.debug('Reading settings.local.json')\n const content = await readFile(settingsLocalPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsLocalJson = content\n logger.debug('settings.local.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('settings.local.json is empty, skipping')\n }\n } else {\n logger.debug('settings.local.json does not exist')\n }\n\n // Log summary\n logger.debug('Settings files summary', {\n hasSettingsGlobalJson: !!settingsGlobalJson,\n hasSettingsJson: !!settingsJson,\n hasSettingsLocalJson: !!settingsLocalJson,\n settingsGlobalJsonLength: settingsGlobalJson.length,\n settingsJsonLength: settingsJson.length,\n settingsLocalJsonLength: settingsLocalJson.length\n })\n\n // Detect shell and read config\n logger.debug('Detecting user shell')\n const shell = this.shellCompletion.detectShell()\n logger.debug('Shell detection result', { shell })\n\n let shellConfigPath = ''\n let shellConfigContent = ''\n\n if (shell !== 'unknown') {\n logger.debug('Grepping shell config for completion setup')\n const shellConfig = await this.shellCompletion.grepCompletionConfig(shell)\n if (shellConfig) {\n shellConfigPath = shellConfig.path\n shellConfigContent = shellConfig.content\n logger.debug('Shell config completion grep completed', {\n path: shellConfigPath,\n contentLength: shellConfigContent.length,\n configExists: existsSync(shellConfigPath),\n hasMatches: shellConfigContent.trim().length > 0\n })\n } else {\n logger.debug('Could not read shell config')\n }\n } else {\n logger.debug('Unknown shell detected, skipping config read')\n }\n\n let remotes: GitRemote[] = []\n try {\n // Detect git remotes for GitHub configuration\n logger.debug('Detecting git remotes for GitHub configuration')\n remotes = await parseGitRemotes()\n logger.debug('Git remotes detected', { count: remotes.length, remotes })\n } catch (error) {\n const message = error instanceof Error ? error.stack : 'Unknown error'\n logger.debug(\"Error occured while getting remote info: \", message)\n }\n\n // Detect if .vscode/settings.json is gitignored\n let vscodeSettingsGitignored = false\n try {\n vscodeSettingsGitignored = await isFileGitignored('.vscode/settings.json')\n logger.debug('VSCode settings gitignore status', { vscodeSettingsGitignored })\n } catch (error) {\n logger.debug('Could not detect gitignore status for .vscode/settings.json', { error })\n }\n\n let remotesInfo = ''\n let multipleRemotes = false\n let singleRemote = false\n let singleRemoteName = ''\n let singleRemoteUrl = ''\n let noRemotes = false\n\n if (remotes.length === 0) {\n noRemotes = true\n remotesInfo = 'No git remotes detected in this repository.'\n } else if (remotes.length === 1 && remotes[0]) {\n singleRemote = true\n singleRemoteName = remotes[0].name\n singleRemoteUrl = remotes[0].url\n remotesInfo = `Detected Remote:\\n- **${remotes[0].name}**: ${remotes[0].url} (${remotes[0].owner}/${remotes[0].repo})`\n } else {\n multipleRemotes = true\n remotesInfo = `Detected Remotes (${remotes.length}):\\n` +\n remotes.map(r => `- **${r.name}**: ${r.url} (${r.owner}/${r.repo})`).join('\\n')\n }\n\n // Load README content for comprehensive documentation\n logger.debug('README content loading...')\n const readmeContent = await this.loadReadmeContent()\n logger.debug('README content loaded', {\n readmeContentLength: readmeContent.length,\n })\n\n // Build template variables\n const variables = {\n SETTINGS_SCHEMA: schemaContent,\n SETTINGS_GLOBAL_JSON: settingsGlobalJson,\n SETTINGS_JSON: settingsJson,\n SETTINGS_LOCAL_JSON: settingsLocalJson,\n SHELL_TYPE: shell,\n SHELL_CONFIG_PATH: shellConfigPath,\n SHELL_CONFIG_CONTENT: shellConfigContent,\n REMOTES_INFO: remotesInfo,\n MULTIPLE_REMOTES: multipleRemotes.toString(),\n SINGLE_REMOTE: singleRemote.toString(),\n SINGLE_REMOTE_NAME: singleRemoteName,\n SINGLE_REMOTE_URL: singleRemoteUrl,\n NO_REMOTES: noRemotes.toString(),\n README_CONTENT: readmeContent,\n VSCODE_SETTINGS_GITIGNORED: vscodeSettingsGitignored.toString(),\n }\n\n logger.debug('Building template variables', {\n variableKeys: Object.keys(variables),\n schemaContentLength: schemaContent.length,\n settingsGlobalJsonLength: settingsGlobalJson.length,\n settingsJsonLength: settingsJson.length,\n settingsLocalJsonLength: settingsLocalJson.length\n })\n\n // Get init prompt\n logger.debug('Loading init prompt template')\n const prompt = await this.templateManager.getPrompt('init', variables)\n\n logger.debug('Init prompt loaded', {\n promptLength: prompt.length,\n containsSchema: prompt.includes('SETTINGS_SCHEMA'),\n containsExistingSettings: prompt.includes('EXISTING_SETTINGS')\n })\n\n const claudeOptions = {\n headless: false,\n appendSystemPrompt: prompt,\n addDir: process.cwd(),\n }\n\n logger.debug('Launching Claude with options', {\n optionKeys: Object.keys(claudeOptions),\n headless: claudeOptions.headless,\n hasSystemPrompt: !!claudeOptions.appendSystemPrompt,\n addDir: claudeOptions.addDir,\n promptLength: prompt.length,\n hasCustomInitialMessage: !!customInitialMessage\n })\n\n // Launch Claude in interactive mode with custom initial message if provided\n const initialMessage = customInitialMessage ?? 'Help me configure iloom settings.'\n await launchClaude(initialMessage, claudeOptions)\n logger.debug('Claude session completed successfully')\n return true\n\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n logger.warn(`Guided configuration failed: ${message}`)\n logger.debug('launchGuidedInit() error details', error instanceof Error ? error.stack : {error})\n logger.info('You can manually edit .iloom/settings.json to configure iloom.')\n return false\n }\n }\n\n /**\n * Load README.md content for init prompt\n * Walks up from dist directory to find README.md in project root\n */\n private async loadReadmeContent(): Promise<string> {\n try {\n // Walk up from current file location to find README.md\n // Use same pattern as PromptTemplateManager for finding files\n let currentDir = path.dirname(fileURLToPath(import.meta.url))\n\n // Walk up to find README.md\n while (currentDir !== path.dirname(currentDir)) {\n const readmePath = path.join(currentDir, 'README.md')\n try {\n const content = await readFile(readmePath, 'utf-8')\n logger.debug('Loaded README.md for init prompt', { readmePath })\n return content\n } catch {\n currentDir = path.dirname(currentDir)\n }\n }\n\n logger.debug('README.md not found, returning empty string')\n return ''\n } catch (error) {\n // Graceful degradation - return empty string on error\n logger.debug(`Failed to load README.md: ${error}`)\n return ''\n }\n }\n\n}\n"],"mappings":"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","names":["readFile","existsSync","path","os","path","existsSync","readFile","os"]}
@@ -5,22 +5,22 @@ import {
5
5
  EnvironmentManager,
6
6
  LoomManager,
7
7
  ResourceCleanup
8
- } from "./chunk-Z5BM4JWB.js";
8
+ } from "./chunk-NRDY6XO3.js";
9
9
  import "./chunk-LVLRMP7V.js";
10
10
  import {
11
11
  ProcessManager
12
12
  } from "./chunk-VU3QMIP2.js";
13
13
  import {
14
14
  IdentifierParser
15
- } from "./chunk-YU5HVI6B.js";
15
+ } from "./chunk-YPOG7WY4.js";
16
16
  import {
17
17
  createNeonProviderFromSettings
18
18
  } from "./chunk-7LSSNB7Y.js";
19
19
  import "./chunk-2ZPFJQ3B.js";
20
20
  import {
21
21
  GitWorktreeManager
22
- } from "./chunk-HMMO2LDS.js";
23
- import "./chunk-53OMUNUN.js";
22
+ } from "./chunk-ESP2FF52.js";
23
+ import "./chunk-TKL7RBEF.js";
24
24
  import {
25
25
  SettingsManager
26
26
  } from "./chunk-IDUICCZY.js";
@@ -278,7 +278,7 @@ var CleanupCommand = class {
278
278
  const { force, dryRun } = parsed.options;
279
279
  let parsedInput = await this.identifierParser.parseForPatternDetection(identifier);
280
280
  if (parsedInput.type === "branch" && parsedInput.branchName) {
281
- const { extractIssueNumber } = await import("./git-OV6ADVO7.js");
281
+ const { extractIssueNumber } = await import("./git-UHUNQZBA.js");
282
282
  const extractedNumber = extractIssueNumber(parsedInput.branchName);
283
283
  if (extractedNumber !== null) {
284
284
  parsedInput = {
@@ -477,4 +477,4 @@ var CleanupCommand = class {
477
477
  export {
478
478
  CleanupCommand
479
479
  };
480
- //# sourceMappingURL=cleanup-Y5W3CNUV.js.map
480
+ //# sourceMappingURL=cleanup-H5QUWBWE.js.map
package/dist/cli.js CHANGED
@@ -4,10 +4,9 @@ import {
4
4
  } from "./chunk-J7GHNTYK.js";
5
5
  import "./chunk-NXMDEL3F.js";
6
6
  import {
7
- FirstRunManager,
8
7
  IssueTrackerFactory,
9
8
  generateIssueManagementMcpConfig
10
- } from "./chunk-66BMJ25W.js";
9
+ } from "./chunk-6YSFTPKW.js";
11
10
  import "./chunk-7Q66W4OH.js";
12
11
  import {
13
12
  CLIIsolationManager,
@@ -15,7 +14,7 @@ import {
15
14
  EnvironmentManager,
16
15
  LoomManager,
17
16
  ResourceCleanup
18
- } from "./chunk-Z5BM4JWB.js";
17
+ } from "./chunk-NRDY6XO3.js";
19
18
  import {
20
19
  detectPackageManager,
21
20
  installDependencies,
@@ -26,14 +25,17 @@ import {
26
25
  } from "./chunk-VU3QMIP2.js";
27
26
  import {
28
27
  IdentifierParser
29
- } from "./chunk-YU5HVI6B.js";
28
+ } from "./chunk-YPOG7WY4.js";
30
29
  import {
31
30
  createNeonProviderFromSettings
32
31
  } from "./chunk-7LSSNB7Y.js";
33
32
  import {
34
33
  InitCommand,
35
34
  ShellCompletion
36
- } from "./chunk-VV66DH6T.js";
35
+ } from "./chunk-ZXWTOJXA.js";
36
+ import {
37
+ FirstRunManager
38
+ } from "./chunk-NKRQNER7.js";
37
39
  import "./chunk-F2PWIRV4.js";
38
40
  import {
39
41
  IssueEnhancementService,
@@ -51,10 +53,10 @@ import {
51
53
  } from "./chunk-2ZPFJQ3B.js";
52
54
  import {
53
55
  MergeManager
54
- } from "./chunk-XNNXAAZT.js";
56
+ } from "./chunk-E4F7KASE.js";
55
57
  import {
56
58
  GitWorktreeManager
57
- } from "./chunk-HMMO2LDS.js";
59
+ } from "./chunk-ESP2FF52.js";
58
60
  import {
59
61
  PRManager
60
62
  } from "./chunk-5IWU3HXE.js";
@@ -92,7 +94,7 @@ import {
92
94
  pushBranchToRemote,
93
95
  removePlaceholderCommitFromHead,
94
96
  removePlaceholderCommitFromHistory
95
- } from "./chunk-53OMUNUN.js";
97
+ } from "./chunk-TKL7RBEF.js";
96
98
  import {
97
99
  SettingsManager
98
100
  } from "./chunk-IDUICCZY.js";
@@ -182,11 +184,6 @@ async function launchFirstRunSetup() {
182
184
  await initCommand.execute(
183
185
  "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."
184
186
  );
185
- const projectRoot = await getProjectRoot();
186
- logger.debug(`Marking project as configured at root: ${projectRoot}`);
187
- const firstRunManager = new FirstRunManager();
188
- await firstRunManager.markProjectAsConfigured(projectRoot);
189
- logger.debug(`Project marked as configured at root: ${projectRoot}`);
190
187
  logger.info("Configuration complete! Continuing with your original command...");
191
188
  }
192
189
 
@@ -2122,7 +2119,7 @@ var FinishCommand = class {
2122
2119
  message: "Commit aborted by user",
2123
2120
  success: false
2124
2121
  });
2125
- return;
2122
+ throw error;
2126
2123
  }
2127
2124
  throw error;
2128
2125
  }
@@ -2309,7 +2306,7 @@ var FinishCommand = class {
2309
2306
  message: "Commit aborted by user",
2310
2307
  success: false
2311
2308
  });
2312
- return;
2309
+ throw error;
2313
2310
  }
2314
2311
  throw error;
2315
2312
  }
@@ -3002,7 +2999,7 @@ async function autoLaunchInitForMultipleRemotes() {
3002
2999
  await waitForKeypress2("Press any key to start configuration...");
3003
3000
  logger.info("");
3004
3001
  try {
3005
- const { InitCommand: InitCommand2 } = await import("./init-CMIRHFSR.js");
3002
+ const { InitCommand: InitCommand2 } = await import("./init-4ZR2XXZA.js");
3006
3003
  const initCommand = new InitCommand2();
3007
3004
  const customInitialMessage = "Help me configure which git remote iloom should use for GitHub operations. I have multiple remotes and need to select the correct one.";
3008
3005
  await initCommand.execute(customInitialMessage);
@@ -3171,6 +3168,9 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
3171
3168
  } else {
3172
3169
  logger.error(`Failed to finish workspace: ${error instanceof Error ? error.message : "Unknown error"}`);
3173
3170
  }
3171
+ if (error instanceof UserAbortedCommitError) {
3172
+ process.exit(130);
3173
+ }
3174
3174
  process.exit(1);
3175
3175
  }
3176
3176
  };
@@ -3183,7 +3183,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
3183
3183
  });
3184
3184
  program.command("rebase").description("Rebase current branch on main with Claude-assisted conflict resolution").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").action(async (options) => {
3185
3185
  try {
3186
- const { RebaseCommand } = await import("./rebase-6UIHMUWS.js");
3186
+ const { RebaseCommand } = await import("./rebase-SRBOVC4M.js");
3187
3187
  const command = new RebaseCommand();
3188
3188
  await command.execute(options);
3189
3189
  } catch (error) {
@@ -3195,7 +3195,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
3195
3195
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
3196
3196
  ).action(async (options) => {
3197
3197
  try {
3198
- const { IgniteCommand } = await import("./ignite-3HB3ZBEW.js");
3198
+ const { IgniteCommand } = await import("./ignite-VPP4PMF4.js");
3199
3199
  const command = new IgniteCommand();
3200
3200
  await command.execute(options.oneShot ?? "default");
3201
3201
  } catch (error) {
@@ -3206,7 +3206,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
3206
3206
  program.command("open").description("Open workspace in browser or run CLI tool").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
3207
3207
  try {
3208
3208
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
3209
- const { OpenCommand } = await import("./open-AXE225Z5.js");
3209
+ const { OpenCommand } = await import("./open-6HBQHPUL.js");
3210
3210
  const cmd = new OpenCommand();
3211
3211
  const input = identifier ? { identifier, args } : { args };
3212
3212
  await cmd.execute(input);
@@ -3218,7 +3218,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
3218
3218
  program.command("run").description("Run CLI tool or open workspace in browser").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
3219
3219
  try {
3220
3220
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
3221
- const { RunCommand } = await import("./run-H375EYRB.js");
3221
+ const { RunCommand } = await import("./run-5FU76FFE.js");
3222
3222
  const cmd = new RunCommand();
3223
3223
  const input = identifier ? { identifier, args } : { args };
3224
3224
  await cmd.execute(input);
@@ -3229,7 +3229,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
3229
3229
  });
3230
3230
  program.command("dev-server").alias("dev").description("Start dev server for workspace (foreground)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--json", "Output as JSON").action(async (identifier, options) => {
3231
3231
  try {
3232
- const { DevServerCommand } = await import("./dev-server-HNBRWGCD.js");
3232
+ const { DevServerCommand } = await import("./dev-server-H5FFXIVX.js");
3233
3233
  const cmd = new DevServerCommand();
3234
3234
  await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
3235
3235
  } catch (error) {
@@ -3239,7 +3239,7 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
3239
3239
  });
3240
3240
  program.command("shell").alias("terminal").description("Open interactive shell with workspace environment").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
3241
3241
  try {
3242
- const { ShellCommand } = await import("./shell-33FJCWJQ.js");
3242
+ const { ShellCommand } = await import("./shell-UQJDI36V.js");
3243
3243
  const cmd = new ShellCommand();
3244
3244
  await cmd.execute({ identifier });
3245
3245
  } catch (error) {
@@ -3250,7 +3250,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
3250
3250
  program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").action(async (identifier, options) => {
3251
3251
  const executeAction = async () => {
3252
3252
  try {
3253
- const { CleanupCommand } = await import("./cleanup-Y5W3CNUV.js");
3253
+ const { CleanupCommand } = await import("./cleanup-H5QUWBWE.js");
3254
3254
  const command = new CleanupCommand();
3255
3255
  const input = {
3256
3256
  options: options ?? {}
@@ -3328,7 +3328,7 @@ program.command("list").description("Show active workspaces").option("--json", "
3328
3328
  });
3329
3329
  program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
3330
3330
  try {
3331
- const { ProjectsCommand } = await import("./projects-GVEMCN5R.js");
3331
+ const { ProjectsCommand } = await import("./projects-SA76I4TZ.js");
3332
3332
  const command = new ProjectsCommand();
3333
3333
  const result = await command.execute(options);
3334
3334
  console.log(JSON.stringify(result, null, 2));
@@ -3339,7 +3339,7 @@ program.command("projects").description("List configured iloom projects").option
3339
3339
  });
3340
3340
  program.command("init").alias("config").description("Initialize iloom configuration").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
3341
3341
  try {
3342
- const { InitCommand: InitCommand2 } = await import("./init-CMIRHFSR.js");
3342
+ const { InitCommand: InitCommand2 } = await import("./init-4ZR2XXZA.js");
3343
3343
  const command = new InitCommand2();
3344
3344
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
3345
3345
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
@@ -3351,7 +3351,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
3351
3351
  });
3352
3352
  program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
3353
3353
  try {
3354
- const { ContributeCommand } = await import("./contribute-SMIPMWCH.js");
3354
+ const { ContributeCommand } = await import("./contribute-VP73TPAL.js");
3355
3355
  const command = new ContributeCommand();
3356
3356
  await command.execute();
3357
3357
  } catch (error) {
@@ -3581,7 +3581,7 @@ program.command("test-webserver").description("Test if a web server is running o
3581
3581
  });
3582
3582
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3583
3583
  try {
3584
- const { TestGitCommand } = await import("./test-git-CO3BA4BV.js");
3584
+ const { TestGitCommand } = await import("./test-git-GB3B6QNT.js");
3585
3585
  const command = new TestGitCommand();
3586
3586
  await command.execute();
3587
3587
  } catch (error) {
@@ -3607,7 +3607,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3607
3607
  });
3608
3608
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3609
3609
  try {
3610
- const { TestPrefixCommand } = await import("./test-prefix-HZYSDQYT.js");
3610
+ const { TestPrefixCommand } = await import("./test-prefix-YQNNTCY3.js");
3611
3611
  const command = new TestPrefixCommand();
3612
3612
  await command.execute();
3613
3613
  } catch (error) {
@@ -3621,7 +3621,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3621
3621
  program.command("summary").description("Generate Claude session summary for a loom").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--with-comment", "Post summary as a comment to the issue/PR").option("--json", "Output result as JSON").action(async (identifier, options) => {
3622
3622
  const executeAction = async () => {
3623
3623
  try {
3624
- const { SummaryCommand } = await import("./summary-JUMOCNLR.js");
3624
+ const { SummaryCommand } = await import("./summary-MOKN7RM2.js");
3625
3625
  const command = new SummaryCommand();
3626
3626
  const result = await command.execute({ identifier, options });
3627
3627
  if (options.json && result) {
@@ -3650,7 +3650,7 @@ program.command("summary").description("Generate Claude session summary for a lo
3650
3650
  program.command("recap").description("Get recap for a loom (defaults to current directory)").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--json", "Output as JSON with filePath for file watching").action(async (identifier, options) => {
3651
3651
  const executeAction = async () => {
3652
3652
  try {
3653
- const { RecapCommand } = await import("./recap-XTBNMEMO.js");
3653
+ const { RecapCommand } = await import("./recap-X7FTTKPP.js");
3654
3654
  const command = new RecapCommand();
3655
3655
  const result = await command.execute({ identifier, json: options.json });
3656
3656
  if (options.json && result) {