Skip to content

Commit 8f83644

Browse files
gluonfieldclaude
andcommitted
feat: show usage and billing info in whoami command
Fetches current usage, bill, and included credits alongside account info. Both GraphQL queries run in parallel for faster response. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a5de16c commit 8f83644

3 files changed

Lines changed: 280 additions & 5 deletions

File tree

cmd/whoami.go

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,65 @@ package cmd
22

33
import (
44
"fmt"
5+
"strconv"
56
"strings"
7+
"sync"
8+
"time"
69

710
"github.com/mldotink/cli/internal/gql"
811
"github.com/spf13/cobra"
912
)
1013

14+
func formatCents(cents int) string {
15+
return fmt.Sprintf("$%.2f", float64(cents)/100)
16+
}
17+
18+
func formatSubtotal(s string) string {
19+
v, err := strconv.ParseFloat(s, 64)
20+
if err != nil {
21+
return "$" + s
22+
}
23+
return fmt.Sprintf("$%.2f", v)
24+
}
25+
26+
func shortDate(raw string) string {
27+
t, err := time.Parse(time.RFC3339Nano, raw)
28+
if err != nil {
29+
return raw
30+
}
31+
return t.Local().Format("Jan 2")
32+
}
1133

1234
var whoamiCmd = &cobra.Command{
1335
Use: "whoami",
1436
Aliases: []string{"account"},
15-
Short: "Show account info, plan, and GitHub App/OAuth connection status",
37+
Short: "Show account info, plan, usage, and GitHub connection status",
1638
Example: `ink whoami
1739
ink whoami --json`,
1840
Run: func(cmd *cobra.Command, args []string) {
1941
client := newClient()
2042

21-
result, err := gql.AccountStatus(ctx(), client)
22-
if err != nil {
23-
fatal(err.Error())
43+
var (
44+
result *gql.AccountStatusResponse
45+
accErr error
46+
usage *gql.UsageBillBreakdownResponse
47+
usageErr error
48+
wg sync.WaitGroup
49+
)
50+
51+
wg.Add(2)
52+
go func() {
53+
defer wg.Done()
54+
result, accErr = gql.AccountStatus(ctx(), client)
55+
}()
56+
go func() {
57+
defer wg.Done()
58+
usage, usageErr = gql.UsageBillBreakdown(ctx(), client, wsPtr())
59+
}()
60+
wg.Wait()
61+
62+
if accErr != nil {
63+
fatal(accErr.Error())
2464
}
2565

2666
a := result.AccountStatus
@@ -29,7 +69,11 @@ ink whoami --json`,
2969
}
3070

3171
if jsonOutput {
32-
printJSON(a)
72+
out := map[string]any{"account": a}
73+
if usageErr == nil {
74+
out["usage"] = usage.UsageBillBreakdown
75+
}
76+
printJSON(out)
3377
return
3478
}
3579

@@ -45,7 +89,21 @@ ink whoami --json`,
4589
}
4690
d.kv("Plan", tier)
4791

92+
// Usage / Billing
93+
if usageErr == nil {
94+
u := usage.UsageBillBreakdown
95+
period := shortDate(u.PeriodStart) + " – " + shortDate(u.PeriodEnd)
96+
d.blank()
97+
d.section("Usage (" + period + ")")
98+
d.kv("Current Usage", formatSubtotal(u.Subtotal))
99+
d.kv("Current Bill", formatCents(u.CurrentBillCents))
100+
if u.IncludedUsageCents > 0 {
101+
d.kv("Included", formatCents(u.IncludedUsageCents))
102+
}
103+
}
104+
48105
// GitHub App — required for deploying from GitHub repos
106+
d.blank()
49107
if a.HasGitHubApp {
50108
d.kv("GitHub App", green.Render("installed")+" "+dim.Render("deploy from GitHub repos"))
51109
} else {

internal/gql/generated.go

Lines changed: 201 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/gql/operations.graphql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,3 +386,19 @@ query AccountStatus {
386386
subscriptionTier
387387
}
388388
}
389+
390+
# ── Usage / Billing ───────────────────────────────
391+
392+
query UsageBillBreakdown($ws: String) {
393+
usageBillBreakdown(workspaceSlug: $ws) {
394+
memory { quantity unitPrice unit totalCents }
395+
cpu { quantity unitPrice unit totalCents }
396+
egress { quantity unitPrice unit totalCents }
397+
subtotal
398+
includedUsageCents
399+
planFeeCents
400+
currentBillCents
401+
periodStart
402+
periodEnd
403+
}
404+
}

0 commit comments

Comments
 (0)