affaan-m/ECC · error · Error

Invalid terminal name; use a simple adapter name such as wez

Error message

Invalid terminal name; use a simple adapter name such as wezterm.

What it means

validateTerminalName requires the terminal adapter name to match ^[A-Za-z0-9][A-Za-z0-9_.-]*$ — it must start alphanumeric and contain only alphanumerics, dots, dashes, and underscores. This blocks path traversal, shell metacharacters, and option injection in the --terminal value. Only 'wezterm' is actually supported (SUPPORTED_TERMINALS), but the name is syntactically validated first.

Source

Thrown at skills/terminal-opener/scripts/open-terminal.js:42

  --standalone       Alias for --recover.
  --detect           Check whether the selected terminal can be launched.
  --launch           Explicitly open the terminal (the default only prints a plan).
  --dry-run          Explicitly print the launch plan without opening a terminal.
  --json             Emit the plan, capability, or launch result as JSON.
  --help, -h         Show this help.

Always pass the executable and arguments as separate entries after --.
Shell command strings are not accepted.
`;
}

function isAbsolutePath(value) {
  return path.isAbsolute(value) || path.win32.isAbsolute(value);
}

function validateTerminalName(value) {
  if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(value)) {
    throw new Error('Invalid terminal name; use a simple adapter name such as wezterm.');
  }
}

function validateCwd(value) {
  if (value.includes('\0')) throw new Error('--cwd must not contain a NUL byte.');
  if (!isAbsolutePath(value)) throw new Error('--cwd must be an absolute path.');
}

function validateExecutable(value) {
  if (!value || /[\0\r\n]/.test(value)) {
    throw new Error('Executable must be a non-empty argv entry without control bytes.');
  }

  const whitespaceIndex = value.search(/\s/);
  const separatorIndexes = [value.indexOf('/'), value.indexOf('\\')].filter(index => index >= 0);
  const firstSeparatorIndex = separatorIndexes.length > 0 ? Math.min(...separatorIndexes) : -1;
  const resemblesExecutablePath = isAbsolutePath(value)
    || (firstSeparatorIndex >= 0 && (whitespaceIndex < 0 || firstSeparatorIndex < whitespaceIndex));

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Use a plain adapter name such as 'wezterm'.
  2. If ECC_TERMINAL is set wrongly, unset it or set it to 'wezterm'.
  3. Pass only the adapter name, not a path: --terminal wezterm (no slashes, spaces, or leading dashes).

Example fix

# before
ECC_TERMINAL=/usr/bin/wezterm node open-terminal.js -- echo hi

# after
unset ECC_TERMINAL
node open-terminal.js --terminal wezterm -- echo hi
Defensive patterns

Strategy: validation

Validate before calling

function isValidTerminalName(value) {
  return typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(value);
}
const terminal = process.env.ECC_TERMINAL || 'wezterm';
if (!isValidTerminalName(terminal)) {
  throw new Error(`Invalid terminal name: ${JSON.stringify(terminal)}`);
}

Prevention

When it happens

Trigger: Passing --terminal (or setting ECC_TERMINAL) to a value that fails the regex: empty string, leading dash/slash/space, or any special character. parseArgs calls validateTerminalName near the end of parsing.

Common situations: ECC_TERMINAL accidentally set to an absolute path like /usr/bin/wezterm; passing --terminal 'wez term' with a space; copying a path from another tool; empty value from an env var.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/d98435d929947e3a. Report an issue: GitHub.