```ts
export function scanSource(line: string): [string, string][] {
  const tokens: [string, string][] = [];
  let i = 0;
  
  while (i < line.length) {
    const char = line[i];

    if (/\s/.test(char)) {
      // Skip spaces and tabs
      i++;
      continue;
    }

    if (/[0-9]/.test(char)) {
      // Lex a number
      let numText = '';
      while (i < line.length && /[0-9]/.test(line[i])) {
        numText += line[i];
        i++;
      }
      tokens.push(['num', numText]);
      continue;
    }

    if (/[_a-zA-Z]/.test(char)) {
      // Lex an identifier
      let idText = '';
      while (i < line.length && /[_a-zA-Z0-9]/.test(line[i])) {
        idText += line[i];
        i++;
      }
      tokens.push(['id', idText]);
      continue;
    }

    if (/[\(\)=<>+\-*\/]/.test(char)) {
      // Lex a single-character operator
      tokens.push(['op', char]);
      i++;
      continue;
    }

    if (i + 1 < line.length && /==|!=|<=|>=/.test(line.substring(i, i + 2))) {
      // Lex a two-character operator
      tokens.push(['op', line.substring(i, i + 2)]);
      i += 2;
      continue;
    }

    if (i + 1 < line.length && /&&|\|\|/.test(line.substring(i, i + 2))) {
      // Lex a two-character logical operator
      tokens.push(['op', line.substring(i, i + 2)]);
      i += 2;
      continue;
    }

    throw new Error(`Invalid character: ${char}`);
  }

  return tokens;
}
```