tool for detachable ptys with optional tailscale discovery
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667package main
import ( "fmt" "os" "slices" "strings"
"tobi/internal/app" "tobi/internal/remote" "tobi/internal/session")
func main() { if err := dispatch(os.Args[1:]); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) }}
const usage = `tobi - persistent terminals across your devices
usage: tobi attach to a session with the fuzzy selector tobi <query> attach using fuzzy search (tobi hx, tobi host.id) tobi <target> -- cmd spawn cmd in a session on target
target is [user@][host.]id and host is optional, so tobi .id -- nu creates alocal session with that id. the daemon detaches when the terminal windowcloses and detached sessions are cleaned up after 24h. sessions arereachable from any device on the tailscale network by running tobi. tobidoesn't nest: running it inside a tobi session replaces it.
requires tssh (or ssh) and tailscale in PATH.`
func dispatch(args []string) error { switch { case os.Getenv("TOBI_COMPLETE") == "1": return app.Complete(strings.Join(args, " ")) case os.Getenv("TOBI_OWNER") == "1": id := os.Getenv("TOBI_ID") for _, k := range []string{"TOBI_OWNER", "TOBI_ID", "TOBI_RPC", "TOBI_COMPLETE"} { os.Unsetenv(k) } return wrapErr("owner", session.RunOwner(id, args)) case os.Getenv("TOBI_RPC") != "": op := os.Getenv("TOBI_RPC") return wrapErr("rpc "+op, remote.RunRPC(op, os.Getenv("TOBI_ID"))) } if len(args) > 0 && (args[0] == "--help" || args[0] == "-h") { fmt.Print(usage) return nil } if i := slices.Index(args, "--"); i != -1 { return app.Spawn(strings.Join(args[:i], " "), args[i+1:]) } return app.Interactive(strings.Join(args, " "))}
func wrapErr(prefix string, err error) error { if err != nil { return fmt.Errorf("%s: %w", prefix, err) } return nil}