]> git.giacomolli.uk - onechat/blob - main.go
Show styled replies only on terminal output
[onechat] / main.go
1 // Command onechat runs the agent daemon and its terminal client.
2 package main
3
4 import (
5         "context"
6         "fmt"
7         "os"
8         "os/signal"
9         "strings"
10         "syscall"
11 )
12
13 // usage is the help text of the command.
14 const usage = `Usage: onechat [COMMAND]
15
16 Commands:
17   chat                     talk to the agent in this terminal (default)
18   daemon                   run the agent, Telegram, and WhatsApp
19   import [-n] ZIP...        import WhatsApp history (stop the daemon first)
20     -n                     print the plan without model calls
21   login                    log in to ChatGPT with a device code
22   probe LOG COUNT [BUILDS] measure the compactor on a log, with real calls
23   version                  show the build version
24   help                     show this help
25
26 Chat needs a running daemon. ONECHAT_DIR sets the data directory.
27 `
28
29 // version is set by the package build and stays dev for direct Go builds.
30 var version = "dev"
31
32 func main() {
33         err := run()
34         if err != nil {
35                 fmt.Fprintln(os.Stderr, "onechat:", err)
36                 os.Exit(1)
37         }
38 }
39
40 func run() error {
41         ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
42         defer cancel()
43
44         args := os.Args[1:]
45         switch {
46         case len(args) == 1 && (args[0] == "help" || args[0] == "--help" || args[0] == "-h"):
47                 _, err := fmt.Print(usage)
48                 if err != nil {
49                         return fmt.Errorf("write command help: %w", err)
50                 }
51         case len(args) == 1 && args[0] == "version":
52                 _, err := fmt.Println(version)
53                 if err != nil {
54                         return fmt.Errorf("write build version: %w", err)
55                 }
56         case len(args) == 1 && args[0] == "login":
57                 err := chatgptLogin(ctx, os.Stdout)
58                 if err != nil {
59                         return err
60                 }
61
62         // A signal is the normal stop of the daemon and the client, so their
63         // result does not include ctx.Err().
64         case len(args) == 1 && args[0] == "daemon":
65                 return daemon(ctx, os.Stdout)
66         case len(args) == 0 || len(args) == 1 && args[0] == "chat":
67                 return terminal(ctx, os.Stdin, os.Stdout)
68         case len(args) > 0 && args[0] == "import":
69                 return whatsappImport(ctx, args[1:], os.Stdout)
70         case len(args) > 0 && args[0] == "probe":
71                 err := probe(ctx, args[1:], os.Stdout)
72                 if err != nil {
73                         return err
74                 }
75         default:
76                 return fmt.Errorf("unknown command %q\n\n%s", strings.Join(args, " "), strings.TrimSuffix(usage, "\n"))
77         }
78
79         return ctx.Err()
80 }