]> git.giacomolli.uk - onechat/blobdiff - main.go
Pass caller contexts through WhatsApp callbacks
[onechat] / main.go
diff --git a/main.go b/main.go
index 271a91a56d749d67880213d921a949ecfa6b8b15..10ac995a9555b2885070e2d8baf77a1eed30fa4f 100644 (file)
--- a/main.go
+++ b/main.go
@@ -1,3 +1,4 @@
+// Command onechat runs the agent daemon and its terminal client.
 package main
 
 import (
@@ -5,9 +6,35 @@ import (
        "fmt"
        "os"
        "os/signal"
+       "strings"
        "syscall"
 )
 
+// usage is the help text of the command.
+const usage = `Usage: onechat [COMMAND]
+
+Commands:
+  backup FILE              archive the running daemon data
+  restore FILE             restore into an empty data directory
+  chat                     talk to the agent in this terminal (default)
+  daemon                   run the agent, Telegram, and WhatsApp
+  import [-n] [--agent NAME] ZIP...
+                           import WhatsApp history (stop the daemon first)
+    -n                     print the plan without model calls
+    --agent NAME           import into an existing direct child (default: root)
+  login                    log in to ChatGPT with a device code
+  probe LOG COUNT [BUILDS] measure the compactor on a log, with real calls
+  version                  show the build version
+  help                     show this help
+
+Chat needs a running daemon. ONECHAT_DIR sets the data directory.
+In chat, /image PATH [caption] sends a JPEG, PNG, or WebP image up to 20 MB.
+Quote PATH with single or double quotes when it contains spaces.
+`
+
+// version is set by the package build and stays dev for direct Go builds.
+var version = "dev"
+
 func main() {
        err := run()
        if err != nil {
@@ -20,9 +47,43 @@ func run() error {
        ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
        defer cancel()
 
-       _, err := fmt.Println("onechat")
-       if err != nil {
-               return err
+       args := os.Args[1:]
+       switch {
+       case len(args) == 1 && (args[0] == "help" || args[0] == "--help" || args[0] == "-h"):
+               _, err := fmt.Print(usage)
+               if err != nil {
+                       return fmt.Errorf("write command help: %w", err)
+               }
+       case len(args) == 1 && args[0] == "version":
+               _, err := fmt.Println(version)
+               if err != nil {
+                       return fmt.Errorf("write build version: %w", err)
+               }
+       case len(args) == 1 && args[0] == "login":
+               err := chatgptLogin(ctx, os.Stdout)
+               if err != nil {
+                       return err
+               }
+
+       // A signal is the normal stop of the daemon and the client, so their
+       // result does not include ctx.Err().
+       case len(args) == 1 && args[0] == "daemon":
+               return daemon(ctx, os.Stdout)
+       case len(args) == 0 || len(args) == 1 && args[0] == "chat":
+               return terminal(ctx, os.Stdin, os.Stdout)
+       case len(args) == 2 && args[0] == "backup":
+               return backup(ctx, args[1], os.Stdout)
+       case len(args) == 2 && args[0] == "restore":
+               return restore(ctx, args[1], os.Stdout)
+       case len(args) > 0 && args[0] == "import":
+               return whatsappImport(ctx, args[1:], os.Stdout)
+       case len(args) > 0 && args[0] == "probe":
+               err := probe(ctx, args[1:], os.Stdout)
+               if err != nil {
+                       return err
+               }
+       default:
+               return fmt.Errorf("unknown command %q\n\n%s", strings.Join(args, " "), strings.TrimSuffix(usage, "\n"))
        }
 
        return ctx.Err()