@braingrid/cli 0.2.53 → 0.2.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.54] - 2026-02-25
11
+
12
+ ### Added
13
+
14
+ - **Logger file writing enabled by default** — `logToFile` now defaults to `true` so all `logger.debug()` calls in auth, JWT, and services actually write to `~/.braingrid/logs/braingrid-cli.log`
15
+ - **Silent catch block logging** — 7 catch blocks in `auth.ts` and 1 in `jwt.ts` that silently swallowed errors now log debug messages with error context
16
+ - **jq installer** — new cross-platform `jq-installer.ts` following the established git/gh installer pattern; `braingrid init` now checks for and offers to install jq (required by all hooks)
17
+ - **jq in CLI tools registry** — `braingrid status` now shows jq version in "Installed Coding Tools" section
18
+ - **Hook error wrapper** — new `log_braingrid_call()` function in `log-helper.sh` captures stderr separately and logs failed CLI calls with exit codes
19
+ - **Hook jq availability check** — `log-helper.sh` warns on stderr if jq is not installed
20
+ - **Hook early-exit logging** — sentinel and status skip conditions now log INFO events for audit trail
21
+ - **Hook SIGTERM traps** — `sync-braingrid-task.sh` and `create-braingrid-task.sh` log timeout kills instead of dying silently
22
+ - **JSON validation in sync hook** — validates `jq` can parse task list output before processing
23
+ - **Debug Logs section in status** — `braingrid status` now shows CLI log and hook log file paths with sizes
24
+ - **Log correlation** — Logger supports optional `sessionId` for requirement-scoped log entries
25
+ - **Flush guarantee** — `flushLogger()` in cli-logger ensures write stream is drained before closing, with 1-second safety timeout
26
+
27
+ ### Fixed
28
+
29
+ - **`$?` capture bug** — `sync-braingrid-task.sh` and `create-braingrid-task.sh` captured exit code after `log_time_end` (which reset `$?` via `date`)
30
+ - **Error formatter `[object Object]`** — plain objects now JSON.stringify instead of showing `[object Object]`
31
+ - **Error formatter context** — regular `Error` objects now include resource context prefix when provided
32
+
33
+ ### Changed
34
+
35
+ - **Error formatter** — stack traces logged at debug level for Error objects
36
+
10
37
  ## [0.2.53] - 2026-02-25
11
38
 
12
39
  ### Added
@@ -101,6 +101,12 @@ var CLI_TOOLS = [
101
101
  return match ? match[1] : null;
102
102
  }
103
103
  },
