00503b4c0a
New zero-dependency Go CLI (cmd/cli) that drives the existing HTTP API: login/logout, apps list, deploy (synchronous, --timeout), logs (one-shot + -f SSE follow), and status. Caches a 24h JWT in ~/.tinyforge/config.json (0600, Chmod-enforced on overwrite); Bearer-header auth keeps the token out of server/proxy logs; no-echo password prompt (kernel32 on Windows, stty elsewhere). Server/token resolved via flags, TINYFORGE_URL/TINYFORGE_TOKEN env, or config. README CLI section + root-anchored .gitignore entries for the build output.
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
// Command tinyforge is a terminal client for a Tinyforge server.
|
|
//
|
|
// It drives the existing HTTP API: log in to obtain a 24h JWT, then list
|
|
// apps, trigger deploys, stream logs, and check status. The token is cached
|
|
// in ~/.tinyforge/config.json (mode 0600) so subsequent commands reuse it.
|
|
//
|
|
// Usage:
|
|
//
|
|
// tinyforge login [--user U] [--password P]
|
|
// tinyforge apps [list]
|
|
// tinyforge deploy <app> [--ref TAG] [--note TEXT]
|
|
// tinyforge logs <app> [-f] [--tail N] [--container CID]
|
|
// tinyforge status [<app>]
|
|
// tinyforge logout
|
|
// tinyforge version
|
|
//
|
|
// The target server is resolved from --base-url, then $TINYFORGE_URL, then the
|
|
// saved config, then http://localhost:8080.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
// version is the CLI build version. Overridable at build time via
|
|
// -ldflags "-X main.version=...".
|
|
var version = "dev"
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
usage(os.Stderr)
|
|
os.Exit(2)
|
|
}
|
|
|
|
cmd, args := os.Args[1], os.Args[2:]
|
|
|
|
var err error
|
|
switch cmd {
|
|
case "login":
|
|
err = runLogin(args)
|
|
case "logout":
|
|
err = runLogout(args)
|
|
case "apps":
|
|
err = runApps(args)
|
|
case "deploy":
|
|
err = runDeploy(args)
|
|
case "logs":
|
|
err = runLogs(args)
|
|
case "status":
|
|
err = runStatus(args)
|
|
case "version", "--version", "-v":
|
|
fmt.Printf("tinyforge %s\n", version)
|
|
case "help", "-h", "--help":
|
|
usage(os.Stdout)
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "tinyforge: unknown command %q\n\n", cmd)
|
|
usage(os.Stderr)
|
|
os.Exit(2)
|
|
}
|
|
|
|
if err != nil {
|
|
// Authenticated commands that hit a 401 get a re-login hint; the login
|
|
// command itself surfaces the server message ("invalid credentials").
|
|
if cmd != "login" && isAuthError(err) {
|
|
err = fmt.Errorf("%w — run 'tinyforge login'", err)
|
|
}
|
|
fmt.Fprintf(os.Stderr, "tinyforge: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func usage(w *os.File) {
|
|
fmt.Fprint(w, `tinyforge — terminal client for a Tinyforge server
|
|
|
|
Usage:
|
|
tinyforge <command> [flags]
|
|
|
|
Commands:
|
|
login Authenticate and cache a token
|
|
logout Revoke the cached token and clear it
|
|
apps [list] List your apps (workloads with a source)
|
|
deploy <app> Trigger a deploy (waits for completion)
|
|
logs <app> Print container logs (use -f to follow)
|
|
status [<app>] Show server health, or one app's containers
|
|
version Print the CLI version
|
|
|
|
Global flags (accepted by any command):
|
|
--base-url URL Server URL (default $TINYFORGE_URL or http://localhost:8080)
|
|
--token TOKEN Auth token (default $TINYFORGE_TOKEN or cached config)
|
|
--config PATH Config file (default $TINYFORGE_CONFIG or ~/.tinyforge/config.json)
|
|
|
|
Run "tinyforge <command> -h" for command-specific flags.
|
|
`)
|
|
}
|