diff --git a/docker/README.md b/docker/README.md index 38cccb18..780fcf93 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,4 +1,4 @@ -# Claude Code UI — Docker Sandbox Templates +# CloudCLI — Docker Sandbox Templates Run AI coding agents with a full web IDE inside [Docker Sandboxes](https://docs.docker.com/ai/sandboxes/). @@ -62,11 +62,11 @@ docker build -f docker/gemini/Dockerfile -t cloudcli-sandbox:gemini docker/ Each template extends Docker's official sandbox base image and adds: -1. **Node.js 22** — Runtime for Claude Code UI -2. **Claude Code UI** — Installed globally via `npm install -g @cloudcli-ai/cloudcli` +1. **Node.js 22** — Runtime for CloudCLI +2. **CloudCLI** — Installed globally via `npm install -g @cloudcli-ai/cloudcli` 3. **Auto-start** — The UI server starts in the background when the sandbox shell opens (port 3001) -The agent (Claude Code, Codex, or Gemini) comes from the base image. Claude Code UI connects to it and provides the web interface on top. +The agent (Claude Code, Codex, or Gemini) comes from the base image. CloudCLI connects to it and provides the web interface on top. ## Configuration @@ -86,4 +86,4 @@ sbx policy allow network "localhost:3001" ## License -These templates are free and open-source under the same license as Claude Code UI (AGPL-3.0-or-later). +These templates are free and open-source under the same license as CloudCLI (AGPL-3.0-or-later). diff --git a/docker/shared/start-cloudcli.sh b/docker/shared/start-cloudcli.sh index 26b6c8c0..145c35c5 100644 --- a/docker/shared/start-cloudcli.sh +++ b/docker/shared/start-cloudcli.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Auto-start Claude Code UI server in background if not already running. +# Auto-start CloudCLI server in background if not already running. # This script is sourced from ~/.bashrc on sandbox shell open. if ! pgrep -f "server/index.js" > /dev/null 2>&1; then @@ -13,7 +13,7 @@ if ! pgrep -f "server/index.js" > /dev/null 2>&1; then disown echo "" - echo " Claude Code UI is starting on port 3001..." + echo " CloudCLI is starting on port 3001..." echo "" echo " To access the web UI, forward the port:" echo " sbx ports \$(hostname) --publish 3001:3001" diff --git a/public/api-docs.html b/public/api-docs.html index 9b8a266d..75f48963 100644 --- a/public/api-docs.html +++ b/public/api-docs.html @@ -3,7 +3,7 @@ - Claude Code UI - API Documentation + CloudCLI - API Documentation @@ -418,7 +418,7 @@
-

Claude Code UI

+

CloudCLI

API Documentation
diff --git a/public/sw.js b/public/sw.js index 9b4351bc..b909bf55 100755 --- a/public/sw.js +++ b/public/sw.js @@ -1,4 +1,4 @@ -// Service Worker for Claude Code UI PWA +// Service Worker for CloudCLI PWA // Cache only manifest (needed for PWA install). HTML and JS are never pre-cached // so a rebuild + refresh always picks up the latest assets. const CACHE_NAME = 'claude-ui-v2'; @@ -79,7 +79,7 @@ self.addEventListener('push', event => { try { payload = event.data.json(); } catch { - payload = { title: 'Claude Code UI', body: event.data.text() }; + payload = { title: 'CloudCLI', body: event.data.text() }; } const options = { @@ -92,7 +92,7 @@ self.addEventListener('push', event => { }; event.waitUntil( - self.registration.showNotification(payload.title || 'Claude Code UI', options) + self.registration.showNotification(payload.title || 'CloudCLI', options) ); }); diff --git a/server/cli.js b/server/cli.js index 8359b6d7..39461673 100755 --- a/server/cli.js +++ b/server/cli.js @@ -1,8 +1,8 @@ #!/usr/bin/env node /** - * Claude Code UI CLI + * CloudCLI CLI * - * Provides command-line utilities for managing Claude Code UI + * Provides command-line utilities for managing CloudCLI * * Commands: * (no args) - Start the server (default) @@ -84,7 +84,7 @@ function getInstallDir() { // Show status command function showStatus() { - console.log(`\n${c.bright('Claude Code UI - Status')}\n`); + console.log(`\n${c.bright('CloudCLI UI - Status')}\n`); console.log(c.dim('═'.repeat(60))); // Version info @@ -141,7 +141,7 @@ function showStatus() { function showHelp() { console.log(` ╔═══════════════════════════════════════════════════════════════╗ -║ Claude Code UI - Command Line Tool ║ +║ CloudCLI - Command Line Tool ║ ╚═══════════════════════════════════════════════════════════════╝ Usage: @@ -149,7 +149,7 @@ Usage: cloudcli [command] [options] Commands: - start Start the Claude Code UI server (default) + start Start the CloudCLI server (default) status Show configuration and data locations update Update to the latest version help Show this help information diff --git a/server/index.js b/server/index.js index 791fac8d..5bce4291 100755 --- a/server/index.js +++ b/server/index.js @@ -2360,7 +2360,7 @@ async function startServer() { console.log(''); console.log(c.dim('═'.repeat(63))); - console.log(` ${c.bright('Claude Code UI Server - Ready')}`); + console.log(` ${c.bright('CloudCLI Server - Ready')}`); console.log(c.dim('═'.repeat(63))); console.log(''); console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + SERVER_PORT)}`); diff --git a/server/routes/agent.js b/server/routes/agent.js index 74f4f97d..35e82991 100644 --- a/server/routes/agent.js +++ b/server/routes/agent.js @@ -1080,7 +1080,7 @@ router.post('/', validateExternalApiKey, async (req, res) => { } else { prBody += `Agent task: ${message}`; } - prBody += '\n\n---\n*This pull request was automatically created by Claude Code UI Agent.*'; + prBody += '\n\n---\n*This pull request was automatically created by CloudCLI.ai Agent.*'; console.log(`📝 PR Title: ${prTitle}`); diff --git a/server/services/notification-orchestrator.js b/server/services/notification-orchestrator.js index bb573e10..d3d47dd6 100644 --- a/server/services/notification-orchestrator.js +++ b/server/services/notification-orchestrator.js @@ -125,7 +125,7 @@ function buildPushBody(event) { const message = CODE_MAP[event.code] || 'You have a new notification'; return { - title: sessionName || 'Claude Code UI', + title: sessionName || 'CloudCLI', body: `${providerLabel}: ${message}`, data: { sessionId: event.sessionId || null, diff --git a/src/components/auth/view/AuthLoadingScreen.tsx b/src/components/auth/view/AuthLoadingScreen.tsx index 36ecbc2f..9b4987d5 100644 --- a/src/components/auth/view/AuthLoadingScreen.tsx +++ b/src/components/auth/view/AuthLoadingScreen.tsx @@ -12,7 +12,7 @@ export default function AuthLoadingScreen() { -

