From ae67ca7a134a129e79501ea629b2e629ffc5d8c1 Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Sun, 7 Jun 2026 19:58:34 -0700 Subject: [PATCH] fix(cli): show Cline credits refill link (#11345) * fix(cli): show Cline credits refill link * fix(cli): simplify Cline credits error matcher * fix(cli): keep credits handling in TUI * fix(cli): rename credits error matcher * fix(cli): render credits dashboard as link * fix(cli): remove credits redirect param * fix(cli): document temporary credits matcher --- apps/cli/src/tui/cline-account.ts | 12 +++++++ apps/cli/src/tui/components/chat-entry.tsx | 37 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/apps/cli/src/tui/cline-account.ts b/apps/cli/src/tui/cline-account.ts index 54d06ba492..4efdc003da 100644 --- a/apps/cli/src/tui/cline-account.ts +++ b/apps/cli/src/tui/cline-account.ts @@ -14,6 +14,8 @@ import { toProviderApiKey } from "../utils/provider-auth"; import type { Config } from "../utils/types"; const WORKOS_TOKEN_PREFIX = "workos:"; +export const CLINE_CREDITS_DASHBOARD_URL = + "https://app.cline.bot/dashboard/account?tab=credits"; type ClineAccountConfig = Pick; @@ -30,6 +32,8 @@ export function formatClineCredits(value: number): string { return formatCreditBalance(normalizeCreditBalance(value)); } +// FIXME: These message checks are temporary until structured error types are +// passed through to the CLI instead of plain error strings. export function isClineAccountAuthErrorMessage(message: string): boolean { const normalized = message.trim().toLowerCase(); return ( @@ -38,6 +42,14 @@ export function isClineAccountAuthErrorMessage(message: string): boolean { ); } +export function isClineAccountCreditsErrorMessage(message: string): boolean { + const normalized = message.trim().toLowerCase(); + return ( + normalized.includes("insufficient balance") && + normalized.includes("cline credits balance") + ); +} + function resolveAccountApiBaseUrl(input: { clineApiBaseUrl?: string; clineProviderSettings?: ProviderSettings; diff --git a/apps/cli/src/tui/components/chat-entry.tsx b/apps/cli/src/tui/components/chat-entry.tsx index dea10bf78d..880277a849 100644 --- a/apps/cli/src/tui/components/chat-entry.tsx +++ b/apps/cli/src/tui/components/chat-entry.tsx @@ -2,6 +2,10 @@ import { useTerminalDimensions } from "@opentui/react"; import type React from "react"; import { useState } from "react"; import "opentui-spinner/react"; +import { + CLINE_CREDITS_DASHBOARD_URL, + isClineAccountCreditsErrorMessage, +} from "../cline-account"; import { useTerminalBackground } from "../hooks/use-terminal-background"; import { getDefaultForeground, @@ -256,6 +260,36 @@ function ToolCallView(props: { ); } +function ClineCreditsErrorView(props: { defaultFg?: string }) { + return ( + + + + Cline Credits depleted + + + Dashboard: + + + {CLINE_CREDITS_DASHBOARD_URL} + + + + + + ); +} + export function ChatEntryView(props: { entry: ChatEntry; accent?: string; @@ -351,6 +385,9 @@ export function ChatEntryView(props: { ); case "error": + if (isClineAccountCreditsErrorMessage(entry.text)) { + return ; + } return (