diff --git a/pyproject.toml b/pyproject.toml index dbacb32..1747385 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "goodeye" -version = "0.18.0" +version = "0.18.1" description = "Goodeye CLI: share and run outcome-aligned AI workflows from the terminal." readme = "README.md" license = { file = "LICENSE" } diff --git a/src/goodeye_cli/commands/usage.py b/src/goodeye_cli/commands/usage.py index 52ef450..bc56c6e 100644 --- a/src/goodeye_cli/commands/usage.py +++ b/src/goodeye_cli/commands/usage.py @@ -24,22 +24,26 @@ def _coerce_usage(body: UsageResponse | dict[str, Any]) -> UsageResponse: def format_usage_summary(body: UsageResponse | dict[str, Any]) -> str: """Render the usage payload as a human-readable multi-line string. - The purchased-credits and unpaid-balance lines only render when their - values are positive. + The purchased-credits, referral-credits, and unpaid-balance lines only + render when their values are positive. """ usage = _coerce_usage(body) refill_at = usage.monthly_refill_at.strftime("%m/%d/%Y") has_purchased = float(usage.purchased_remaining_usd) > 0 + has_referral = float(usage.referral_remaining_usd) > 0 lines = [ f"Tier: {usage.tier}", f"Available: ${usage.available_usd}", ] - if has_purchased: + if has_purchased or has_referral: lines.append( f" ${usage.monthly_remaining_usd} monthly " f"(refills to ${usage.monthly_refill_usd} on {refill_at})" ) - lines.append(f" ${usage.purchased_remaining_usd} one-off credits") + if has_purchased: + lines.append(f" ${usage.purchased_remaining_usd} one-off credits") + if has_referral: + lines.append(f" ${usage.referral_remaining_usd} referral credits") else: lines.append(f" refills to ${usage.monthly_refill_usd} on {refill_at}") if float(usage.unpaid_balance_usd) > 0: @@ -75,6 +79,7 @@ def usage( "monthly_refill_usd": result.monthly_refill_usd, "monthly_refill_at": result.monthly_refill_at.isoformat(), "purchased_remaining_usd": result.purchased_remaining_usd, + "referral_remaining_usd": result.referral_remaining_usd, "unpaid_balance_usd": result.unpaid_balance_usd, } typer.echo(_json.dumps(payload)) diff --git a/src/goodeye_cli/wire.py b/src/goodeye_cli/wire.py index b21394f..f07aac2 100644 --- a/src/goodeye_cli/wire.py +++ b/src/goodeye_cli/wire.py @@ -38,7 +38,9 @@ class UsageResponse(_WireBase): Money-shaped fields are strings to preserve exact decimal values across the wire (callers parse them with ``Decimal`` or ``float`` as needed). ``available_usd`` is what the caller can spend right now: monthly grant - plus any one-off purchased credits, minus carried-over unpaid balance. + plus any one-off purchased credits and referral bonus credits, minus + carried-over unpaid balance. ``referral_remaining_usd`` defaults to 0.00 + so responses from servers that predate the field still parse. """ tier: str @@ -47,6 +49,7 @@ class UsageResponse(_WireBase): monthly_refill_usd: str monthly_refill_at: datetime purchased_remaining_usd: str + referral_remaining_usd: str = "0.00" unpaid_balance_usd: str diff --git a/tests/test_commands_usage.py b/tests/test_commands_usage.py index 59ad962..61e5647 100644 --- a/tests/test_commands_usage.py +++ b/tests/test_commands_usage.py @@ -70,6 +70,40 @@ def test_format_usage_summary_with_purchased() -> None: assert "$50.00 one-off credits" in out +def test_format_usage_summary_with_referral() -> None: + out = format_usage_summary( + _body( + available_usd="9.17", + monthly_remaining_usd="4.17", + referral_remaining_usd="5.00", + ) + ) + assert "Available: $9.17" in out + assert "$4.17 monthly (refills to $5.00 on 05/14/2026)" in out + assert "$5.00 referral credits" in out + + +def test_format_usage_summary_with_purchased_and_referral() -> None: + out = format_usage_summary( + _body( + available_usd="59.17", + monthly_remaining_usd="4.17", + purchased_remaining_usd="50.00", + referral_remaining_usd="5.00", + ) + ) + assert "Available: $59.17" in out + assert "$50.00 one-off credits" in out + assert "$5.00 referral credits" in out + + +def test_format_usage_summary_no_referral_line_when_absent() -> None: + # Older servers omit the field entirely; the wire default keeps it at 0.00 + # and the line is suppressed. + out = format_usage_summary(_body()) + assert "referral" not in out + + def test_format_usage_summary_with_unpaid() -> None: out = format_usage_summary( _body( @@ -128,6 +162,7 @@ def test_usage_command_json(tmp_config_paths: ConfigPaths, monkeypatch) -> None: assert data["tier"] == "pro" assert data["available_usd"] == "15.00" assert data["monthly_refill_usd"] == "20.00" + assert data["referral_remaining_usd"] == "0.00" def test_usage_command_without_credentials_errors( diff --git a/uv.lock b/uv.lock index 6d1fb6b..feb7b2e 100644 --- a/uv.lock +++ b/uv.lock @@ -176,7 +176,7 @@ wheels = [ [[package]] name = "goodeye" -version = "0.17.0" +version = "0.18.1" source = { editable = "." } dependencies = [ { name = "httpx" },