{"version":3,"file":"shell-utils.mjs","names":[],"sources":["../../src/util/shell-utils.ts"],"sourcesContent":["/**\n * Convert a camelCase string to kebab-case.\n * Returns null if the string has no uppercase letters (no conversion needed).\n */\nexport function camelToKebab(str: string): string | null {\n  if (!/[A-Z]/.test(str)) return null;\n  return str.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);\n}\n\nexport type ShellType = 'bash' | 'zsh' | 'fish' | 'powershell';\n\n/**\n * Detects the current shell from environment variables and process info.\n * @returns The detected shell type, or undefined if unknown\n */\nexport async function detectShell(): Promise<ShellType | undefined> {\n  if (typeof process === 'undefined') return undefined;\n\n  // Method 1: Check SHELL environment variable (most common)\n  const shellEnv = process.env.SHELL || '';\n  if (shellEnv.includes('zsh')) return 'zsh';\n  if (shellEnv.includes('bash')) return 'bash';\n  if (shellEnv.includes('fish')) return 'fish';\n\n  // Method 2: Check Windows-specific shells\n  if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {\n    return 'powershell';\n  }\n\n  // Method 3: Check parent process on Unix-like systems\n  try {\n    const ppid = process.ppid;\n    if (ppid) {\n      const { execSync } = (await import('node:child_process')) as typeof import('node:child_process');\n      const processName = execSync(`ps -p ${ppid} -o comm=`, {\n        encoding: 'utf-8',\n        stdio: ['pipe', 'pipe', 'ignore'],\n      }).trim();\n\n      if (processName.includes('zsh')) return 'zsh';\n      if (processName.includes('bash')) return 'bash';\n      if (processName.includes('fish')) return 'fish';\n    }\n  } catch {\n    // Ignore errors (e.g., ps not available)\n  }\n\n  return undefined;\n}\n\nexport async function getRcFile(shell: ShellType, home?: string): Promise<string | null> {\n  const { homedir } = await import('node:os');\n  const { join } = await import('node:path');\n  const h = home ?? homedir();\n  switch (shell) {\n    case 'bash':\n      return join(h, '.bashrc');\n    case 'zsh':\n      return join(h, '.zshrc');\n    case 'fish':\n      return join(h, '.config', 'fish', 'config.fish');\n    case 'powershell':\n      return (\n        (typeof process !== 'undefined' ? process.env.PROFILE : undefined) ||\n        join(h, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1')\n      );\n    default:\n      return null;\n  }\n}\n\nexport function escapeRegExp(str: string): string {\n  return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Writes a snippet to a shell config file using begin/end markers for idempotency.\n * If a block with the same begin marker exists, it is replaced. Otherwise the snippet is appended.\n */\nexport async function writeToRcFile(\n  rcFile: string,\n  snippet: string,\n  beginMarker: string,\n  endMarker: string,\n): Promise<{ file: string; updated: boolean }> {\n  const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import('node:fs');\n  const { dirname } = await import('node:path');\n  const existing = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';\n\n  if (existing.includes(beginMarker)) {\n    const pattern = new RegExp(`${escapeRegExp(beginMarker)}[\\\\s\\\\S]*?${escapeRegExp(endMarker)}`);\n    writeFileSync(rcFile, existing.replace(pattern, snippet));\n    return { file: rcFile, updated: true };\n  }\n\n  mkdirSync(dirname(rcFile), { recursive: true });\n  const separator = existing.length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n  writeFileSync(rcFile, `${existing}${separator}\\n${snippet}\\n`);\n  return { file: rcFile, updated: false };\n}\n"],"mappings":";;;;;AAIA,SAAgB,aAAa,KAA4B;CACvD,IAAI,CAAC,QAAQ,KAAK,GAAG,GAAG,OAAO;CAC/B,OAAO,IAAI,QAAQ,WAAW,OAAO,IAAI,GAAG,YAAY,GAAG;AAC7D;;;;;AAQA,eAAsB,cAA8C;CAClE,IAAI,OAAO,YAAY,aAAa,OAAO,KAAA;CAG3C,MAAM,WAAW,QAAQ,IAAI,SAAS;CACtC,IAAI,SAAS,SAAS,KAAK,GAAG,OAAO;CACrC,IAAI,SAAS,SAAS,MAAM,GAAG,OAAO;CACtC,IAAI,SAAS,SAAS,MAAM,GAAG,OAAO;CAGtC,IAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,iCAC1C,OAAO;CAIT,IAAI;EACF,MAAM,OAAO,QAAQ;EACrB,IAAI,MAAM;GACR,MAAM,EAAE,aAAc,MAAM,OAAO;GACnC,MAAM,cAAc,SAAS,SAAS,KAAK,YAAY;IACrD,UAAU;IACV,OAAO;KAAC;KAAQ;KAAQ;IAAQ;GAClC,CAAC,CAAC,CAAC,KAAK;GAER,IAAI,YAAY,SAAS,KAAK,GAAG,OAAO;GACxC,IAAI,YAAY,SAAS,MAAM,GAAG,OAAO;GACzC,IAAI,YAAY,SAAS,MAAM,GAAG,OAAO;EAC3C;CACF,QAAQ,CAER;AAGF;AAEA,eAAsB,UAAU,OAAkB,MAAuC;CACvF,MAAM,EAAE,YAAY,MAAM,OAAO;CACjC,MAAM,EAAE,SAAS,MAAM,OAAO;CAC9B,MAAM,IAAI,QAAQ,QAAQ;CAC1B,QAAQ,OAAR;EACE,KAAK,QACH,OAAO,KAAK,GAAG,SAAS;EAC1B,KAAK,OACH,OAAO,KAAK,GAAG,QAAQ;EACzB,KAAK,QACH,OAAO,KAAK,GAAG,WAAW,QAAQ,aAAa;EACjD,KAAK,cACH,QACG,OAAO,YAAY,cAAc,QAAQ,IAAI,UAAU,KAAA,MACxD,KAAK,GAAG,aAAa,cAAc,kCAAkC;EAEzE,SACE,OAAO;CACX;AACF;AAEA,SAAgB,aAAa,KAAqB;CAChD,OAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;;;;;AAMA,eAAsB,cACpB,QACA,SACA,aACA,WAC6C;CAC7C,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,MAAM,OAAO;CAC5E,MAAM,EAAE,YAAY,MAAM,OAAO;CACjC,MAAM,WAAW,WAAW,MAAM,IAAI,aAAa,QAAQ,OAAO,IAAI;CAEtE,IAAI,SAAS,SAAS,WAAW,GAAG;EAClC,MAAM,UAAU,IAAI,OAAO,GAAG,aAAa,WAAW,EAAE,YAAY,aAAa,SAAS,GAAG;EAC7F,cAAc,QAAQ,SAAS,QAAQ,SAAS,OAAO,CAAC;EACxD,OAAO;GAAE,MAAM;GAAQ,SAAS;EAAK;CACvC;CAEA,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;CAE9C,cAAc,QAAQ,GAAG,WADP,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,IAAI,IAAI,OAAO,GAC7B,IAAI,QAAQ,GAAG;CAC7D,OAAO;EAAE,MAAM;EAAQ,SAAS;CAAM;AACxC"}