From b6fa20784d8afc8e301846abf54a1bc377e808de Mon Sep 17 00:00:00 2001
From: DTTerastar
Date: Sat, 25 Apr 2026 18:00:29 -0400
Subject: [PATCH] feat: add 'auth status' subcommand
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Per quantcli shared contract §5, every CLI exposes 'auth status'
printing a one-line readiness summary, exit 0 if usable.
https://github.com/quantcli/common/blob/main/CONTRACT.md#5-auth
liftoff-export auth status
→ "logged in (token expires 2026-04-25T20:37:21-04:00)" / exit 0
→ "not logged in — run: liftoff-export auth login" / exit 1
→ "token expired YYYY-MM-DDTHH:MM:SS-04:00 — run: ... auth refresh" / exit 1
Local check only — no network call, no refresh attempted. Adds an
exported auth.Load() so cmd/ can read the token store without going
through GetToken's auto-refresh path.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
cmd/auth.go | 28 ++++++++++++++++++++++++++++
internal/auth/auth.go | 7 +++++++
2 files changed, 35 insertions(+)
diff --git a/cmd/auth.go b/cmd/auth.go
index b86c56a..a62f9a3 100644
--- a/cmd/auth.go
+++ b/cmd/auth.go
@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"strings"
+ "time"
"github.com/quantcli/liftoff-export-cli/internal/auth"
"github.com/spf13/cobra"
@@ -67,8 +68,35 @@ var logoutCmd = &cobra.Command{
},
}
+var statusCmd = &cobra.Command{
+ Use: "status",
+ Short: "Print one-line auth readiness state and exit 0 if usable",
+ Long: `Print a one-line summary of whether the CLI has a usable token. Exit 0
+if a saved token is present and not yet expired, 1 otherwise.
+
+This is a local check — no network call and no refresh is attempted, even
+when the saved token is expired. Use 'auth refresh' (or any export
+subcommand) to actually refresh.
+
+Per the quantcli shared contract:
+https://github.com/quantcli/common/blob/main/CONTRACT.md#5-auth`,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ store, err := auth.Load()
+ if err != nil {
+ return fmt.Errorf("not logged in — run: liftoff-export auth login")
+ }
+ exp := store.ExpiresAt.Local().Format(time.RFC3339)
+ if time.Now().After(store.ExpiresAt) {
+ return fmt.Errorf("token expired %s — run: liftoff-export auth refresh", exp)
+ }
+ fmt.Fprintf(cmd.OutOrStdout(), "logged in (token expires %s)\n", exp)
+ return nil
+ },
+}
+
func init() {
authCmd.AddCommand(loginCmd)
authCmd.AddCommand(logoutCmd)
authCmd.AddCommand(refreshCmd)
+ authCmd.AddCommand(statusCmd)
}
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index 2845d67..946f98b 100644
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -245,6 +245,13 @@ func load() (*TokenStore, error) {
return &store, json.Unmarshal(data, &store)
}
+// Load reads the saved token store without attempting a refresh. Returns
+// (nil, error) when no token has been saved yet. Suitable for non-mutating
+// status checks; use GetToken when an action needs a usable access token.
+func Load() (*TokenStore, error) {
+ return load()
+}
+
// parseBearer extracts "Bearer " from an Authorization header value.
func parseBearer(header string) string {
if strings.HasPrefix(header, "Bearer ") {