104
+ {
105
+ name: "jq",
106
+ command: "jq",
107
+ versionFlag: "--version",
108
+ versionParser: (output) => output.match(/jq-([\d.]+)/)?.[1] || output.trim()
109
+ },
104
110
  {
105
111
  name: "Claude Code",
106
112
  command: "claude",
@@ -451,4 +457,4 @@ export {
451
457
  installGh,
452
458
  getGhManualInstallInstructions
453
459
  };
454
- //# sourceMappingURL=chunk-S3D6P3QC.js.map
460
+ //# sourceMappingURL=chunk-NEDKD2DE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/gh-installer.ts","../src/utils/cli-tools.ts","../src/utils/package-manager-installer.ts"],"sourcesContent":["/**\n * GitHub CLI Installer Utility\n *\n * Automatically installs GitHub CLI on the user's system using platform-specific methods:\n * - macOS: Homebrew (if installed) or Webi (automated installer)\n * - Windows: winget\n * - Linux: apt/dnf/pacman (auto-detected)\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport chalk from 'chalk';\nimport { getCliVersion, isCliInstalled } from './cli-tools.js';\nimport {\n\tdetectLinuxPackageManager,\n\tisHomebrewInstalled,\n\tisWingetAvailable,\n} from './package-manager-installer.js';\n\nconst execAsync = promisify(exec);\n\nexport interface GhInstallResult {\n\tsuccess: boolean;\n\tmessage: string;\n\tversion?: string;\n}\n\n/**\n * Check if GitHub CLI is installed\n */\nexport async function isGhInstalled(): Promise<boolean> {\n\treturn isCliInstalled('gh');\n}\n\n/**\n * Get GitHub CLI version if installed\n */\nexport async function getGhVersion(): Promise<string | null> {\n\treturn getCliVersion('gh', '--version', output => {\n\t\tconst match = output.match(/gh version ([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t});\n}\n\n/**\n * Install GitHub CLI on macOS via Homebrew (when Homebrew is already installed)\n */\nasync function installViaHomebrew(): Promise<GhInstallResult> {\n\tconsole.log(chalk.blue('📦 Installing GitHub CLI via Homebrew...'));\n\n\ttry {\n\t\tawait execAsync('brew install gh', {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: chalk.red('❌ GitHub CLI installation completed but gh command not found'),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI via Homebrew\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on macOS via Webi (automated installer, no Homebrew needed)\n */\nasync function installViaWebi(): Promise<GhInstallResult> {\n\tconsole.log(chalk.blue('📦 Installing GitHub CLI via Webi...'));\n\tconsole.log(chalk.dim('This will install gh to ~/.local/bin/\\n'));\n\n\ttry {\n\t\tawait execAsync('curl -sS https://webi.sh/gh | sh', {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\t// Installation succeeded but PATH not updated yet\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage:\n\t\t\t\t\tchalk.green('✅ GitHub CLI installed successfully!\\n') +\n\t\t\t\t\tchalk.dim(\n\t\t\t\t\t\t'Note: You may need to restart your terminal for the gh command to be available.'\n\t\t\t\t\t),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI via Webi\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on macOS using best available method\n * Strategy: Use Homebrew if installed, otherwise use Webi\n */\nasync function installGhMacOS(): Promise<GhInstallResult> {\n\t// Check if Homebrew is already installed\n\tconst hasHomebrew = await isHomebrewInstalled();\n\n\tif (hasHomebrew) {\n\t\t// User already has Homebrew - use it (fast and familiar)\n\t\treturn installViaHomebrew();\n\t}\n\n\t// No Homebrew - use Webi (automated installer, no package manager needed)\n\treturn installViaWebi();\n}\n\n/**\n * Install GitHub CLI on Windows using winget\n */\nasync function installGhWindows(): Promise<GhInstallResult> {\n\t// Check if winget is available\n\tconst hasWinget = await isWingetAvailable();\n\n\tif (!hasWinget) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ winget is not available on this system\\n\\n') +\n\t\t\t\tchalk.dim('winget is included in Windows 10 (version 1809+) and Windows 11.\\n') +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n\n\tconsole.log(chalk.blue('📦 Installing GitHub CLI via winget...'));\n\n\ttry {\n\t\tawait execAsync('winget install --id GitHub.cli --silent', {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: chalk.red('❌ GitHub CLI installation completed but gh command not found'),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI via winget\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on Linux using detected package manager\n */\nasync function installGhLinux(): Promise<GhInstallResult> {\n\tconst packageManager = await detectLinuxPackageManager();\n\n\tif (!packageManager) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Could not detect a supported package manager\\n\\n') +\n\t\t\t\tchalk.dim('Supported package managers: apt, dnf, yum, pacman\\n') +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n\n\tconsole.log(chalk.blue(`📦 Installing GitHub CLI via ${packageManager.name}...`));\n\tconsole.log(chalk.dim('This may prompt for your sudo password.\\n'));\n\n\ttry {\n\t\tlet installCommand: string;\n\n\t\tswitch (packageManager.name) {\n\t\t\tcase 'apt':\n\t\t\t\t// Add GitHub CLI repository and install\n\t\t\t\tinstallCommand =\n\t\t\t\t\t'curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && ' +\n\t\t\t\t\t'sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && ' +\n\t\t\t\t\t'echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main\" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && ' +\n\t\t\t\t\t'sudo apt update && sudo apt install gh -y';\n\t\t\t\tbreak;\n\t\t\tcase 'dnf':\n\t\t\t\tinstallCommand = 'sudo dnf install gh -y';\n\t\t\t\tbreak;\n\t\t\tcase 'yum':\n\t\t\t\tinstallCommand = 'sudo yum install gh -y';\n\t\t\t\tbreak;\n\t\t\tcase 'pacman':\n\t\t\t\tinstallCommand = 'sudo pacman -S --noconfirm github-cli';\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: chalk.red(`❌ Unsupported package manager: ${packageManager.name}`),\n\t\t\t\t};\n\t\t}\n\n\t\tawait execAsync(installCommand, {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: chalk.red('❌ GitHub CLI installation completed but gh command not found'),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on the current platform\n * Auto-detects platform and uses appropriate installation method\n */\nexport async function installGh(): Promise<GhInstallResult> {\n\tconst platform = process.platform;\n\n\tswitch (platform) {\n\t\tcase 'darwin':\n\t\t\treturn installGhMacOS();\n\n\t\tcase 'win32':\n\t\t\treturn installGhWindows();\n\n\t\tcase 'linux':\n\t\t\treturn installGhLinux();\n\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage:\n\t\t\t\t\tchalk.red(`❌ Unsupported platform: ${platform}\\n\\n`) +\n\t\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t\t};\n\t}\n}\n\n/**\n * Get manual installation instructions for the current platform\n */\nexport function getGhManualInstallInstructions(): string {\n\tconst platform = process.platform;\n\n\tswitch (platform) {\n\t\tcase 'darwin':\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation (macOS)\\n\\n') +\n\t\t\t\tchalk.dim('Option 1 - Webi (recommended, no Homebrew needed):\\n') +\n\t\t\t\tchalk.cyan(' curl -sS https://webi.sh/gh | sh\\n\\n') +\n\t\t\t\tchalk.dim('Option 2 - Homebrew:\\n') +\n\t\t\t\tchalk.cyan(' brew install gh\\n\\n') +\n\t\t\t\tchalk.dim('Option 3 - Direct download:\\n') +\n\t\t\t\tchalk.cyan(' Download from: https://cli.github.com/')\n\t\t\t);\n\n\t\tcase 'win32':\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation (Windows)\\n\\n') +\n\t\t\t\tchalk.dim('Option 1 - winget (Windows 10+):\\n') +\n\t\t\t\tchalk.cyan(' winget install --id GitHub.cli\\n\\n') +\n\t\t\t\tchalk.dim('Option 2 - Direct download:\\n') +\n\t\t\t\tchalk.cyan(' Download from: https://cli.github.com/')\n\t\t\t);\n\n\t\tcase 'linux':\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation (Linux)\\n\\n') +\n\t\t\t\tchalk.dim('Debian/Ubuntu:\\n') +\n\t\t\t\tchalk.cyan(\n\t\t\t\t\t' See instructions at: https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian-ubuntu-linux-raspberry-pi-os-apt\\n\\n'\n\t\t\t\t) +\n\t\t\t\tchalk.dim('Fedora/RHEL:\\n') +\n\t\t\t\tchalk.cyan(' sudo dnf install gh\\n\\n') +\n\t\t\t\tchalk.dim('Arch Linux:\\n') +\n\t\t\t\tchalk.cyan(' sudo pacman -S github-cli\\n\\n') +\n\t\t\t\tchalk.dim('Or download from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/')\n\t\t\t);\n\n\t\tdefault:\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation\\n\\n') +\n\t\t\t\tchalk.dim('Download from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/')\n\t\t\t);\n\t}\n}\n","/**\n * CLI Tools Detection Utilities\n *\n * Detects installed AI coding tools and CLI utilities:\n * - Checks if common AI IDE CLIs are installed\n * - Gets version information where available\n * - Cross-platform support (macOS, Linux, Windows)\n */\n\nimport { exec } from 'node:child_process';\nimport { access, constants } from 'node:fs/promises';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\n// Claude Code local installation path after migrate-installer\nconst CLAUDE_LOCAL_PATH = join(homedir(), '.claude', 'local', 'claude');\n\nexport interface CliToolInfo {\n\tname: string; // Display name (e.g., \"GitHub CLI\")\n\tcommand: string; // Command to check (e.g., \"gh\")\n\tinstalled: boolean; // Whether it's installed\n\tversion?: string; // Version string if available\n}\n\ninterface CliToolConfig {\n\tname: string;\n\tcommand: string;\n\tversionFlag?: string;\n\tversionParser?: (output: string) => string | null;\n\tspecialCheck?: () => Promise<boolean>;\n\tspecialVersionCheck?: () => Promise<string | null>;\n}\n\n/**\n * Check if Claude Code is installed\n * Special handling for Claude CLI after `claude migrate-installer`\n *\n * The migrate-installer command moves the Claude Code executable from PATH\n * to ~/.claude/local/claude, so standard PATH checks fail.\n *\n * Detection priority:\n * 1. Check ~/.claude/local/claude (after migrate-installer)\n * 2. Try executing `claude --version` (may work via shell alias)\n * 3. Check PATH with `which claude`\n */\nasync function checkClaudeInstalled(): Promise<boolean> {\n\t// Priority 1: Check ~/.claude/local/claude (after migrate-installer)\n\ttry {\n\t\tawait access(CLAUDE_LOCAL_PATH, constants.X_OK);\n\t\treturn true;\n\t} catch {\n\t\t// Fall through to next check\n\t}\n\n\t// Priority 2: Try executing claude --version (may work via shell alias)\n\ttry {\n\t\tawait execAsync('claude --version 2>&1', { timeout: 2000 });\n\t\treturn true;\n\t} catch {\n\t\t// Fall through to PATH check\n\t}\n\n\t// Priority 3: Check PATH with which\n\treturn isCliInstalled('claude');\n}\n\n/**\n * Get Claude Code version\n * Tries local path first, then falls back to standard version check\n */\nasync function getClaudeVersion(): Promise<string | null> {\n\t// Try local path first\n\ttry {\n\t\tawait access(CLAUDE_LOCAL_PATH, constants.X_OK);\n\t\tconst result = await execAsync(`\"${CLAUDE_LOCAL_PATH}\" --version 2>&1`, {\n\t\t\ttimeout: 2000,\n\t\t});\n\t\tconst output = result.stdout || result.stderr;\n\t\tconst match = output.match(/([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t} catch {\n\t\t// Fall through to regular version check\n\t}\n\n\t// Fall back to regular claude command\n\treturn getCliVersion('claude', '--version', output => {\n\t\tconst match = output.match(/([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t});\n}\n\n/**\n * Get platform-specific Cursor IDE application paths\n */\nfunction getCursorAppPaths(): string[] {\n\tconst paths: string[] = [];\n\tconst home = homedir();\n\n\tswitch (platform()) {\n\t\tcase 'darwin': // macOS\n\t\t\tpaths.push('/Applications/Cursor.app');\n\t\t\tpaths.push(join(home, 'Library/Application Support/Cursor'));\n\t\t\tbreak;\n\n\t\tcase 'win32': {\n\t\t\t// Windows\n\t\t\tconst localAppData = process.env.LOCALAPPDATA || join(home, 'AppData', 'Local');\n\t\t\tconst appData = process.env.APPDATA || join(home, 'AppData', 'Roaming');\n\t\t\tpaths.push(join(localAppData, 'Programs', 'Cursor'));\n\t\t\tpaths.push(join(appData, 'Cursor'));\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 'linux':\n\t\t\t// Linux: Check config directory (most reliable for AppImage)\n\t\t\tpaths.push(join(home, '.config', 'Cursor'));\n\t\t\tpaths.push(join(home, '.cursor'));\n\t\t\t// Common AppImage locations\n\t\t\tpaths.push('/opt/cursor.appimage');\n\t\t\tpaths.push('/usr/local/bin/cursor.appimage');\n\t\t\tbreak;\n\t}\n\n\treturn paths;\n}\n\n/**\n * Check if Cursor IDE is installed\n * Checks platform-specific application paths and config directories\n */\nasync function checkCursorIdeInstalled(): Promise<boolean> {\n\tconst paths = getCursorAppPaths();\n\n\t// Try each path\n\tfor (const path of paths) {\n\t\ttry {\n\t\t\tawait access(path);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// Continue to next path\n\t\t}\n\t}\n\n\t// Fallback: Check if cursor CLI is available\n\treturn isCliInstalled('cursor');\n}\n\n/**\n * Get Cursor IDE version\n * Falls back to CLI version if app version unavailable\n */\nasync function getCursorIdeVersion(): Promise<string | null> {\n\t// Try CLI version first (simplest)\n\tconst cliVersion = await getCliVersion('cursor', '--version', output => {\n\t\tconst match = output.match(/([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t});\n\n\treturn cliVersion;\n}\n\nconst CLI_TOOLS: CliToolConfig[] = [\n\t{\n\t\tname: 'Git',\n\t\tcommand: 'git',\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\tconst match = output.match(/git version ([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n\t{\n\t\tname: 'GitHub CLI',\n\t\tcommand: 'gh',\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\tconst match = output.match(/gh version ([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n\t{\n\t\tname: 'Claude Code',\n\t\tcommand: 'claude',\n\t\tspecialCheck: checkClaudeInstalled,\n\t\tspecialVersionCheck: getClaudeVersion,\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\t// Output format: \"2.0.1 (Claude Code)\"\n\t\t\tconst match = output.match(/([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n\t{\n\t\tname: 'Cursor',\n\t\tcommand: 'cursor',\n\t\tspecialCheck: checkCursorIdeInstalled,\n\t\tspecialVersionCheck: getCursorIdeVersion,\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\tconst match = output.match(/([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n];\n\n/**\n * Check if a CLI command is installed\n * Uses user's shell to access PATH (supports shell-installed CLIs)\n */\nexport async function isCliInstalled(command: string): Promise<boolean> {\n\ttry {\n\t\tif (process.platform === 'win32') {\n\t\t\tawait execAsync(`where ${command}`, { timeout: 2000 });\n\t\t} else {\n\t\t\t// Use which command to check PATH\n\t\t\tawait execAsync(`which ${command} 2>/dev/null`, { timeout: 2000 });\n\t\t}\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get the version of a CLI tool\n * Returns null if version cannot be determined\n */\nexport async function getCliVersion(\n\tcommand: string,\n\tversionFlag: string = '--version',\n\tparser?: (output: string) => string | null\n): Promise<string | null> {\n\ttry {\n\t\tconst result = await execAsync(`${command} ${versionFlag} 2>&1`, {\n\t\t\ttimeout: 2000,\n\t\t});\n\n\t\tconst output = result.stdout || result.stderr;\n\n\t\tif (parser) {\n\t\t\treturn parser(output);\n\t\t}\n\n\t\t// Default: return first line, trimmed\n\t\treturn output.trim().split('\\n')[0] || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Check a single CLI tool (installed status and version)\n */\nasync function checkCliTool(config: CliToolConfig): Promise<CliToolInfo> {\n\t// Use special check if provided, otherwise use standard check\n\tconst installed = config.specialCheck\n\t\t? await config.specialCheck()\n\t\t: await isCliInstalled(config.command);\n\n\tif (!installed) {\n\t\treturn {\n\t\t\tname: config.name,\n\t\t\tcommand: config.command,\n\t\t\tinstalled: false,\n\t\t};\n\t}\n\n\t// Try to get version - use special version check if provided\n\tlet version: string | undefined;\n\tif (config.specialVersionCheck) {\n\t\tconst versionStr = await config.specialVersionCheck();\n\t\tif (versionStr) {\n\t\t\tversion = versionStr;\n\t\t}\n\t} else if (config.versionFlag) {\n\t\tconst versionStr = await getCliVersion(\n\t\t\tconfig.command,\n\t\t\tconfig.versionFlag,\n\t\t\tconfig.versionParser\n\t\t);\n\t\tif (versionStr) {\n\t\t\tversion = versionStr;\n\t\t}\n\t}\n\n\treturn {\n\t\tname: config.name,\n\t\tcommand: config.command,\n\t\tinstalled: true,\n\t\tversion,\n\t};\n}\n\n/**\n * Check all configured CLI tools in parallel\n * Returns array of CLI tool information\n */\nexport async function checkInstalledCliTools(): Promise<CliToolInfo[]> {\n\ttry {\n\t\tconst results = await Promise.all(CLI_TOOLS.map(config => checkCliTool(config)));\n\t\treturn results;\n\t} catch {\n\t\t// If something goes catastrophically wrong, return empty array\n\t\t// This ensures status command never fails due to CLI detection\n\t\treturn CLI_TOOLS.map(config => ({\n\t\t\tname: config.name,\n\t\t\tcommand: config.command,\n\t\t\tinstalled: false,\n\t\t}));\n\t}\n}\n","/**\n * Package Manager Detection Utilities\n *\n * Detects package managers on different platforms:\n * - Homebrew on macOS\n * - winget on Windows (typically pre-installed on Windows 10+)\n * - apt/dnf/pacman on Linux\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\nexport interface PackageManagerInfo {\n\tname: string;\n\tcommand: string;\n\tavailable: boolean;\n}\n\n/**\n * Check if Homebrew is installed (macOS)\n */\nexport async function isHomebrewInstalled(): Promise<boolean> {\n\tif (process.platform !== 'darwin') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait execAsync('which brew', { timeout: 2000 });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if winget is available (Windows)\n * winget is pre-installed on Windows 10 (version 1809+) and Windows 11\n */\nexport async function isWingetAvailable(): Promise<boolean> {\n\tif (process.platform !== 'win32') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait execAsync('winget --version', { timeout: 2000 });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Detect available package manager on Linux\n * Returns the first available package manager found\n */\nexport async function detectLinuxPackageManager(): Promise<PackageManagerInfo | null> {\n\tif (process.platform !== 'linux') {\n\t\treturn null;\n\t}\n\n\tconst packageManagers: PackageManagerInfo[] = [\n\t\t{ name: 'apt', command: 'apt-get', available: false },\n\t\t{ name: 'dnf', command: 'dnf', available: false },\n\t\t{ name: 'yum', command: 'yum', available: false },\n\t\t{ name: 'pacman', command: 'pacman', available: false },\n\t];\n\n\tfor (const pm of packageManagers) {\n\t\ttry {\n\t\t\tawait execAsync(`which ${pm.command}`, { timeout: 2000 });\n\t\t\treturn { ...pm, available: true };\n\t\t} catch {\n\t\t\t// Package manager not found, continue checking\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Get the appropriate package manager for the current platform\n */\nexport async function detectPackageManager(): Promise<{\n\tplatform: string;\n\tpackageManager: string | null;\n\tavailable: boolean;\n}> {\n\tconst platform = process.platform;\n\n\tswitch (platform) {\n\t\tcase 'darwin': {\n\t\t\tconst hasHomebrew = await isHomebrewInstalled();\n\t\t\treturn {\n\t\t\t\tplatform: 'macOS',\n\t\t\t\tpackageManager: 'brew',\n\t\t\t\tavailable: hasHomebrew,\n\t\t\t};\n\t\t}\n\n\t\tcase 'win32': {\n\t\t\tconst hasWinget = await isWingetAvailable();\n\t\t\treturn {\n\t\t\t\tplatform: 'Windows',\n\t\t\t\tpackageManager: 'winget',\n\t\t\t\tavailable: hasWinget,\n\t\t\t};\n\t\t}\n\n\t\tcase 'linux': {\n\t\t\tconst linuxPM = await detectLinuxPackageManager();\n\t\t\treturn {\n\t\t\t\tplatform: 'Linux',\n\t\t\t\tpackageManager: linuxPM?.name || null,\n\t\t\t\tavailable: linuxPM !== null,\n\t\t\t};\n\t\t}\n\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tplatform: platform,\n\t\t\t\tpackageManager: null,\n\t\t\t\tavailable: false,\n\t\t\t};\n\t}\n}\n"],"mappings":"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","names":["exec","promisify","exec","promisify","execAsync","execAsync","promisify","exec","platform"]}
1
+ {"version":3,"sources":["../src/utils/gh-installer.ts","../src/utils/cli-tools.ts","../src/utils/package-manager-installer.ts"],"sourcesContent":["/**\n * GitHub CLI Installer Utility\n *\n * Automatically installs GitHub CLI on the user's system using platform-specific methods:\n * - macOS: Homebrew (if installed) or Webi (automated installer)\n * - Windows: winget\n * - Linux: apt/dnf/pacman (auto-detected)\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport chalk from 'chalk';\nimport { getCliVersion, isCliInstalled } from './cli-tools.js';\nimport {\n\tdetectLinuxPackageManager,\n\tisHomebrewInstalled,\n\tisWingetAvailable,\n} from './package-manager-installer.js';\n\nconst execAsync = promisify(exec);\n\nexport interface GhInstallResult {\n\tsuccess: boolean;\n\tmessage: string;\n\tversion?: string;\n}\n\n/**\n * Check if GitHub CLI is installed\n */\nexport async function isGhInstalled(): Promise<boolean> {\n\treturn isCliInstalled('gh');\n}\n\n/**\n * Get GitHub CLI version if installed\n */\nexport async function getGhVersion(): Promise<string | null> {\n\treturn getCliVersion('gh', '--version', output => {\n\t\tconst match = output.match(/gh version ([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t});\n}\n\n/**\n * Install GitHub CLI on macOS via Homebrew (when Homebrew is already installed)\n */\nasync function installViaHomebrew(): Promise<GhInstallResult> {\n\tconsole.log(chalk.blue('📦 Installing GitHub CLI via Homebrew...'));\n\n\ttry {\n\t\tawait execAsync('brew install gh', {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: chalk.red('❌ GitHub CLI installation completed but gh command not found'),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI via Homebrew\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on macOS via Webi (automated installer, no Homebrew needed)\n */\nasync function installViaWebi(): Promise<GhInstallResult> {\n\tconsole.log(chalk.blue('📦 Installing GitHub CLI via Webi...'));\n\tconsole.log(chalk.dim('This will install gh to ~/.local/bin/\\n'));\n\n\ttry {\n\t\tawait execAsync('curl -sS https://webi.sh/gh | sh', {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\t// Installation succeeded but PATH not updated yet\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage:\n\t\t\t\t\tchalk.green('✅ GitHub CLI installed successfully!\\n') +\n\t\t\t\t\tchalk.dim(\n\t\t\t\t\t\t'Note: You may need to restart your terminal for the gh command to be available.'\n\t\t\t\t\t),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI via Webi\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on macOS using best available method\n * Strategy: Use Homebrew if installed, otherwise use Webi\n */\nasync function installGhMacOS(): Promise<GhInstallResult> {\n\t// Check if Homebrew is already installed\n\tconst hasHomebrew = await isHomebrewInstalled();\n\n\tif (hasHomebrew) {\n\t\t// User already has Homebrew - use it (fast and familiar)\n\t\treturn installViaHomebrew();\n\t}\n\n\t// No Homebrew - use Webi (automated installer, no package manager needed)\n\treturn installViaWebi();\n}\n\n/**\n * Install GitHub CLI on Windows using winget\n */\nasync function installGhWindows(): Promise<GhInstallResult> {\n\t// Check if winget is available\n\tconst hasWinget = await isWingetAvailable();\n\n\tif (!hasWinget) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ winget is not available on this system\\n\\n') +\n\t\t\t\tchalk.dim('winget is included in Windows 10 (version 1809+) and Windows 11.\\n') +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n\n\tconsole.log(chalk.blue('📦 Installing GitHub CLI via winget...'));\n\n\ttry {\n\t\tawait execAsync('winget install --id GitHub.cli --silent', {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: chalk.red('❌ GitHub CLI installation completed but gh command not found'),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI via winget\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on Linux using detected package manager\n */\nasync function installGhLinux(): Promise<GhInstallResult> {\n\tconst packageManager = await detectLinuxPackageManager();\n\n\tif (!packageManager) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Could not detect a supported package manager\\n\\n') +\n\t\t\t\tchalk.dim('Supported package managers: apt, dnf, yum, pacman\\n') +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n\n\tconsole.log(chalk.blue(`📦 Installing GitHub CLI via ${packageManager.name}...`));\n\tconsole.log(chalk.dim('This may prompt for your sudo password.\\n'));\n\n\ttry {\n\t\tlet installCommand: string;\n\n\t\tswitch (packageManager.name) {\n\t\t\tcase 'apt':\n\t\t\t\t// Add GitHub CLI repository and install\n\t\t\t\tinstallCommand =\n\t\t\t\t\t'curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && ' +\n\t\t\t\t\t'sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && ' +\n\t\t\t\t\t'echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main\" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && ' +\n\t\t\t\t\t'sudo apt update && sudo apt install gh -y';\n\t\t\t\tbreak;\n\t\t\tcase 'dnf':\n\t\t\t\tinstallCommand = 'sudo dnf install gh -y';\n\t\t\t\tbreak;\n\t\t\tcase 'yum':\n\t\t\t\tinstallCommand = 'sudo yum install gh -y';\n\t\t\t\tbreak;\n\t\t\tcase 'pacman':\n\t\t\t\tinstallCommand = 'sudo pacman -S --noconfirm github-cli';\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tmessage: chalk.red(`❌ Unsupported package manager: ${packageManager.name}`),\n\t\t\t\t};\n\t\t}\n\n\t\tawait execAsync(installCommand, {\n\t\t\ttimeout: 300000, // 5 minutes\n\t\t});\n\n\t\t// Verify installation\n\t\tconst version = await getGhVersion();\n\t\tif (!version) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage: chalk.red('❌ GitHub CLI installation completed but gh command not found'),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tmessage: chalk.green(`✅ GitHub CLI installed successfully (version ${version})!`),\n\t\t\tversion,\n\t\t};\n\t} catch (error: unknown) {\n\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\tmessage:\n\t\t\t\tchalk.red('❌ Failed to install GitHub CLI\\n\\n') +\n\t\t\t\tchalk.dim('Error: ') +\n\t\t\t\terrorMsg +\n\t\t\t\t'\\n\\n' +\n\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t};\n\t}\n}\n\n/**\n * Install GitHub CLI on the current platform\n * Auto-detects platform and uses appropriate installation method\n */\nexport async function installGh(): Promise<GhInstallResult> {\n\tconst platform = process.platform;\n\n\tswitch (platform) {\n\t\tcase 'darwin':\n\t\t\treturn installGhMacOS();\n\n\t\tcase 'win32':\n\t\t\treturn installGhWindows();\n\n\t\tcase 'linux':\n\t\t\treturn installGhLinux();\n\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\tmessage:\n\t\t\t\t\tchalk.red(`❌ Unsupported platform: ${platform}\\n\\n`) +\n\t\t\t\t\tchalk.dim('Please install GitHub CLI manually from: ') +\n\t\t\t\t\tchalk.cyan('https://cli.github.com/'),\n\t\t\t};\n\t}\n}\n\n/**\n * Get manual installation instructions for the current platform\n */\nexport function getGhManualInstallInstructions(): string {\n\tconst platform = process.platform;\n\n\tswitch (platform) {\n\t\tcase 'darwin':\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation (macOS)\\n\\n') +\n\t\t\t\tchalk.dim('Option 1 - Webi (recommended, no Homebrew needed):\\n') +\n\t\t\t\tchalk.cyan(' curl -sS https://webi.sh/gh | sh\\n\\n') +\n\t\t\t\tchalk.dim('Option 2 - Homebrew:\\n') +\n\t\t\t\tchalk.cyan(' brew install gh\\n\\n') +\n\t\t\t\tchalk.dim('Option 3 - Direct download:\\n') +\n\t\t\t\tchalk.cyan(' Download from: https://cli.github.com/')\n\t\t\t);\n\n\t\tcase 'win32':\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation (Windows)\\n\\n') +\n\t\t\t\tchalk.dim('Option 1 - winget (Windows 10+):\\n') +\n\t\t\t\tchalk.cyan(' winget install --id GitHub.cli\\n\\n') +\n\t\t\t\tchalk.dim('Option 2 - Direct download:\\n') +\n\t\t\t\tchalk.cyan(' Download from: https://cli.github.com/')\n\t\t\t);\n\n\t\tcase 'linux':\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation (Linux)\\n\\n') +\n\t\t\t\tchalk.dim('Debian/Ubuntu:\\n') +\n\t\t\t\tchalk.cyan(\n\t\t\t\t\t' See instructions at: https://github.com/cli/cli/blob/trunk/docs/install_linux.md#debian-ubuntu-linux-raspberry-pi-os-apt\\n\\n'\n\t\t\t\t) +\n\t\t\t\tchalk.dim('Fedora/RHEL:\\n') +\n\t\t\t\tchalk.cyan(' sudo dnf install gh\\n\\n') +\n\t\t\t\tchalk.dim('Arch Linux:\\n') +\n\t\t\t\tchalk.cyan(' sudo pacman -S github-cli\\n\\n') +\n\t\t\t\tchalk.dim('Or download from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/')\n\t\t\t);\n\n\t\tdefault:\n\t\t\treturn (\n\t\t\t\tchalk.yellow('📖 Manual GitHub CLI Installation\\n\\n') +\n\t\t\t\tchalk.dim('Download from: ') +\n\t\t\t\tchalk.cyan('https://cli.github.com/')\n\t\t\t);\n\t}\n}\n","/**\n * CLI Tools Detection Utilities\n *\n * Detects installed AI coding tools and CLI utilities:\n * - Checks if common AI IDE CLIs are installed\n * - Gets version information where available\n * - Cross-platform support (macOS, Linux, Windows)\n */\n\nimport { exec } from 'node:child_process';\nimport { access, constants } from 'node:fs/promises';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\n// Claude Code local installation path after migrate-installer\nconst CLAUDE_LOCAL_PATH = join(homedir(), '.claude', 'local', 'claude');\n\nexport interface CliToolInfo {\n\tname: string; // Display name (e.g., \"GitHub CLI\")\n\tcommand: string; // Command to check (e.g., \"gh\")\n\tinstalled: boolean; // Whether it's installed\n\tversion?: string; // Version string if available\n}\n\ninterface CliToolConfig {\n\tname: string;\n\tcommand: string;\n\tversionFlag?: string;\n\tversionParser?: (output: string) => string | null;\n\tspecialCheck?: () => Promise<boolean>;\n\tspecialVersionCheck?: () => Promise<string | null>;\n}\n\n/**\n * Check if Claude Code is installed\n * Special handling for Claude CLI after `claude migrate-installer`\n *\n * The migrate-installer command moves the Claude Code executable from PATH\n * to ~/.claude/local/claude, so standard PATH checks fail.\n *\n * Detection priority:\n * 1. Check ~/.claude/local/claude (after migrate-installer)\n * 2. Try executing `claude --version` (may work via shell alias)\n * 3. Check PATH with `which claude`\n */\nasync function checkClaudeInstalled(): Promise<boolean> {\n\t// Priority 1: Check ~/.claude/local/claude (after migrate-installer)\n\ttry {\n\t\tawait access(CLAUDE_LOCAL_PATH, constants.X_OK);\n\t\treturn true;\n\t} catch {\n\t\t// Fall through to next check\n\t}\n\n\t// Priority 2: Try executing claude --version (may work via shell alias)\n\ttry {\n\t\tawait execAsync('claude --version 2>&1', { timeout: 2000 });\n\t\treturn true;\n\t} catch {\n\t\t// Fall through to PATH check\n\t}\n\n\t// Priority 3: Check PATH with which\n\treturn isCliInstalled('claude');\n}\n\n/**\n * Get Claude Code version\n * Tries local path first, then falls back to standard version check\n */\nasync function getClaudeVersion(): Promise<string | null> {\n\t// Try local path first\n\ttry {\n\t\tawait access(CLAUDE_LOCAL_PATH, constants.X_OK);\n\t\tconst result = await execAsync(`\"${CLAUDE_LOCAL_PATH}\" --version 2>&1`, {\n\t\t\ttimeout: 2000,\n\t\t});\n\t\tconst output = result.stdout || result.stderr;\n\t\tconst match = output.match(/([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t} catch {\n\t\t// Fall through to regular version check\n\t}\n\n\t// Fall back to regular claude command\n\treturn getCliVersion('claude', '--version', output => {\n\t\tconst match = output.match(/([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t});\n}\n\n/**\n * Get platform-specific Cursor IDE application paths\n */\nfunction getCursorAppPaths(): string[] {\n\tconst paths: string[] = [];\n\tconst home = homedir();\n\n\tswitch (platform()) {\n\t\tcase 'darwin': // macOS\n\t\t\tpaths.push('/Applications/Cursor.app');\n\t\t\tpaths.push(join(home, 'Library/Application Support/Cursor'));\n\t\t\tbreak;\n\n\t\tcase 'win32': {\n\t\t\t// Windows\n\t\t\tconst localAppData = process.env.LOCALAPPDATA || join(home, 'AppData', 'Local');\n\t\t\tconst appData = process.env.APPDATA || join(home, 'AppData', 'Roaming');\n\t\t\tpaths.push(join(localAppData, 'Programs', 'Cursor'));\n\t\t\tpaths.push(join(appData, 'Cursor'));\n\t\t\tbreak;\n\t\t}\n\n\t\tcase 'linux':\n\t\t\t// Linux: Check config directory (most reliable for AppImage)\n\t\t\tpaths.push(join(home, '.config', 'Cursor'));\n\t\t\tpaths.push(join(home, '.cursor'));\n\t\t\t// Common AppImage locations\n\t\t\tpaths.push('/opt/cursor.appimage');\n\t\t\tpaths.push('/usr/local/bin/cursor.appimage');\n\t\t\tbreak;\n\t}\n\n\treturn paths;\n}\n\n/**\n * Check if Cursor IDE is installed\n * Checks platform-specific application paths and config directories\n */\nasync function checkCursorIdeInstalled(): Promise<boolean> {\n\tconst paths = getCursorAppPaths();\n\n\t// Try each path\n\tfor (const path of paths) {\n\t\ttry {\n\t\t\tawait access(path);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// Continue to next path\n\t\t}\n\t}\n\n\t// Fallback: Check if cursor CLI is available\n\treturn isCliInstalled('cursor');\n}\n\n/**\n * Get Cursor IDE version\n * Falls back to CLI version if app version unavailable\n */\nasync function getCursorIdeVersion(): Promise<string | null> {\n\t// Try CLI version first (simplest)\n\tconst cliVersion = await getCliVersion('cursor', '--version', output => {\n\t\tconst match = output.match(/([\\d.]+)/);\n\t\treturn match ? match[1] : null;\n\t});\n\n\treturn cliVersion;\n}\n\nconst CLI_TOOLS: CliToolConfig[] = [\n\t{\n\t\tname: 'Git',\n\t\tcommand: 'git',\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\tconst match = output.match(/git version ([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n\t{\n\t\tname: 'GitHub CLI',\n\t\tcommand: 'gh',\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\tconst match = output.match(/gh version ([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n\t{\n\t\tname: 'jq',\n\t\tcommand: 'jq',\n\t\tversionFlag: '--version',\n\t\tversionParser: output => output.match(/jq-([\\d.]+)/)?.[1] || output.trim(),\n\t},\n\t{\n\t\tname: 'Claude Code',\n\t\tcommand: 'claude',\n\t\tspecialCheck: checkClaudeInstalled,\n\t\tspecialVersionCheck: getClaudeVersion,\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\t// Output format: \"2.0.1 (Claude Code)\"\n\t\t\tconst match = output.match(/([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n\t{\n\t\tname: 'Cursor',\n\t\tcommand: 'cursor',\n\t\tspecialCheck: checkCursorIdeInstalled,\n\t\tspecialVersionCheck: getCursorIdeVersion,\n\t\tversionFlag: '--version',\n\t\tversionParser: output => {\n\t\t\tconst match = output.match(/([\\d.]+)/);\n\t\t\treturn match ? match[1] : null;\n\t\t},\n\t},\n];\n\n/**\n * Check if a CLI command is installed\n * Uses user's shell to access PATH (supports shell-installed CLIs)\n */\nexport async function isCliInstalled(command: string): Promise<boolean> {\n\ttry {\n\t\tif (process.platform === 'win32') {\n\t\t\tawait execAsync(`where ${command}`, { timeout: 2000 });\n\t\t} else {\n\t\t\t// Use which command to check PATH\n\t\t\tawait execAsync(`which ${command} 2>/dev/null`, { timeout: 2000 });\n\t\t}\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get the version of a CLI tool\n * Returns null if version cannot be determined\n */\nexport async function getCliVersion(\n\tcommand: string,\n\tversionFlag: string = '--version',\n\tparser?: (output: string) => string | null\n): Promise<string | null> {\n\ttry {\n\t\tconst result = await execAsync(`${command} ${versionFlag} 2>&1`, {\n\t\t\ttimeout: 2000,\n\t\t});\n\n\t\tconst output = result.stdout || result.stderr;\n\n\t\tif (parser) {\n\t\t\treturn parser(output);\n\t\t}\n\n\t\t// Default: return first line, trimmed\n\t\treturn output.trim().split('\\n')[0] || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Check a single CLI tool (installed status and version)\n */\nasync function checkCliTool(config: CliToolConfig): Promise<CliToolInfo> {\n\t// Use special check if provided, otherwise use standard check\n\tconst installed = config.specialCheck\n\t\t? await config.specialCheck()\n\t\t: await isCliInstalled(config.command);\n\n\tif (!installed) {\n\t\treturn {\n\t\t\tname: config.name,\n\t\t\tcommand: config.command,\n\t\t\tinstalled: false,\n\t\t};\n\t}\n\n\t// Try to get version - use special version check if provided\n\tlet version: string | undefined;\n\tif (config.specialVersionCheck) {\n\t\tconst versionStr = await config.specialVersionCheck();\n\t\tif (versionStr) {\n\t\t\tversion = versionStr;\n\t\t}\n\t} else if (config.versionFlag) {\n\t\tconst versionStr = await getCliVersion(\n\t\t\tconfig.command,\n\t\t\tconfig.versionFlag,\n\t\t\tconfig.versionParser\n\t\t);\n\t\tif (versionStr) {\n\t\t\tversion = versionStr;\n\t\t}\n\t}\n\n\treturn {\n\t\tname: config.name,\n\t\tcommand: config.command,\n\t\tinstalled: true,\n\t\tversion,\n\t};\n}\n\n/**\n * Check all configured CLI tools in parallel\n * Returns array of CLI tool information\n */\nexport async function checkInstalledCliTools(): Promise<CliToolInfo[]> {\n\ttry {\n\t\tconst results = await Promise.all(CLI_TOOLS.map(config => checkCliTool(config)));\n\t\treturn results;\n\t} catch {\n\t\t// If something goes catastrophically wrong, return empty array\n\t\t// This ensures status command never fails due to CLI detection\n\t\treturn CLI_TOOLS.map(config => ({\n\t\t\tname: config.name,\n\t\t\tcommand: config.command,\n\t\t\tinstalled: false,\n\t\t}));\n\t}\n}\n","/**\n * Package Manager Detection Utilities\n *\n * Detects package managers on different platforms:\n * - Homebrew on macOS\n * - winget on Windows (typically pre-installed on Windows 10+)\n * - apt/dnf/pacman on Linux\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\nexport interface PackageManagerInfo {\n\tname: string;\n\tcommand: string;\n\tavailable: boolean;\n}\n\n/**\n * Check if Homebrew is installed (macOS)\n */\nexport async function isHomebrewInstalled(): Promise<boolean> {\n\tif (process.platform !== 'darwin') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait execAsync('which brew', { timeout: 2000 });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if winget is available (Windows)\n * winget is pre-installed on Windows 10 (version 1809+) and Windows 11\n */\nexport async function isWingetAvailable(): Promise<boolean> {\n\tif (process.platform !== 'win32') {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tawait execAsync('winget --version', { timeout: 2000 });\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Detect available package manager on Linux\n * Returns the first available package manager found\n */\nexport async function detectLinuxPackageManager(): Promise<PackageManagerInfo | null> {\n\tif (process.platform !== 'linux') {\n\t\treturn null;\n\t}\n\n\tconst packageManagers: PackageManagerInfo[] = [\n\t\t{ name: 'apt', command: 'apt-get', available: false },\n\t\t{ name: 'dnf', command: 'dnf', available: false },\n\t\t{ name: 'yum', command: 'yum', available: false },\n\t\t{ name: 'pacman', command: 'pacman', available: false },\n\t];\n\n\tfor (const pm of packageManagers) {\n\t\ttry {\n\t\t\tawait execAsync(`which ${pm.command}`, { timeout: 2000 });\n\t\t\treturn { ...pm, available: true };\n\t\t} catch {\n\t\t\t// Package manager not found, continue checking\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Get the appropriate package manager for the current platform\n */\nexport async function detectPackageManager(): Promise<{\n\tplatform: string;\n\tpackageManager: string | null;\n\tavailable: boolean;\n}> {\n\tconst platform = process.platform;\n\n\tswitch (platform) {\n\t\tcase 'darwin': {\n\t\t\tconst hasHomebrew = await isHomebrewInstalled();\n\t\t\treturn {\n\t\t\t\tplatform: 'macOS',\n\t\t\t\tpackageManager: 'brew',\n\t\t\t\tavailable: hasHomebrew,\n\t\t\t};\n\t\t}\n\n\t\tcase 'win32': {\n\t\t\tconst hasWinget = await isWingetAvailable();\n\t\t\treturn {\n\t\t\t\tplatform: 'Windows',\n\t\t\t\tpackageManager: 'winget',\n\t\t\t\tavailable: hasWinget,\n\t\t\t};\n\t\t}\n\n\t\tcase 'linux': {\n\t\t\tconst linuxPM = await detectLinuxPackageManager();\n\t\t\treturn {\n\t\t\t\tplatform: 'Linux',\n\t\t\t\tpackageManager: linuxPM?.name || null,\n\t\t\t\tavailable: linuxPM !== null,\n\t\t\t};\n\t\t}\n\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tplatform: platform,\n\t\t\t\tpackageManager: null,\n\t\t\t\tavailable: false,\n\t\t\t};\n\t}\n}\n"],"mappings":"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","names":["exec","promisify","exec","promisify","execAsync","execAsync","promisify","exec","platform"]}