package 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 attach using fuzzy search (tobi hx, tobi host.id) tobi -- cmd spawn cmd in a session on target target is [user@][host.]id and host is optional, so tobi .id -- nu creates a local session with that id. the daemon detaches when the terminal window closes and detached sessions are cleaned up after 24h. sessions are reachable from any device on the tailscale network by running tobi. tobi doesn'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 }