spacr.qt.ai.pty_sign_in

Sign in to an AI command-line tool without leaving spaCR.

The goal is a tool installed, logged in and marked READY with no terminal used. The Claude, GPT and Gemini command-line tools sign in by conversation – a web page to confirm in, sometimes a code to paste back – and they only hold that conversation with a TERMINAL, which is why spaCR used to open one. A pseudo-terminal is a terminal as far as the tool can tell, so the sign-in is run on one here, inside a small window: the web page the tool prints is opened, what it asks is shown, and the answer is typed into a box and sent.

POSIX only (Linux, macOS), where a pseudo-terminal is part of the standard library. On Windows the caller falls back to opening a terminal, as before.

Classes

PtySession

One command running on a pseudo-terminal, read off its own thread.

SignInDialog

A tool's sign-in, held inside spaCR.

Functions

find_urls(→ List[str])

Every web address in text, in order, without trailing punctuation.

pty_available(→ bool)

Whether a sign-in can run on a pseudo-terminal here.

strip_terminal_codes(→ str)

text without colour, cursor and title escape sequences.

Module Contents

class spacr.qt.ai.pty_sign_in.PtySession(argv: Sequence[str], env: Dict[str, str] | None = None)[source]

One command running on a pseudo-terminal, read off its own thread.

Parameters:
  • argv – the command.

  • env – its environment; the current one when None.

Start argv; output collects in read().

poll() → int | None[source]

The exit code, or None while it runs.

read() → str[source]

Everything the command has written since the last call.

Returns:

the text, escape sequences removed.

send(text: str) → None[source]

Type text and press Enter.

Parameters:

text – the answer.

stop() → None[source]

Reap the command, stop its process group and close the terminal.

Launchers can leave a child holding the terminal after they exit. The group belongs to this session, so cancellation also ends those children. Repeated teardown cannot close a reused file descriptor.

class spacr.qt.ai.pty_sign_in.SignInDialog(title: str, argv: Sequence[str], parent=None, *, session_factory=None, open_url=None)[source]

Bases: PySide6.QtWidgets.QDialog

A tool’s sign-in, held inside spaCR.

Parameters:
  • title – what is being signed in to, e.g. "Claude".

  • argv – the tool’s own sign-in command.

  • parent – the window it belongs to.

  • session_factory – fn(argv) -> PtySession, for tests.

  • open_url – fn(url); opens the system browser when None.

Start the sign-in and show what it says.

done(result: int) → None[source]

Stop the sign-in when the window closes.

Parameters:

result – the dialog’s result code, passed on to Qt unchanged.

spacr.qt.ai.pty_sign_in.find_urls(text: str) → List[str][source]

Every web address in text, in order, without trailing punctuation.

Parameters:

text – terminal output, escape sequences removed.

Returns:

the addresses.

spacr.qt.ai.pty_sign_in.pty_available() → bool[source]

Whether a sign-in can run on a pseudo-terminal here.

Returns:

True on Linux and macOS.

spacr.qt.ai.pty_sign_in.strip_terminal_codes(text: str) → str[source]

text without colour, cursor and title escape sequences.

Parameters:

text – raw terminal output.

Returns:

what a reader would see.