Skip to content

fix: Add Windows compatibility and JupyterKernelClient fallback - #99

Open
Yash-Kavaiya wants to merge 1 commit into
googlecolab:mainfrom
Yash-Kavaiya:fix-windows-compatibility-and-kernel-client
Open

fix: Add Windows compatibility and JupyterKernelClient fallback#99
Yash-Kavaiya wants to merge 1 commit into
googlecolab:mainfrom
Yash-Kavaiya:fix-windows-compatibility-and-kernel-client

Conversation

@Yash-Kavaiya

@Yash-Kavaiya Yash-Kavaiya commented Aug 6, 2026

Copy link
Copy Markdown

Fixes #100

Summary of Fixes

This PR adds native cross-platform support for Windows and resolves a runtime AttributeError:

  1. Windows Console Compatibility (colab_cli/console.py):

    • Wrapped termios and tty imports in a try/except ImportError block.
    • Added guards around termios, tty, fileno(), and signal.SIGWINCH calls to prevent ModuleNotFoundError: No module named 'termios' on Windows.
  2. Google Drive Auth /dev/tty Fallback (colab_cli/commands/automation.py):

    • Added a fallback for open("/dev/tty") on non-POSIX systems to use sys.stdin.readline().
  3. JupyterKernelClient Fallback (colab_cli/runtime.py):

    • Fixed AttributeError: module 'jupyter_kernel_client' has no attribute 'KernelClient' in ColabRuntime.kernel_client by updating the fallback class name to jupyter_kernel_client.JupyterKernelClient.

Testing Verification

Verified end-to-end on Windows 11 with PowerShell:

  • Created sessions using colab new --gpu T4 -s demo-session
  • Handled OAuth flow & Drive automation
  • Executed Python code & GPU workloads (nvidia-smi on Tesla T4 runtime)

@ramgeart

ramgeart commented Sep 7, 2026

Copy link
Copy Markdown

Great work on adding Windows support to the CLI!

While testing this branch on Windows 11 with colab ssh --proxy-mode (e.g. for VS Code Remote - SSH and OpenSSH), we identified an issue where the proxy bridge terminates immediately after the server's SSH identification banner, causing OpenSSH to fail:

debug1: SSH2_MSG_KEXINIT sent
Connection closed by UNKNOWN port 65535
SSH server closed unexpectedly. Error code: 255

Root Cause in src/colab_cli/commands/ssh.py

  1. select.select() fails on non-socket file descriptors on Windows:
    In _bridge_proxy_mode(), stdin_to_ws() calls:

    ready, _, _ = select.select([stdin_fd], [], [], None)

    On Windows, Python's select.select() only supports Winsock network sockets (not anonymous pipes, console handles, or file descriptors). Calling it on stdin_fd raises:
    OSError: [WinError 10038] An operation was attempted on something that is not a socket.
    The try...except (OSError, ...) catches this error and immediately runs _close_quietly(ws) in finally, killing the WebSocket connection right after the initial banner.
    Fix: Since stdin_to_ws runs in a dedicated daemon thread, we can bypass select.select on Windows and let os.read(stdin_fd, 8192) block natively.

  2. Windows stdio mode & binary packet corruption:
    On Windows, sys.stdin and sys.stdout open in text mode by default. Binary SSH traffic is corrupted by automatic CRLF translation (\n <-> \r\n), and byte 0x1A (Ctrl+Z) is treated as EOF by the C runtime.
    Fix: Call msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) and msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) when sys.platform == "win32".

  3. Missing signal.SIGHUP on Windows:
    signal.SIGHUP does not exist in Python on Windows. Accessing it in _install_rm_signal_handlers() raises AttributeError whenever --rm is used.
    Fix: Guard signal.SIGHUP with hasattr(signal, "SIGHUP").


Suggested Patch

diff --git a/src/colab_cli/commands/ssh.py b/src/colab_cli/commands/ssh.py
index 1d5c4b6..e58b334 100644
--- a/src/colab_cli/commands/ssh.py
+++ b/src/colab_cli/commands/ssh.py
@@ -352,14 +352,20 @@ def _bridge_proxy_mode(ws: websocket.WebSocket) -> int:
     Returns:
       0 when either side closes.
     """
+    if sys.platform == 'win32':
+        import msvcrt
+        msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+        msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+
     stdin_fd = sys.stdin.buffer.fileno()
 
     def stdin_to_ws():
         try:
             while True:
-                ready, _, _ = select.select([stdin_fd], [], [], None)
-                if not ready:
-                    continue
+                if sys.platform != 'win32':
+                    ready, _, _ = select.select([stdin_fd], [], [], None)
+                    if not ready:
+                        continue
                 data = os.read(stdin_fd, 8192)
                 if not data:
                     break
@@ -528,7 +534,10 @@ def _install_rm_signal_handlers(do_rm: Callable[[], None]) -> None:
         do_rm()
         os._exit(0)
 
-    for sig in (signal.SIGHUP, signal.SIGTERM, signal.SIGINT):
+    signals = [signal.SIGTERM, signal.SIGINT]
+    if hasattr(signal, 'SIGHUP'):
+        signals.append(signal.SIGHUP)
+    for sig in signals:
         try:
             signal.signal(sig, _on_signal)
         except (ValueError, OSError):

All 50 unit tests in tests/test_ssh.py pass with this change.


How to Connect on Windows (VS Code / OpenSSH)

With this fix applied, connecting from Windows works smoothly:

  1. Configure ~/.ssh/config (C:\Users\<username>\.ssh\config):

    Host colab
        HostName colab
        User root
        IdentityFile C:\Users\<username>\.ssh\id_ed25519
        IdentitiesOnly yes
        ProxyCommand colab ssh --proxy-mode -s colab
        StrictHostKeyChecking no
        UserKnownHostsFile NUL
        ServerAliveInterval 30
        ServerAliveCountMax 4
    

    (Note: Passing -s <session_name> like -s colab is recommended because colab ssh will automatically provision a new runtime session if none exists, routing output to stderr so the SSH byte stream remains clean).

  2. Connect:

    • Terminal:
      ssh colab
    • VS Code / Cursor Remote - SSH:
      Press Ctrl+Shift+P -> Remote-SSH: Connect to Host... -> Select colab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Windows compatibility crashes ('termios' ModuleNotFoundError & KernelClient AttributeError)

2 participants