So have the thunk capture whichever ports it needs before being handed to with-* and without-echo? My concept is to hand the triplet of stdin, stdout, and stderr to the with-* procedures, and stdout to without-echo, and they extract a file descriptor from one of the ports to then do termios manipulation to. In either case, it is an error if the ports don't correspond to /dev/tty.
In that case, why not just open /dev/tty by name and close it when you've done what you need to for the moment? You don't even need to keep it open while the thunk is running. An alternative, if you think searching the pathname is too slow, would be to open /dev/tty on the first Scheme-level call and then leave it open until the process ends.
Avoiding having ^C possibly blast you completely out of your Scheme program session.
The only way to stop that is to catch signals, which is something we are not trying to do.
For example, if with-cooked-mode is *always* used for shelling out, that could be built into how it's called.
As I pointed out before, when your application switches between CLI and TUI mode, you want the CLI to run in cooked mode. Exactly how you do that depends on which mode the program start up in.