UNPKG

detect-terminal

Version:

Detect the terminal program currently being used, with support for iTerm, Terminal.app, Hyper, iTerm2, ConEmu, Cmde,r Alacritty, Xterm, Terminator, Termux, Kitty, and others. Detection is based on environment variables and process-level indicators to iden

753 lines (746 loc) 20.9 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/color.ts var TRUE_COLOR_PATTERN = /^(truecolor|24bits?)$/; var has256Color = /* @__PURE__ */ __name((value) => { return Boolean(value?.match(/256/)); }, "has256Color"); var supportsTrueColor = /* @__PURE__ */ __name((value) => { return Boolean(value?.match(TRUE_COLOR_PATTERN)); }, "supportsTrueColor"); var getColorSupport = /* @__PURE__ */ __name((env) => { return { supports256Color: has256Color(env.TERM) || has256Color(env.COLORTERM), supportsTrueColor: supportsTrueColor(env.COLORTERM) }; }, "getColorSupport"); var NO_BASIC_COLOR_TERMINALS = /* @__PURE__ */ new Set([ "dumb", "linux_console", "none", "unknown", "vt100" ]); var getColorLevel = /* @__PURE__ */ __name((env, terminal, colorSupport = getColorSupport(env)) => { const { supports256Color, supportsTrueColor: supportsTrueColor2 } = colorSupport; if (supportsTrueColor2) { return 3; } if (supports256Color) { return 2; } if (terminal && !NO_BASIC_COLOR_TERMINALS.has(terminal)) { return 1; } if (env.TERM_PROGRAM || env.COLORTERM || env.TERMUX_VERSION) { return 1; } return 0; }, "getColorLevel"); // src/normalize.ts import path from "path"; var AMBIGUOUS_ENV_TERMINALS = /* @__PURE__ */ new Set([ "linux_console", "truecolor_terminal", "vt100", "xterm", "xterm_256color", "xterm_truecolor" ]); var SHELL_PROCESS_NAMES = /* @__PURE__ */ new Set([ "bash", "csh", "dash", "fish", "ksh", "login", "node", "nodejs", "nu", "sh", "sudo", "tcsh", "zsh" ]); var normalizeIdentifier = /* @__PURE__ */ __name((value) => { return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_"); }, "normalizeIdentifier"); var normalizeAppName = /* @__PURE__ */ __name((value, platform) => { const appName = platform === "darwin" ? path.parse(value).name : value; return normalizeIdentifier(appName); }, "normalizeAppName"); var isAmbiguousEnvResult = /* @__PURE__ */ __name((terminal, options = {}) => { if (!terminal) { return true; } if (options.preferOuter && (terminal === "tmux" || terminal === "screen")) { return true; } return AMBIGUOUS_ENV_TERMINALS.has(terminal); }, "isAmbiguousEnvResult"); var hasKonsoleEnvironment = /* @__PURE__ */ __name((env) => { return Object.keys(env).some((envVar) => /konsole/i.test(envVar)); }, "hasKonsoleEnvironment"); var normalizeParentProcessName = /* @__PURE__ */ __name((processName) => { const normalized = normalizeIdentifier(path.parse(processName).name); switch (normalized) { case "alacritty": case "aterm": case "atomic_terminal": case "eterm": case "foot": case "ghostty": case "hyper": case "kitty": case "konsole": case "kuake": case "mate_terminal": case "mrxvt": case "powershell": case "putty": case "qterminal": case "rio": case "rxvt": case "terminator": case "terminology": case "tilda": case "tmux": case "warp": case "wezterm": case "wterm": return normalized; case "apple_terminal": case "terminal": return "terminal"; case "cmd": return "cmd"; case "code": case "code_insiders": return "vscode"; case "conhost": return "conhost"; case "gnome": case "gnome_terminal": case "gnome_terminal_server": case "guake": return "gnome_terminal"; case "iterm": case "iterm2": return "iterm"; case "login": case "linux": return "linux_console"; case "pwsh": return "powershell"; case "screen": return "screen"; case "terminal_app": return "terminal_app"; case "urxvt": case "urxvt256c": case "urxvt256c_ml": case "urxvt_ml": return "rxvt"; case "wt": case "windows_terminal": return "windows_terminal"; case "xfce": case "xfce_terminal": case "xfce4_terminal": return "xfce4_terminal"; default: { if (normalized.startsWith("gnome_terminal")) { return "gnome_terminal"; } if (normalized.startsWith("warp")) { return "warp"; } return null; } } }, "normalizeParentProcessName"); // src/env.ts var colorVariant = /* @__PURE__ */ __name((terminal, supports256Color, supportsTrueColor2) => { return supports256Color || supportsTrueColor2 ? `${terminal}_256color` : terminal; }, "colorVariant"); var normalizeTermProgram = /* @__PURE__ */ __name((termProgram) => { switch (termProgram) { case "apple_terminal": return "terminal"; case "eterm": return "eterm"; case "gnome_terminal": case "gnome_terminal_server": return "gnome_terminal"; case "hyper": return "hyper"; case "iterm_app": case "iterm": case "iterm2": return "iterm"; case "kitty": return "kitty"; case "konsole": return "konsole"; case "mate_terminal": return "mate_terminal"; case "powershell": return "powershell"; case "putty": return "putty"; case "qterminal": return "qterminal"; case "rio": return "rio"; case "rxvt": return "rxvt"; case "terminal_app": return "terminal_app"; case "terminal": return "terminal"; case "terminator": return "terminator"; case "termux": return "termux"; case "vscode": return "vscode"; case "warp": return "warp"; case "wezterm": return "wezterm"; case "xfce4_terminal": return "xfce4_terminal"; case "alacritty": return "alacritty"; default: return null; } }, "normalizeTermProgram"); var detectFromTerm = /* @__PURE__ */ __name((term, env, platform) => { const { supports256Color, supportsTrueColor: supportsTrueColor2 } = getColorSupport(env); if (term === "xterm" || term === "xterm_256color") { if (supportsTrueColor2) { return "xterm_truecolor"; } if (env.VTE_VERSION) { const vteVersion = Number.parseInt(env.VTE_VERSION, 10); if (vteVersion >= 3803) { return colorVariant("gnome_terminal", supports256Color, supportsTrueColor2); } } if (hasKonsoleEnvironment(env)) { return colorVariant("konsole", supports256Color, supportsTrueColor2); } if (platform === "darwin") { return "terminal"; } return term; } switch (term) { case "linux": return "linux_console"; case "gnome": case "gnome_256color": case "gnome_terminal": case "gnome_terminal_256color": case "guake": case "terminator": return colorVariant("gnome_terminal", supports256Color, supportsTrueColor2); case "konsole": return colorVariant("konsole", supports256Color, supportsTrueColor2); case "rxvt": case "rxvt_xpm": case "rxvt_unicode": case "rxvt_unicode_256color": case "urxvt": case "urxvt_ml": case "urxvt256c": case "urxvt256c_ml": return colorVariant("rxvt", term === "rxvt" || supports256Color, supportsTrueColor2); case "xfce": case "xfce_terminal": case "xfce4_terminal": return "xfce4_terminal"; case "eterm": return colorVariant("eterm", supports256Color, supportsTrueColor2); case "xterm_kitty": case "kitty": return "kitty"; case "screen": case "screen_256color": return "screen"; case "tmux": case "tmux_256color": return "tmux"; case "vt100": return "vt100"; case "aterm": case "atomic_terminal": case "dopamine": case "foot": case "ghostty": case "kuake": case "rio": case "terminology": case "termux": case "tilda": case "wterm": case "mrxvt": return term; default: if (/screen/.test(term)) return "screen"; if (/tmux/.test(term)) return "tmux"; if (/rxvt/.test(term)) return "rxvt"; if (/vt100/.test(term)) return "vt100"; if (/linux/.test(term)) return "linux_console"; if (/alacritty/.test(term)) return "alacritty"; if (/dopamine/.test(term)) return "dopamine"; if (/kitty/.test(term)) return "kitty"; if (/ghostty/.test(term)) return "ghostty"; if (/^foot/.test(term)) return "foot"; if (/^rio/.test(term)) return "rio"; return term; } }, "detectFromTerm"); var detectFromEnvResult = /* @__PURE__ */ __name((options = {}) => { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; const term = env.TERM ? normalizeIdentifier(env.TERM) : void 0; if (platform === "android" && env.TERMUX_VERSION) { return { terminal: "termux", source: "env", generic: term }; } if (!options.preferOuter && term) { if (term.startsWith("tmux")) { return { terminal: "tmux", source: "env", generic: term }; } if (term.startsWith("screen")) { return { terminal: "screen", source: "env", generic: term }; } } if (env.KITTY_PID) { return { terminal: "kitty", source: "env", generic: term }; } if (env.GHOSTTY_RESOURCES_DIR) { return { terminal: "ghostty", source: "env", generic: term }; } if (env.ALACRITTY_SOCKET || env.ALACRITTY_LOG) { return { terminal: "alacritty", source: "env", generic: term }; } const termProgram = env.TERM_PROGRAM ? normalizeAppName(env.TERM_PROGRAM, platform) : void 0; if (termProgram) { return { terminal: normalizeTermProgram(termProgram) ?? termProgram, source: "env", generic: term }; } if (typeof env.VSCODE_PID !== "undefined" || typeof env.TERM_PROGRAM_VERSION !== "undefined" && /vscode/i.test(env.TERM_PROGRAM_VERSION)) { return { terminal: "vscode", source: "env", generic: term }; } if (term && term !== "unknown") { return { terminal: detectFromTerm(term, env, platform), source: "env", generic: term }; } const colorTerm = env.COLORTERM ? normalizeIdentifier(env.COLORTERM) : void 0; if (colorTerm === "truecolor" || colorTerm === "24bit" || colorTerm === "24bits") { return { terminal: "truecolor_terminal", source: "env", generic: term }; } if (colorTerm) { return { terminal: colorTerm, source: "env", generic: term }; } return null; }, "detectFromEnvResult"); var detectFromEnv = /* @__PURE__ */ __name((options = {}) => { return detectFromEnvResult(options)?.terminal ?? null; }, "detectFromEnv"); // src/parent.ts import { execFileSync as nodeExecFileSync } from "child_process"; var runPs = /* @__PURE__ */ __name((run, args) => { return run("ps", args, { encoding: "utf8", timeout: 1e3, stdio: ["ignore", "pipe", "ignore"] }); }, "runPs"); var getParentProcess = /* @__PURE__ */ __name((pid, options = {}) => { const run = options.execFileSync ?? nodeExecFileSync; const parentPid = Number.parseInt( runPs(run, ["-o", "ppid=", "-p", String(pid)]).trim(), 10 ); if (!Number.isFinite(parentPid) || parentPid <= 1) { return null; } const appName = runPs(run, ["-o", "comm=", "-p", String(parentPid)]).trim(); if (!appName) { return null; } return { pid: parentPid, appName }; }, "getParentProcess"); var colorVariant2 = /* @__PURE__ */ __name((terminal, supports256Color, supportsTrueColor2) => { return supports256Color || supportsTrueColor2 ? `${terminal}_256color` : terminal; }, "colorVariant"); var applyParentColorVariant = /* @__PURE__ */ __name((terminal, env) => { const { supports256Color, supportsTrueColor: supportsTrueColor2 } = getColorSupport(env); switch (terminal) { case "eterm": case "konsole": case "rxvt": return colorVariant2(terminal, supports256Color, supportsTrueColor2); case "gnome_terminal": case "terminator": return colorVariant2("gnome_terminal", supports256Color, supportsTrueColor2); default: return terminal; } }, "applyParentColorVariant"); var detectFromParentProcessResult = /* @__PURE__ */ __name((options = {}) => { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; if (platform === "win32" || env.SSH_CONNECTION) { return null; } const seenPids = /* @__PURE__ */ new Set(); let pid = options.pid ?? process.pid; for (let depth = 0; depth < 12; depth += 1) { if (seenPids.has(pid)) { break; } seenPids.add(pid); try { const parent = getParentProcess(pid, options); if (!parent) { break; } const normalized = normalizeParentProcessName(parent.appName); if (normalized === "screen" || normalized === "tmux") { if (!options.preferOuter) { return { terminal: normalized, source: "parent", appName: parent.appName, pid: parent.pid }; } pid = parent.pid; continue; } if (normalized) { return { terminal: applyParentColorVariant(normalized, env), source: "parent", appName: parent.appName, pid: parent.pid }; } if (!SHELL_PROCESS_NAMES.has(normalizeIdentifier(parent.appName))) { break; } pid = parent.pid; } catch { break; } } return null; }, "detectFromParentProcessResult"); var detectFromParentProcess = /* @__PURE__ */ __name((options = {}) => { return detectFromParentProcessResult(options)?.terminal ?? null; }, "detectFromParentProcess"); // src/process-title.ts var detectFromProcessTitleResult = /* @__PURE__ */ __name((options = {}) => { const processTitle = (options.processTitle ?? process.title)?.toLowerCase() ?? ""; if (/^alacritty/.test(processTitle)) { return { terminal: "alacritty", source: "process_title" }; } if (/^kitty/.test(processTitle)) { return { terminal: "kitty", source: "process_title" }; } if (/^wezterm/.test(processTitle)) { return { terminal: "wezterm", source: "process_title" }; } if (/^hyper/.test(processTitle)) { return { terminal: "hyper", source: "process_title" }; } if (/^foot/.test(processTitle)) { return { terminal: "foot", source: "process_title" }; } if (/^rio/.test(processTitle)) { return { terminal: "rio", source: "process_title" }; } if (/^ghostty/.test(processTitle)) { return { terminal: "ghostty", source: "process_title" }; } if (/bash/.test(processTitle)) { return { terminal: "bash", source: "process_title" }; } if (/zsh/.test(processTitle)) { return { terminal: "zsh", source: "process_title" }; } if (/ksh/.test(processTitle)) { return { terminal: "ksh", source: "process_title" }; } if (/fish/.test(processTitle)) { return { terminal: "fish", source: "process_title" }; } if (/csh/.test(processTitle)) { return { terminal: "csh", source: "process_title" }; } if (/tcsh/.test(processTitle)) { return { terminal: "tcsh", source: "process_title" }; } if (/pwsh/.test(processTitle)) { return { terminal: "powershell", source: "process_title" }; } if (/powershell/.test(processTitle)) { return { terminal: "powershell", source: "process_title" }; } if (/cmd/.test(processTitle)) { return { terminal: "cmd", source: "process_title" }; } if (/sh$/.test(processTitle)) { return { terminal: "sh", source: "process_title" }; } if (/^node/.test(processTitle)) { return { terminal: "node", source: "process_title" }; } return null; }, "detectFromProcessTitleResult"); var detectFromProcessTitle = /* @__PURE__ */ __name(() => { return detectFromProcessTitleResult()?.terminal ?? null; }, "detectFromProcessTitle"); // src/shell.ts import { execFileSync as nodeExecFileSync2 } from "child_process"; var runShellTerm = /* @__PURE__ */ __name((run) => { return run("sh", ["-c", 'printf %s "$TERM"'], { encoding: "utf8", timeout: 1e3, stdio: ["ignore", "pipe", "ignore"] }); }, "runShellTerm"); var detectFromShellResult = /* @__PURE__ */ __name((options = {}) => { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; try { if (platform === "win32") { if (env.WT_SESSION) { return { terminal: "windows_terminal", source: "shell" }; } const shell = env.COMSPEC?.toLowerCase() || ""; if (/powershell/i.test(shell)) { return { terminal: "powershell", source: "shell" }; } if (/pwsh/i.test(shell)) { return { terminal: "powershell", source: "shell" }; } if (/cmd\.exe/i.test(shell)) { return { terminal: "cmd", source: "shell" }; } if (/wt\.exe/i.test(shell)) { return { terminal: "windows_terminal", source: "shell" }; } if (/conhost\.exe/i.test(shell)) { return { terminal: "conhost", source: "shell" }; } return { terminal: "windows_cmd", source: "shell" }; } const run = options.execFileSync ?? nodeExecFileSync2; const terminal = normalizeIdentifier(runShellTerm(run)); if (!terminal) { return null; } if (!options.preferOuter) { if (terminal.startsWith("tmux")) { return { terminal: "tmux", source: "shell" }; } if (terminal.startsWith("screen")) { return { terminal: "screen", source: "shell" }; } } return { terminal, source: "shell" }; } catch { return null; } }, "detectFromShellResult"); var detectFromShell = /* @__PURE__ */ __name((options = {}) => { return detectFromShellResult(options)?.terminal ?? null; }, "detectFromShell"); // src/details.ts var getTerminalResult = /* @__PURE__ */ __name((options) => { const envTerminal = detectFromEnvResult(options); let result = envTerminal; if (options.resolveAmbiguousFromParent && isAmbiguousEnvResult(envTerminal?.terminal ?? null, options)) { result = detectFromParentProcessResult(options) ?? result; } result ??= detectFromShellResult(options); result ??= detectFromProcessTitleResult(options); return result ?? { terminal: envTerminal?.terminal ?? "unknown", source: envTerminal ? envTerminal.source : "unknown", generic: envTerminal?.generic }; }, "getTerminalResult"); var detectTerminalDetails = /* @__PURE__ */ __name((options = {}) => { const env = options.env ?? process.env; const stdout = options.stdout ?? process.stdout; const isTTY = Boolean(stdout.isTTY); const isSSH = Boolean(env.SSH_CONNECTION); const term = env.TERM?.trim(); const termProgram = env.TERM_PROGRAM?.trim(); const colorTerm = env.COLORTERM?.trim(); const colorSupport = getColorSupport(env); if (!isTTY && !options.unpipe) { return { terminal: "none", source: "none", isTTY, isSSH, isAmbiguous: false, supportsColor: false, colorLevel: 0, supports256Color: colorSupport.supports256Color, supportsTrueColor: colorSupport.supportsTrueColor, term, termProgram, colorTerm, generic: "none" }; } const result = getTerminalResult(options); const colorLevel = getColorLevel(env, result.terminal, colorSupport); return { terminal: result.terminal, source: result.source, isTTY, isSSH, isAmbiguous: result.source === "env" && isAmbiguousEnvResult(result.terminal, options), colorLevel, supportsColor: colorLevel > 0, supports256Color: colorSupport.supports256Color, supportsTrueColor: colorSupport.supportsTrueColor, term, termProgram, colorTerm, generic: result.generic ?? term?.toLowerCase() ?? "unknown", pid: result.pid, appName: result.appName }; }, "detectTerminalDetails"); var detectTerminal = /* @__PURE__ */ __name((options = {}) => { return detectTerminalDetails(options).terminal; }, "detectTerminal"); export { AMBIGUOUS_ENV_TERMINALS, SHELL_PROCESS_NAMES, detectTerminal as default, detectFromEnv, detectFromEnvResult, detectFromParentProcess, detectFromParentProcessResult, detectFromProcessTitle, detectFromProcessTitleResult, detectFromShell, detectFromShellResult, detectTerminal, detectTerminalDetails, getColorLevel, getColorSupport, getParentProcess, has256Color, hasKonsoleEnvironment, isAmbiguousEnvResult, normalizeAppName, normalizeIdentifier, normalizeParentProcessName, supportsTrueColor }; //# sourceMappingURL=index.mjs.map