From 437a9e9171b97329579d69aef88dd61478956a02 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 26 May 2026 09:32:20 +0200 Subject: [PATCH] fix(scripts): format auth expiries on macos --- scripts/claude-auth-status.sh | 9 +++- test/scripts/claude-auth-status.test.ts | 65 +++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 test/scripts/claude-auth-status.test.ts diff --git a/scripts/claude-auth-status.sh b/scripts/claude-auth-status.sh index 64babcf71b93..6bf8e9759e30 100755 --- a/scripts/claude-auth-status.sh +++ b/scripts/claude-auth-status.sh @@ -51,6 +51,11 @@ calc_status_from_expires() { fi } +format_epoch_seconds() { + local epoch_seconds="$1" + date -r "$epoch_seconds" 2>/dev/null || date -d "@$epoch_seconds" +} + json_expires_for_claude_cli() { echo "$STATUS_JSON" | jq -r ' [.auth.oauth.profiles[] @@ -223,7 +228,7 @@ else echo " Consider running: claude setup-token" else echo -e " Status: ${GREEN}OK${NC}" - echo " Expires: $(date -d @$((expires_at/1000))) (${hours}h ${mins}m)" + echo " Expires: $(format_epoch_seconds "$((expires_at/1000))") (${hours}h ${mins}m)" fi fi @@ -267,7 +272,7 @@ else echo -e " Status: ${YELLOW}EXPIRING SOON (${mins}m remaining)${NC}" else echo -e " Status: ${GREEN}OK${NC}" - echo " Expires: $(date -d @$((expires/1000))) (${hours}h ${mins}m)" + echo " Expires: $(format_epoch_seconds "$((expires/1000))") (${hours}h ${mins}m)" fi fi diff --git a/test/scripts/claude-auth-status.test.ts b/test/scripts/claude-auth-status.test.ts new file mode 100644 index 000000000000..6f0c15030e4a --- /dev/null +++ b/test/scripts/claude-auth-status.test.ts @@ -0,0 +1,65 @@ +import { spawnSync } from "node:child_process"; +import { chmodSync, mkdirSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { createScriptTestHarness } from "./test-helpers.ts"; + +const SCRIPT = "scripts/claude-auth-status.sh"; + +describe("claude-auth-status.sh", () => { + const harness = createScriptTestHarness(); + + it("prints expiry timestamps on macOS without GNU date", () => { + const root = harness.createTempDir("openclaw-claude-auth-status-"); + const bin = path.join(root, "bin"); + mkdirSync(bin, { recursive: true }); + const openclaw = path.join(bin, "openclaw"); + const futureMs = String(Date.now() + 2 * 60 * 60 * 1000); + + writeFileSync( + openclaw, + [ + "#!/usr/bin/env bash", + "set -euo pipefail", + 'if [ "$*" = "models status --json" ]; then', + "cat <<'JSON'", + JSON.stringify({ + auth: { + oauth: { + profiles: [ + { + provider: "anthropic", + type: "oauth", + profileId: "anthropic:test", + expiresAt: Number(futureMs), + }, + ], + }, + providers: [{ provider: "anthropic", profiles: { apiKey: 0 } }], + }, + }), + "JSON", + "else", + "exit 2", + "fi", + "", + ].join("\n"), + ); + chmodSync(openclaw, 0o755); + + const result = spawnSync("bash", [SCRIPT, "full"], { + cwd: process.cwd(), + encoding: "utf8", + env: { + ...process.env, + HOME: root, + PATH: `${bin}:${process.env.PATH ?? ""}`, + }, + }); + + expect(result.status).toBe(0); + expect(result.stderr).not.toContain("date:"); + expect(result.stdout).toContain("Claude Code Auth Status"); + expect(result.stdout.match(/Expires:/g)).toHaveLength(2); + }); +});