| 89 | } |
| 90 | |
| 91 | function getDefaultShell(): string { |
| 92 | if (os.platform() === "win32") { |
| 93 | // On Windows, prefer COMSPEC (cmd.exe) or PowerShell |
| 94 | const comspec = process.env.COMSPEC |
| 95 | if (comspec && fs.existsSync(comspec)) { |
| 96 | logger.info("[Pty] Using Windows shell from COMSPEC:", JSON.stringify({ shell: comspec })) |
| 97 | return comspec |
| 98 | } |
| 99 | // Fall back to PowerShell |
| 100 | logger.info("[Pty] Using Windows PowerShell") |
| 101 | return "powershell.exe" |
| 102 | } |
| 103 | |
| 104 | // Unix: use SHELL env var with fallback cascade |
| 105 | const shellEnv = process.env.SHELL |
| 106 | if (shellEnv && fs.existsSync(shellEnv)) { |
| 107 | logger.info("[Pty] Using shell from SHELL env:", JSON.stringify({ shell: shellEnv })) |
| 108 | return shellEnv |
| 109 | } |
| 110 | |
| 111 | // Fallback cascade for Unix systems |
| 112 | const fallbacks = ["/bin/bash", "/bin/zsh", "/bin/sh"] |
| 113 | for (const fallback of fallbacks) { |
| 114 | if (fs.existsSync(fallback)) { |
| 115 | logger.info("[Pty] Using fallback shell:", JSON.stringify({ shell: fallback })) |
| 116 | return fallback |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | // Last resort - will likely fail but at least log it |
| 121 | logger.warn("[Pty] No shell found, defaulting to /bin/sh") |
| 122 | return "/bin/sh" |
| 123 | } |
| 124 | |
| 125 | function emitLifecycle(event: PtyLifecycleEvent): void { |
| 126 | for (const listener of lifecycleListeners) { |