Claude Code UI

+

CloudCLI

{loadingDotAnimationDelays.map((delay) => ( diff --git a/src/components/auth/view/AuthScreenLayout.tsx b/src/components/auth/view/AuthScreenLayout.tsx index 6651dbe0..d53ff95f 100644 --- a/src/components/auth/view/AuthScreenLayout.tsx +++ b/src/components/auth/view/AuthScreenLayout.tsx @@ -1,5 +1,6 @@ import type { ReactNode } from 'react'; import { MessageSquare } from 'lucide-react'; +import { IS_PLATFORM } from '../../../constants/config'; type AuthScreenLayoutProps = { title: string; @@ -37,6 +38,22 @@ export default function AuthScreenLayout({

{footerText}

+ + {!IS_PLATFORM && ( +
+ + + CloudCLI is open source + +
+ )}
diff --git a/src/components/auth/view/LoginForm.tsx b/src/components/auth/view/LoginForm.tsx index 4e0973e2..cf26ca3d 100644 --- a/src/components/auth/view/LoginForm.tsx +++ b/src/components/auth/view/LoginForm.tsx @@ -58,7 +58,7 @@ export default function LoginForm() {
} diff --git a/src/components/settings/types/types.ts b/src/components/settings/types/types.ts index 096059ce..e3af730b 100644 --- a/src/components/settings/types/types.ts +++ b/src/components/settings/types/types.ts @@ -1,6 +1,6 @@ import type { Dispatch, SetStateAction } from 'react'; -export type SettingsMainTab = 'agents' | 'appearance' | 'git' | 'api' | 'tasks' | 'notifications' | 'plugins'; +export type SettingsMainTab = 'agents' | 'appearance' | 'git' | 'api' | 'tasks' | 'notifications' | 'plugins' | 'about'; export type AgentProvider = 'claude' | 'cursor' | 'codex' | 'gemini'; export type AgentCategory = 'account' | 'permissions' | 'mcp'; export type ProjectSortOrder = 'name' | 'date'; diff --git a/src/components/settings/view/PremiumFeatureCard.tsx b/src/components/settings/view/PremiumFeatureCard.tsx new file mode 100644 index 00000000..07980d86 --- /dev/null +++ b/src/components/settings/view/PremiumFeatureCard.tsx @@ -0,0 +1,46 @@ +import { ExternalLink, Lock } from 'lucide-react'; +import type { ReactNode } from 'react'; + +const CLOUDCLI_URL = 'https://cloudcli.ai'; + +type PremiumFeatureCardProps = { + icon: ReactNode; + title: string; + description: string; + ctaText?: string; +}; + +export default function PremiumFeatureCard({ + icon, + title, + description, + ctaText = 'Available with CloudCLI Pro', +}: PremiumFeatureCardProps) { + return ( +
+
+
+ {icon} +
+
+
+

{title}

+ +
+

+ {description} +

+ + {ctaText} + + +
+
+
+ ); +} diff --git a/src/components/settings/view/Settings.tsx b/src/components/settings/view/Settings.tsx index 444d0e06..70d3ea4d 100644 --- a/src/components/settings/view/Settings.tsx +++ b/src/components/settings/view/Settings.tsx @@ -12,6 +12,7 @@ import GitSettingsTab from '../view/tabs/git-settings/GitSettingsTab'; import NotificationsSettingsTab from '../view/tabs/NotificationsSettingsTab'; import TasksSettingsTab from '../view/tabs/tasks-settings/TasksSettingsTab'; import PluginSettingsTab from '../../plugins/view/PluginSettingsTab'; +import AboutTab from '../view/tabs/AboutTab'; import { useSettingsController } from '../hooks/useSettingsController'; import { useWebPush } from '../../../hooks/useWebPush'; import type { SettingsProps } from '../types/types'; @@ -206,6 +207,8 @@ function Settings({ isOpen, onClose, projects = [], initialTab = 'agents' }: Set {activeTab === 'api' && } {activeTab === 'plugins' && } + + {activeTab === 'about' && } diff --git a/src/components/settings/view/SettingsMainTabs.tsx b/src/components/settings/view/SettingsMainTabs.tsx index d085d545..5c15f6de 100644 --- a/src/components/settings/view/SettingsMainTabs.tsx +++ b/src/components/settings/view/SettingsMainTabs.tsx @@ -1,4 +1,4 @@ -import { GitBranch, Key, Puzzle } from 'lucide-react'; +import { GitBranch, Info, Key, Puzzle } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { SettingsMainTab } from '../types/types'; @@ -22,6 +22,7 @@ const TAB_CONFIG: MainTabConfig[] = [ { id: 'tasks', labelKey: 'mainTabs.tasks' }, { id: 'notifications', labelKey: 'mainTabs.notifications' }, { id: 'plugins', labelKey: 'mainTabs.plugins', icon: Puzzle }, + { id: 'about', labelKey: 'mainTabs.about', icon: Info }, ]; export default function SettingsMainTabs({ activeTab, onChange }: SettingsMainTabsProps) { diff --git a/src/components/settings/view/SettingsSidebar.tsx b/src/components/settings/view/SettingsSidebar.tsx index e6f56f46..149c1492 100644 --- a/src/components/settings/view/SettingsSidebar.tsx +++ b/src/components/settings/view/SettingsSidebar.tsx @@ -1,4 +1,4 @@ -import { Bell, Bot, GitBranch, Key, ListChecks, Palette, Puzzle } from 'lucide-react'; +import { Bell, Bot, GitBranch, Info, Key, ListChecks, Palette, Puzzle } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { cn } from '../../../lib/utils'; import { PillBar, Pill } from '../../../shared/view/ui'; @@ -23,6 +23,7 @@ const NAV_ITEMS: NavItem[] = [ { id: 'tasks', labelKey: 'mainTabs.tasks', icon: ListChecks }, { id: 'plugins', labelKey: 'mainTabs.plugins', icon: Puzzle }, { id: 'notifications', labelKey: 'mainTabs.notifications', icon: Bell }, + { id: 'about', labelKey: 'mainTabs.about', icon: Info }, ]; export default function SettingsSidebar({ activeTab, onChange }: SettingsSidebarProps) { diff --git a/src/components/settings/view/tabs/AboutTab.tsx b/src/components/settings/view/tabs/AboutTab.tsx new file mode 100644 index 00000000..027af75e --- /dev/null +++ b/src/components/settings/view/tabs/AboutTab.tsx @@ -0,0 +1,166 @@ +import { ExternalLink, MessageSquare, Star } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; +import { IS_PLATFORM } from '../../../../constants/config'; +import { useVersionCheck } from '../../../../hooks/useVersionCheck'; +import PremiumFeatureCard from '../PremiumFeatureCard'; +import { Cloud, Users } from 'lucide-react'; + +const GITHUB_REPO_URL = 'https://github.com/siteboon/claudecodeui'; +const DISCORD_URL = 'https://discord.gg/buxwujPNRE'; +const DOCS_URL = 'https://cloudcli.ai/docs/plugin-overview'; +const CLOUDCLI_URL = 'https://cloudcli.ai'; + +function GitHubIcon({ className }: { className?: string }) { + return ( + + ); +} + +function DiscordIcon({ className }: { className?: string }) { + return ( + + ); +} + +export default function AboutTab() { + const { t } = useTranslation('settings'); + const { updateAvailable, latestVersion, currentVersion, releaseInfo } = useVersionCheck('siteboon', 'claudecodeui'); + const releasesUrl = releaseInfo?.htmlUrl || `${GITHUB_REPO_URL}/releases`; + + return ( +
+ {/* Logo + name + version */} +
+
+ +
+
+ +

+ Open-source AI coding assistant interface +

+
+
+ + {/* Star on GitHub button */} + + + + Star on GitHub + + + {/* Links */} + + + {/* Hosted CTA (OSS mode only) */} + {!IS_PLATFORM && ( +
+

Try CloudCLI Hosted

+

+ Team collaboration, shared MCP configs, settings sync across environments, and managed infrastructure. +

+ + Learn more + + +
+ )} + + {/* Premium feature placeholders (OSS mode only) */} + {!IS_PLATFORM && ( +
+

CloudCLI Pro Features

+ } + title="Sync Settings" + description="Keep your preferences, MCP configs, and theme in sync across all your environments." + /> + } + title="Team Management" + description="Multiple users, role-based access, and shared projects for your team." + /> +
+ )} + + {/* License */} +
+

+ Licensed under AGPL-3.0 +

+
+
+ ); +} diff --git a/src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx b/src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx index 9db223a1..c62f8f8f 100644 --- a/src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx +++ b/src/components/settings/view/tabs/agents-settings/sections/content/McpServersContent.tsx @@ -1,6 +1,8 @@ -import { Edit3, Globe, Plus, Server, Terminal, Trash2, Zap } from 'lucide-react'; +import { Edit3, Globe, Plus, Server, Terminal, Trash2, Users, Zap } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { Badge, Button } from '../../../../../../../shared/view/ui'; +import { IS_PLATFORM } from '../../../../../../../constants/config'; +import PremiumFeatureCard from '../../../../PremiumFeatureCard'; import type { McpServer, McpToolsResult, McpTestResult } from '../../../../../types/types'; const getTransportIcon = (type: string | undefined) => { @@ -179,6 +181,14 @@ function ClaudeMcpServers({
{t('mcpServers.empty')}
)} + + {!IS_PLATFORM && ( + } + title="Team MCP Configs" + description="Share MCP server configurations across your team. Everyone stays in sync automatically." + /> + )} ); } diff --git a/src/components/settings/view/tabs/api-settings/CredentialsSettingsTab.tsx b/src/components/settings/view/tabs/api-settings/CredentialsSettingsTab.tsx index 0f475125..89d440c3 100644 --- a/src/components/settings/view/tabs/api-settings/CredentialsSettingsTab.tsx +++ b/src/components/settings/view/tabs/api-settings/CredentialsSettingsTab.tsx @@ -1,14 +1,11 @@ import { useTranslation } from 'react-i18next'; -import { useVersionCheck } from '../../../../../hooks/useVersionCheck'; import { useCredentialsSettings } from '../../../hooks/useCredentialsSettings'; import ApiKeysSection from './sections/ApiKeysSection'; import GithubCredentialsSection from './sections/GithubCredentialsSection'; import NewApiKeyAlert from './sections/NewApiKeyAlert'; -import VersionInfoSection from './sections/VersionInfoSection'; export default function CredentialsSettingsTab() { const { t } = useTranslation('settings'); - const { updateAvailable, latestVersion, currentVersion, releaseInfo } = useVersionCheck('siteboon', 'claudecodeui'); const { apiKeys, githubCredentials, @@ -89,12 +86,6 @@ export default function CredentialsSettingsTab() { onDeleteGithubCredential={deleteGithubCredential} /> - ); } diff --git a/src/components/settings/view/tabs/api-settings/sections/VersionInfoSection.tsx b/src/components/settings/view/tabs/api-settings/sections/VersionInfoSection.tsx index 01b1fa2e..a7d5f83b 100644 --- a/src/components/settings/view/tabs/api-settings/sections/VersionInfoSection.tsx +++ b/src/components/settings/view/tabs/api-settings/sections/VersionInfoSection.tsx @@ -1,7 +1,29 @@ -import { ExternalLink } from 'lucide-react'; +import { ExternalLink, Star, MessageSquare } from 'lucide-react'; import { useTranslation } from 'react-i18next'; +import { IS_PLATFORM } from '../../../../../../constants/config'; import type { ReleaseInfo } from '../../../../../../types/sharedTypes'; +const GITHUB_REPO_URL = 'https://github.com/siteboon/claudecodeui'; +const DISCORD_URL = 'https://discord.gg/buxwujPNRE'; +const DOCS_URL = 'https://cloudcli.ai/docs/plugin-overview'; +const CLOUDCLI_URL = 'https://cloudcli.ai'; + +function GitHubIcon({ className }: { className?: string }) { + return ( + + ); +} + +function DiscordIcon({ className }: { className?: string }) { + return ( + + ); +} + type VersionInfoSectionProps = { currentVersion: string; updateAvailable: boolean; @@ -16,29 +38,115 @@ export default function VersionInfoSection({ releaseInfo, }: VersionInfoSectionProps) { const { t } = useTranslation('settings'); - const releasesUrl = releaseInfo?.htmlUrl || 'https://github.com/siteboon/claudecodeui/releases'; + const releasesUrl = releaseInfo?.htmlUrl || `${GITHUB_REPO_URL}/releases`; return (
-
+ {/* About CloudCLI */} +
+ {/* Logo + name + version */} +
+
+ +
+
+ +

+ Open-source AI coding assistant interface +

+
+
+ + {/* Star on GitHub button */} - v{currentVersion} + + + Star on GitHub - {updateAvailable && latestVersion && ( + + {/* Links */} + + + {/* Hosted CTA (OSS mode only) */} + {!IS_PLATFORM && ( +
+

Try CloudCLI Hosted

+

+ Team collaboration, shared MCP configs, settings sync across environments, and managed infrastructure. +

+ + Learn more + + +
)}
diff --git a/src/components/sidebar/view/Sidebar.tsx b/src/components/sidebar/view/Sidebar.tsx index cba08749..fefb6dca 100644 --- a/src/components/sidebar/view/Sidebar.tsx +++ b/src/components/sidebar/view/Sidebar.tsx @@ -266,6 +266,7 @@ function Sidebar({ updateAvailable={updateAvailable} releaseInfo={releaseInfo} latestVersion={latestVersion} + currentVersion={currentVersion} onShowVersionModal={() => setShowVersionModal(true)} onShowSettings={onShowSettings} projectListProps={projectListProps} diff --git a/src/components/sidebar/view/subcomponents/GitHubStarBadge.tsx b/src/components/sidebar/view/subcomponents/GitHubStarBadge.tsx new file mode 100644 index 00000000..539710c4 --- /dev/null +++ b/src/components/sidebar/view/subcomponents/GitHubStarBadge.tsx @@ -0,0 +1,48 @@ +import { Star, X } from 'lucide-react'; +import { useGitHubStars } from '../../../../hooks/useGitHubStars'; +import { IS_PLATFORM } from '../../../../constants/config'; + +const GITHUB_REPO_URL = 'https://github.com/siteboon/claudecodeui'; + +function GitHubIcon({ className }: { className?: string }) { + return ( + + ); +} + +export default function GitHubStarBadge() { + const { formattedCount, isDismissed, dismiss } = useGitHubStars('siteboon', 'claudecodeui'); + + if (IS_PLATFORM || isDismissed) return null; + + return ( +
+ + + + Star + {formattedCount && ( + {formattedCount} + )} + + +
+ ); +} diff --git a/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx b/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx index e09ceb87..90a6338f 100644 --- a/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx +++ b/src/components/sidebar/view/subcomponents/SidebarCollapsed.tsx @@ -1,7 +1,8 @@ -import { Settings, Sparkles, PanelLeftOpen } from 'lucide-react'; +import { Settings, Sparkles, PanelLeftOpen, Bug } from 'lucide-react'; import type { TFunction } from 'i18next'; const DISCORD_INVITE_URL = 'https://discord.gg/buxwujPNRE'; +const GITHUB_ISSUES_URL = 'https://github.com/siteboon/claudecodeui/issues/new'; function DiscordIcon({ className }: { className?: string }) { return ( @@ -50,6 +51,18 @@ export default function SidebarCollapsed({ + {/* Report Issue */} + + + + {/* Discord */} void; onShowSettings: () => void; projectListProps: SidebarProjectListProps; @@ -83,6 +84,7 @@ export default function SidebarContent({ updateAvailable, releaseInfo, latestVersion, + currentVersion, onShowVersionModal, onShowSettings, projectListProps, @@ -217,6 +219,7 @@ export default function SidebarContent({ updateAvailable={updateAvailable} releaseInfo={releaseInfo} latestVersion={latestVersion} + currentVersion={currentVersion} onShowVersionModal={onShowVersionModal} onShowSettings={onShowSettings} t={t} diff --git a/src/components/sidebar/view/subcomponents/SidebarFooter.tsx b/src/components/sidebar/view/subcomponents/SidebarFooter.tsx index afa0c6a1..b024be30 100644 --- a/src/components/sidebar/view/subcomponents/SidebarFooter.tsx +++ b/src/components/sidebar/view/subcomponents/SidebarFooter.tsx @@ -1,7 +1,11 @@ -import { Settings, ArrowUpCircle } from 'lucide-react'; +import { Settings, ArrowUpCircle, Bug } from 'lucide-react'; import type { TFunction } from 'i18next'; +import { IS_PLATFORM } from '../../../../constants/config'; import type { ReleaseInfo } from '../../../../types/sharedTypes'; +const GITHUB_ISSUES_URL = 'https://github.com/siteboon/claudecodeui/issues/new'; +const GITHUB_REPO_URL = 'https://github.com/siteboon/claudecodeui'; + const DISCORD_INVITE_URL = 'https://discord.gg/buxwujPNRE'; function DiscordIcon({ className }: { className?: string }) { @@ -16,6 +20,7 @@ type SidebarFooterProps = { updateAvailable: boolean; releaseInfo: ReleaseInfo | null; latestVersion: string | null; + currentVersion: string; onShowVersionModal: () => void; onShowSettings: () => void; t: TFunction; @@ -25,6 +30,7 @@ export default function SidebarFooter({ updateAvailable, releaseInfo, latestVersion, + currentVersion, onShowVersionModal, onShowSettings, t, @@ -79,11 +85,24 @@ export default function SidebarFooter({ )} - {/* Discord + Settings */} + {/* Community + Settings */}
- {/* Desktop Discord */} + {/* Desktop Report Issue */} + + {/* Desktop Discord */} + - {/* Mobile Discord */} + {/* Desktop version brand line (OSS mode only) */} + {!IS_PLATFORM && ( + + )} + + {/* Mobile Report Issue */} + + {/* Mobile Discord */} + + + {/* Search bar */} {projectsCount > 0 && !isLoading && (
diff --git a/src/hooks/useGitHubStars.ts b/src/hooks/useGitHubStars.ts new file mode 100644 index 00000000..2e731817 --- /dev/null +++ b/src/hooks/useGitHubStars.ts @@ -0,0 +1,77 @@ +import { useState, useEffect, useCallback } from 'react'; + +const CACHE_KEY = 'CLOUDCLI_GITHUB_STARS'; +const DISMISS_KEY = 'CLOUDCLI_HIDE_GITHUB_STAR'; +const CACHE_TTL = 60 * 60 * 1000; // 1 hour + +type CachedStars = { + count: number; + timestamp: number; +}; + +export const useGitHubStars = (owner: string, repo: string) => { + const [starCount, setStarCount] = useState(null); + const [isDismissed, setIsDismissed] = useState(() => { + try { + return localStorage.getItem(DISMISS_KEY) === 'true'; + } catch { + return false; + } + }); + + useEffect(() => { + if (isDismissed) return; + + // Check cache first + try { + const cached = localStorage.getItem(CACHE_KEY); + if (cached) { + const parsed: CachedStars = JSON.parse(cached); + if (Date.now() - parsed.timestamp < CACHE_TTL) { + setStarCount(parsed.count); + return; + } + } + } catch { + // ignore + } + + const fetchStars = async () => { + try { + const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`); + if (!response.ok) return; + const data = await response.json(); + const count = data.stargazers_count; + if (typeof count === 'number') { + setStarCount(count); + try { + localStorage.setItem(CACHE_KEY, JSON.stringify({ count, timestamp: Date.now() })); + } catch { + // ignore + } + } + } catch { + // silent fail + } + }; + + void fetchStars(); + }, [owner, repo, isDismissed]); + + const dismiss = useCallback(() => { + setIsDismissed(true); + try { + localStorage.setItem(DISMISS_KEY, 'true'); + } catch { + // ignore + } + }, []); + + const formattedCount = starCount !== null + ? starCount >= 1000 + ? `${(starCount / 1000).toFixed(1)}k` + : `${starCount}` + : null; + + return { starCount, formattedCount, isDismissed, dismiss }; +}; diff --git a/src/i18n/locales/de/auth.json b/src/i18n/locales/de/auth.json index 9b8327cb..0a1d5226 100644 --- a/src/i18n/locales/de/auth.json +++ b/src/i18n/locales/de/auth.json @@ -1,7 +1,7 @@ { "login": { "title": "Willkommen zurück", - "description": "Meld dich bei deinem Claude Code UI-Konto an", + "description": "Meld dich bei deinem CloudCLI-Konto an", "username": "Benutzername", "password": "Passwort", "submit": "Anmelden", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 1b1d4c7d..bc4c7473 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -84,7 +84,7 @@ "openInEditor": "Im Editor öffnen" }, "mainContent": { - "loading": "Claude Code UI wird geladen", + "loading": "CloudCLI wird geladen", "settingUpWorkspace": "Arbeitsbereich wird eingerichtet...", "chooseProject": "Projekt auswählen", "selectProjectDescription": "Wähl ein Projekt aus der Seitenleiste, um mit Claude zu programmieren. Jedes Projekt enthält deine Chat-Sitzungen und den Dateiverlauf.", diff --git a/src/i18n/locales/de/settings.json b/src/i18n/locales/de/settings.json index 25c289dd..84f5e2db 100644 --- a/src/i18n/locales/de/settings.json +++ b/src/i18n/locales/de/settings.json @@ -105,7 +105,8 @@ "git": "Git", "apiTokens": "API & Token", "tasks": "Aufgaben", - "plugins": "Plugins" + "plugins": "Plugins", + "about": "Info" }, "appearanceSettings": { "darkMode": { diff --git a/src/i18n/locales/de/sidebar.json b/src/i18n/locales/de/sidebar.json index 8727f103..8b26756c 100644 --- a/src/i18n/locales/de/sidebar.json +++ b/src/i18n/locales/de/sidebar.json @@ -20,7 +20,7 @@ "runClaudeCli": "Führ Claude CLI in einem Projektverzeichnis aus, um zu beginnen" }, "app": { - "title": "Claude Code UI", + "title": "CloudCLI", "subtitle": "KI-Programmierassistent-Oberfläche" }, "sessions": { @@ -65,7 +65,12 @@ "save": "Speichern", "delete": "Löschen", "rename": "Umbenennen", - "joinCommunity": "Community beitreten" + "joinCommunity": "Community beitreten", + "reportIssue": "Problem melden", + "starOnGithub": "Stern auf GitHub" + }, + "branding": { + "openSource": "Open Source" }, "status": { "active": "Aktiv", diff --git a/src/i18n/locales/en/auth.json b/src/i18n/locales/en/auth.json index 2788855f..5ca25fd2 100644 --- a/src/i18n/locales/en/auth.json +++ b/src/i18n/locales/en/auth.json @@ -1,7 +1,7 @@ { "login": { "title": "Welcome Back", - "description": "Sign in to your Claude Code UI account", + "description": "Sign in to your CloudCLI self-hosted account", "username": "Username", "password": "Password", "submit": "Sign In", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 928bdaf1..0d25fedf 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -84,7 +84,7 @@ "openInEditor": "Open in Editor" }, "mainContent": { - "loading": "Loading Claude Code UI", + "loading": "Loading CloudCLI", "settingUpWorkspace": "Setting up your workspace...", "chooseProject": "Choose Your Project", "selectProjectDescription": "Select a project from the sidebar to start coding with Claude. Each project contains your chat sessions and file history.", diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json index 8596e045..ce3de906 100644 --- a/src/i18n/locales/en/settings.json +++ b/src/i18n/locales/en/settings.json @@ -106,8 +106,8 @@ "apiTokens": "API & Tokens", "tasks": "Tasks", "notifications": "Notifications", - "plugins": "Plugins" - + "plugins": "Plugins", + "about": "About" }, "notifications": { "title": "Notifications", diff --git a/src/i18n/locales/en/sidebar.json b/src/i18n/locales/en/sidebar.json index a56c1b84..eab0a3f3 100644 --- a/src/i18n/locales/en/sidebar.json +++ b/src/i18n/locales/en/sidebar.json @@ -20,7 +20,7 @@ "runClaudeCli": "Run Claude CLI in a project directory to get started" }, "app": { - "title": "Claude Code UI", + "title": "CloudCLI", "subtitle": "AI coding assistant interface" }, "sessions": { @@ -65,7 +65,12 @@ "save": "Save", "delete": "Delete", "rename": "Rename", - "joinCommunity": "Join Community" + "joinCommunity": "Join Community", + "reportIssue": "Report Issue", + "starOnGithub": "Star on GitHub" + }, + "branding": { + "openSource": "Open Source" }, "status": { "active": "Active", diff --git a/src/i18n/locales/ja/auth.json b/src/i18n/locales/ja/auth.json index ce946497..d1ba9fd8 100644 --- a/src/i18n/locales/ja/auth.json +++ b/src/i18n/locales/ja/auth.json @@ -1,7 +1,7 @@ { "login": { "title": "おかえりなさい", - "description": "Claude Code UIアカウントにサインイン", + "description": "CloudCLIアカウントにサインイン", "username": "ユーザー名", "password": "パスワード", "submit": "サインイン", diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 59c33c98..097eb057 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -84,7 +84,7 @@ "openInEditor": "エディタで開く" }, "mainContent": { - "loading": "Claude Code UI を読み込んでいます", + "loading": "CloudCLI を読み込んでいます", "settingUpWorkspace": "ワークスペースを準備しています...", "chooseProject": "プロジェクトを選択", "selectProjectDescription": "サイドバーからプロジェクトを選択して、Claudeとコーディングを始めましょう。各プロジェクトにはチャットセッションとファイル履歴が含まれています。", diff --git a/src/i18n/locales/ja/settings.json b/src/i18n/locales/ja/settings.json index 60b454ca..c9cc282d 100644 --- a/src/i18n/locales/ja/settings.json +++ b/src/i18n/locales/ja/settings.json @@ -106,8 +106,8 @@ "apiTokens": "API & トークン", "tasks": "タスク", "notifications": "通知", - "plugins": "プラグイン" - + "plugins": "プラグイン", + "about": "概要" }, "notifications": { "title": "通知", diff --git a/src/i18n/locales/ja/sidebar.json b/src/i18n/locales/ja/sidebar.json index 17813411..4590c752 100644 --- a/src/i18n/locales/ja/sidebar.json +++ b/src/i18n/locales/ja/sidebar.json @@ -20,7 +20,7 @@ "runClaudeCli": "プロジェクトディレクトリでClaude CLIを実行して始めましょう" }, "app": { - "title": "Claude Code UI", + "title": "CloudCLI", "subtitle": "AIコーディングアシスタント" }, "sessions": { @@ -64,7 +64,12 @@ "save": "保存", "delete": "削除", "rename": "名前の変更", - "joinCommunity": "コミュニティに参加" + "joinCommunity": "コミュニティに参加", + "reportIssue": "問題を報告", + "starOnGithub": "GitHubでスター" + }, + "branding": { + "openSource": "オープンソース" }, "status": { "active": "アクティブ", diff --git a/src/i18n/locales/ko/auth.json b/src/i18n/locales/ko/auth.json index ebfef608..08f09e74 100644 --- a/src/i18n/locales/ko/auth.json +++ b/src/i18n/locales/ko/auth.json @@ -1,7 +1,7 @@ { "login": { "title": "다시 오신 것을 환영합니다", - "description": "Claude Code UI 계정에 로그인하세요", + "description": "CloudCLI 계정에 로그인하세요", "username": "사용자명", "password": "비밀번호", "submit": "로그인", diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 95004280..b3554401 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -84,7 +84,7 @@ "openInEditor": "에디터에서 열기" }, "mainContent": { - "loading": "Claude Code UI 로딩 중", + "loading": "CloudCLI 로딩 중", "settingUpWorkspace": "워크스페이스 설정 중...", "chooseProject": "프로젝트 선택", "selectProjectDescription": "사이드바에서 프로젝트를 선택하여 Claude와 코딩을 시작하세요. 각 프로젝트에는 채팅 세션과 파일 히스토리가 포함됩니다.", diff --git a/src/i18n/locales/ko/settings.json b/src/i18n/locales/ko/settings.json index b8a1f450..1071cc37 100644 --- a/src/i18n/locales/ko/settings.json +++ b/src/i18n/locales/ko/settings.json @@ -106,8 +106,8 @@ "apiTokens": "API & 토큰", "tasks": "작업", "notifications": "알림", - "plugins": "플러그인" - + "plugins": "플러그인", + "about": "정보" }, "notifications": { "title": "알림", diff --git a/src/i18n/locales/ko/sidebar.json b/src/i18n/locales/ko/sidebar.json index 2eaca911..cda7eab2 100644 --- a/src/i18n/locales/ko/sidebar.json +++ b/src/i18n/locales/ko/sidebar.json @@ -20,7 +20,7 @@ "runClaudeCli": "프로젝트 디렉토리에서 Claude CLI를 실행하여 시작하세요" }, "app": { - "title": "Claude Code UI", + "title": "CloudCLI", "subtitle": "AI 코딩 어시스턴트 UI" }, "sessions": { @@ -64,7 +64,12 @@ "save": "저장", "delete": "삭제", "rename": "이름 변경", - "joinCommunity": "커뮤니티 참여" + "joinCommunity": "커뮤니티 참여", + "reportIssue": "문제 신고", + "starOnGithub": "GitHub에서 스타" + }, + "branding": { + "openSource": "오픈 소스" }, "status": { "active": "활성", diff --git a/src/i18n/locales/ru/auth.json b/src/i18n/locales/ru/auth.json index b81fd562..919a4a30 100644 --- a/src/i18n/locales/ru/auth.json +++ b/src/i18n/locales/ru/auth.json @@ -1,7 +1,7 @@ { "login": { "title": "Добро пожаловать", - "description": "Войдите в свой аккаунт Claude Code UI", + "description": "Войдите в свой аккаунт CloudCLI", "username": "Имя пользователя", "password": "Пароль", "submit": "Войти", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 665ab6f8..906b78eb 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -84,7 +84,7 @@ "openInEditor": "Открыть в редакторе" }, "mainContent": { - "loading": "Загрузка Claude Code UI", + "loading": "Загрузка CloudCLI", "settingUpWorkspace": "Настройка рабочего пространства...", "chooseProject": "Выберите проект", "selectProjectDescription": "Выберите проект на боковой панели, чтобы начать работу с Claude. Каждый проект содержит ваши сеансы чата и историю файлов.", diff --git a/src/i18n/locales/ru/settings.json b/src/i18n/locales/ru/settings.json index f8991ab0..da287733 100644 --- a/src/i18n/locales/ru/settings.json +++ b/src/i18n/locales/ru/settings.json @@ -105,7 +105,8 @@ "git": "Git", "apiTokens": "API и токены", "tasks": "Задачи", - "plugins": "Плагины" + "plugins": "Плагины", + "about": "О программе" }, "appearanceSettings": { "darkMode": { diff --git a/src/i18n/locales/ru/sidebar.json b/src/i18n/locales/ru/sidebar.json index d79a9d3d..71250d2f 100644 --- a/src/i18n/locales/ru/sidebar.json +++ b/src/i18n/locales/ru/sidebar.json @@ -20,7 +20,7 @@ "runClaudeCli": "Запустите Claude CLI в каталоге проекта для начала работы" }, "app": { - "title": "Claude Code UI", + "title": "CloudCLI", "subtitle": "Интерфейс AI помощника для программирования" }, "sessions": { @@ -65,7 +65,12 @@ "save": "Сохранить", "delete": "Удалить", "rename": "Переименовать", - "joinCommunity": "Присоединиться к сообществу" + "joinCommunity": "Присоединиться к сообществу", + "reportIssue": "Сообщить о проблеме", + "starOnGithub": "Звезда на GitHub" + }, + "branding": { + "openSource": "Открытый исходный код" }, "status": { "active": "Активен", diff --git a/src/i18n/locales/zh-CN/auth.json b/src/i18n/locales/zh-CN/auth.json index 3905c2bd..3d790f37 100644 --- a/src/i18n/locales/zh-CN/auth.json +++ b/src/i18n/locales/zh-CN/auth.json @@ -1,7 +1,7 @@ { "login": { "title": "欢迎回来", - "description": "登录您的 Claude Code UI 账户", + "description": "登录您的 CloudCLI 账户", "username": "用户名", "password": "密码", "submit": "登录", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 710daf5e..936fe5b2 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -84,7 +84,7 @@ "openInEditor": "在编辑器中打开" }, "mainContent": { - "loading": "正在加载 Claude Code UI", + "loading": "正在加载 CloudCLI", "settingUpWorkspace": "正在设置您的工作空间...", "chooseProject": "选择您的项目", "selectProjectDescription": "从侧边栏选择一个项目以开始使用 Claude 进行编程。每个项目包含您的聊天会话和文件历史。", diff --git a/src/i18n/locales/zh-CN/settings.json b/src/i18n/locales/zh-CN/settings.json index d9f2b2cd..789eb612 100644 --- a/src/i18n/locales/zh-CN/settings.json +++ b/src/i18n/locales/zh-CN/settings.json @@ -106,8 +106,8 @@ "apiTokens": "API 和令牌", "tasks": "任务", "notifications": "通知", - "plugins": "插件" - + "plugins": "插件", + "about": "关于" }, "notifications": { "title": "通知", diff --git a/src/i18n/locales/zh-CN/sidebar.json b/src/i18n/locales/zh-CN/sidebar.json index 27cacec5..3a28778c 100644 --- a/src/i18n/locales/zh-CN/sidebar.json +++ b/src/i18n/locales/zh-CN/sidebar.json @@ -20,7 +20,7 @@ "runClaudeCli": "在项目目录中运行 Claude CLI 以开始使用" }, "app": { - "title": "Claude Code UI", + "title": "CloudCLI", "subtitle": "AI 编程助手" }, "sessions": { @@ -65,7 +65,12 @@ "save": "保存", "delete": "删除", "rename": "重命名", - "joinCommunity": "加入社区" + "joinCommunity": "加入社区", + "reportIssue": "报告问题", + "starOnGithub": "在GitHub上加星" + }, + "branding": { + "openSource": "开源" }, "status": { "active": "活动",