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
1 lines • 11.7 kB
Source Map (JSON)
{"version":3,"sources":["../../src/parent.ts","../../src/color.ts","../../src/normalize.ts"],"sourcesContent":["import type { DetectOptions, DetectionResult, ExecFileSync, ParentProcessInfo } from './types';\nimport { execFileSync as nodeExecFileSync } from 'node:child_process';\nimport { getColorSupport } from './color';\nimport { normalizeIdentifier, normalizeParentProcessName, SHELL_PROCESS_NAMES } from './normalize';\n\nconst runPs = (run: ExecFileSync, args: string[]): string => {\n return run('ps', args, {\n encoding: 'utf8',\n timeout: 1000,\n stdio: ['ignore', 'pipe', 'ignore']\n }) as string;\n};\n\nexport const getParentProcess = (\n pid: number,\n options: Pick<DetectOptions, 'execFileSync'> = {}\n): ParentProcessInfo | null => {\n const run = options.execFileSync ?? nodeExecFileSync;\n const parentPid = Number.parseInt(\n runPs(run, ['-o', 'ppid=', '-p', String(pid)]).trim(),\n 10\n );\n\n if (!Number.isFinite(parentPid) || parentPid <= 1) {\n return null;\n }\n\n const appName = runPs(run, ['-o', 'comm=', '-p', String(parentPid)]).trim();\n\n if (!appName) {\n return null;\n }\n\n return {\n pid: parentPid,\n appName\n };\n};\n\nconst colorVariant = (\n terminal: string,\n supports256Color: boolean,\n supportsTrueColor: boolean\n): string => {\n return supports256Color || supportsTrueColor ? `${terminal}_256color` : terminal;\n};\n\nconst applyParentColorVariant = (terminal: string, env: NodeJS.ProcessEnv): string => {\n const { supports256Color, supportsTrueColor } = getColorSupport(env);\n\n switch (terminal) {\n case 'eterm':\n case 'konsole':\n case 'rxvt':\n return colorVariant(terminal, supports256Color, supportsTrueColor);\n case 'gnome_terminal':\n case 'terminator':\n return colorVariant('gnome_terminal', supports256Color, supportsTrueColor);\n default:\n return terminal;\n }\n};\n\nexport const detectFromParentProcessResult = (\n options: DetectOptions = {}\n): DetectionResult | null => {\n const env = options.env ?? process.env;\n const platform = options.platform ?? process.platform;\n\n if (platform === 'win32' || env.SSH_CONNECTION) {\n return null;\n }\n\n const seenPids = new Set<number>();\n let pid = options.pid ?? process.pid;\n\n for (let depth = 0; depth < 12; depth += 1) {\n if (seenPids.has(pid)) {\n break;\n }\n\n seenPids.add(pid);\n\n try {\n const parent = getParentProcess(pid, options);\n\n if (!parent) {\n break;\n }\n\n const normalized = normalizeParentProcessName(parent.appName);\n\n if (normalized === 'screen' || normalized === 'tmux') {\n if (!options.preferOuter) {\n return {\n terminal: normalized,\n source: 'parent',\n appName: parent.appName,\n pid: parent.pid\n };\n }\n\n pid = parent.pid;\n continue;\n }\n\n if (normalized) {\n return {\n terminal: applyParentColorVariant(normalized, env),\n source: 'parent',\n appName: parent.appName,\n pid: parent.pid\n };\n }\n\n if (!SHELL_PROCESS_NAMES.has(normalizeIdentifier(parent.appName))) {\n break;\n }\n\n pid = parent.pid;\n } catch {\n break;\n }\n }\n\n return null;\n};\n\nexport const detectFromParentProcess = (options: DetectOptions = {}): string | null => {\n return detectFromParentProcessResult(options)?.terminal ?? null;\n};\n","import type { ColorLevel } from './types';\n\nconst TRUE_COLOR_PATTERN = /^(truecolor|24bits?)$/;\n\nexport const has256Color = (value: string | undefined): boolean => {\n return Boolean(value?.match(/256/));\n};\n\nexport const supportsTrueColor = (value: string | undefined): boolean => {\n return Boolean(value?.match(TRUE_COLOR_PATTERN));\n};\n\nexport const getColorSupport = (env: NodeJS.ProcessEnv) => {\n return {\n supports256Color: has256Color(env.TERM) || has256Color(env.COLORTERM),\n supportsTrueColor: supportsTrueColor(env.COLORTERM)\n };\n};\n\nconst NO_BASIC_COLOR_TERMINALS = new Set([\n 'dumb',\n 'linux_console',\n 'none',\n 'unknown',\n 'vt100'\n]);\n\nexport const getColorLevel = (\n env: NodeJS.ProcessEnv,\n terminal?: string | null,\n colorSupport = getColorSupport(env)\n): ColorLevel => {\n const { supports256Color, supportsTrueColor } = colorSupport;\n\n if (supportsTrueColor) {\n return 3;\n }\n\n if (supports256Color) {\n return 2;\n }\n\n if (terminal && !NO_BASIC_COLOR_TERMINALS.has(terminal)) {\n return 1;\n }\n\n if (env.TERM_PROGRAM || env.COLORTERM || env.TERMUX_VERSION) {\n return 1;\n }\n\n return 0;\n};\n","import type { DetectOptions } from './types';\nimport path from 'node:path';\n\nexport const AMBIGUOUS_ENV_TERMINALS = new Set([\n 'linux_console',\n 'truecolor_terminal',\n 'vt100',\n 'xterm',\n 'xterm_256color',\n 'xterm_truecolor'\n]);\n\nexport const SHELL_PROCESS_NAMES = new Set([\n 'bash',\n 'csh',\n 'dash',\n 'fish',\n 'ksh',\n 'login',\n 'node',\n 'nodejs',\n 'nu',\n 'sh',\n 'sudo',\n 'tcsh',\n 'zsh'\n]);\n\nexport const normalizeIdentifier = (value: string): string => {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_');\n};\n\nexport const normalizeAppName = (value: string, platform: NodeJS.Platform): string => {\n const appName = platform === 'darwin' ? path.parse(value).name : value;\n return normalizeIdentifier(appName);\n};\n\nexport const isAmbiguousEnvResult = (\n terminal: string | null,\n options: DetectOptions = {}\n): boolean => {\n if (!terminal) {\n return true;\n }\n\n if (options.preferOuter && (terminal === 'tmux' || terminal === 'screen')) {\n return true;\n }\n\n return AMBIGUOUS_ENV_TERMINALS.has(terminal);\n};\n\nexport const hasKonsoleEnvironment = (env: NodeJS.ProcessEnv): boolean => {\n return Object.keys(env).some(envVar => /konsole/i.test(envVar));\n};\n\nexport const normalizeParentProcessName = (processName: string): string | null => {\n const normalized = normalizeIdentifier(path.parse(processName).name);\n\n switch (normalized) {\n case 'alacritty':\n case 'aterm':\n case 'atomic_terminal':\n case 'eterm':\n case 'foot':\n case 'ghostty':\n case 'hyper':\n case 'kitty':\n case 'konsole':\n case 'kuake':\n case 'mate_terminal':\n case 'mrxvt':\n case 'powershell':\n case 'putty':\n case 'qterminal':\n case 'rio':\n case 'rxvt':\n case 'terminator':\n case 'terminology':\n case 'tilda':\n case 'tmux':\n case 'warp':\n case 'wezterm':\n case 'wterm':\n return normalized;\n case 'apple_terminal':\n case 'terminal':\n return 'terminal';\n case 'cmd':\n return 'cmd';\n case 'code':\n case 'code_insiders':\n return 'vscode';\n case 'conhost':\n return 'conhost';\n case 'gnome':\n case 'gnome_terminal':\n case 'gnome_terminal_server':\n case 'guake':\n return 'gnome_terminal';\n case 'iterm':\n case 'iterm2':\n return 'iterm';\n case 'login':\n case 'linux':\n return 'linux_console';\n case 'pwsh':\n return 'powershell';\n case 'screen':\n return 'screen';\n case 'terminal_app':\n return 'terminal_app';\n case 'urxvt':\n case 'urxvt256c':\n case 'urxvt256c_ml':\n case 'urxvt_ml':\n return 'rxvt';\n case 'wt':\n case 'windows_terminal':\n return 'windows_terminal';\n case 'xfce':\n case 'xfce_terminal':\n case 'xfce4_terminal':\n return 'xfce4_terminal';\n default: {\n if (normalized.startsWith('gnome_terminal')) {\n return 'gnome_terminal';\n }\n\n if (normalized.startsWith('warp')) {\n return 'warp';\n }\n\n return null;\n }\n }\n};\n"],"mappings":"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","names":["supportsTrueColor"]}