From b359c515277b4266fde2fb9a29b5356949c07c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?X=C3=AC=20G=C3=A0?= Date: Fri, 27 Feb 2026 22:28:10 +0700 Subject: [PATCH 1/6] feat: add copy icon for user messages (#449) * feat: add copy icon for user messages Expose a copy control on user chat bubbles so previous content can be reused quickly. * fix: Copy control is effectively hidden on touch devices * fix: copyTextToClipboard doesn't need timer --------- Co-authored-by: dev Co-authored-by: Haileyesus <118998054+blackmammoth@users.noreply.github.com> --- .../view/subcomponents/MessageComponent.tsx | 45 +++++++++++++++++-- src/i18n/locales/en/chat.json | 4 ++ src/i18n/locales/ja/chat.json | 4 ++ src/i18n/locales/ko/chat.json | 4 ++ src/i18n/locales/zh-CN/chat.json | 4 ++ 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/components/chat/view/subcomponents/MessageComponent.tsx b/src/components/chat/view/subcomponents/MessageComponent.tsx index 2abc1700..fe12f427 100644 --- a/src/components/chat/view/subcomponents/MessageComponent.tsx +++ b/src/components/chat/view/subcomponents/MessageComponent.tsx @@ -10,6 +10,7 @@ import type { import { Markdown } from './Markdown'; import { formatUsageLimitText } from '../../utils/chatFormatting'; import { getClaudePermissionSuggestion } from '../../utils/chatPermissions'; +import { copyTextToClipboard } from '../../../../utils/clipboard'; import type { Project } from '../../../../types/app'; import { ToolRenderer, shouldHideToolResult } from '../../tools'; @@ -53,6 +54,7 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile const [isExpanded, setIsExpanded] = React.useState(false); const permissionSuggestion = getClaudePermissionSuggestion(message, provider); const [permissionGrantState, setPermissionGrantState] = React.useState('idle'); + const [messageCopied, setMessageCopied] = React.useState(false); React.useEffect(() => { @@ -100,7 +102,7 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile {message.type === 'user' ? ( /* User message bubble on the right */
-
+
{message.content}
@@ -117,8 +119,45 @@ const MessageComponent = memo(({ message, index, prevMessage, createDiff, onFile ))}
)} -
- {formattedTime} +
+ + {formattedTime}
{!isGrouped && ( diff --git a/src/i18n/locales/en/chat.json b/src/i18n/locales/en/chat.json index b907f180..dc2b3109 100644 --- a/src/i18n/locales/en/chat.json +++ b/src/i18n/locales/en/chat.json @@ -4,6 +4,10 @@ "copied": "Copied", "copyCode": "Copy code" }, + "copyMessage": { + "copy": "Copy message", + "copied": "Message copied" + }, "messageTypes": { "user": "U", "error": "Error", diff --git a/src/i18n/locales/ja/chat.json b/src/i18n/locales/ja/chat.json index 0d81a1ad..2c3dda4d 100644 --- a/src/i18n/locales/ja/chat.json +++ b/src/i18n/locales/ja/chat.json @@ -4,6 +4,10 @@ "copied": "コピーしました", "copyCode": "コードをコピー" }, + "copyMessage": { + "copy": "メッセージをコピー", + "copied": "メッセージをコピーしました" + }, "messageTypes": { "user": "U", "error": "エラー", diff --git a/src/i18n/locales/ko/chat.json b/src/i18n/locales/ko/chat.json index cddc89af..ca66e3a9 100644 --- a/src/i18n/locales/ko/chat.json +++ b/src/i18n/locales/ko/chat.json @@ -4,6 +4,10 @@ "copied": "복사됨", "copyCode": "코드 복사" }, + "copyMessage": { + "copy": "메시지 복사", + "copied": "메시지 복사됨" + }, "messageTypes": { "user": "U", "error": "오류", diff --git a/src/i18n/locales/zh-CN/chat.json b/src/i18n/locales/zh-CN/chat.json index 678ea171..1fdbc462 100644 --- a/src/i18n/locales/zh-CN/chat.json +++ b/src/i18n/locales/zh-CN/chat.json @@ -4,6 +4,10 @@ "copied": "已复制", "copyCode": "复制代码" }, + "copyMessage": { + "copy": "复制消息", + "copied": "消息已复制" + }, "messageTypes": { "user": "U", "error": "错误", From d19b1e949f458642794f4908e45c7b23383f242f Mon Sep 17 00:00:00 2001 From: simosmik Date: Fri, 27 Feb 2026 15:41:20 +0000 Subject: [PATCH 2/6] Release 1.21.0 --- CHANGELOG.md | 17 +++++++++++++++++ package-lock.json | 4 ++-- package.json | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73a2a6bf..7a6e12c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to CloudCLI UI will be documented in this file. +## [1.21.0](https://github.com/siteboon/claudecodeui/compare/v1.20.1...v1.21.0) (2026-02-27) + +### New Features + +* add copy icon for user messages ([#449](https://github.com/siteboon/claudecodeui/issues/449)) ([b359c51](https://github.com/siteboon/claudecodeui/commit/b359c515277b4266fde2fb9a29b5356949c07c4f)) +* Google's gemini-cli integration ([#422](https://github.com/siteboon/claudecodeui/issues/422)) ([a367edd](https://github.com/siteboon/claudecodeui/commit/a367edd51578608b3281373cb4a95169dbf17f89)) +* persist active tab across reloads via localStorage ([#414](https://github.com/siteboon/claudecodeui/issues/414)) ([e3b6892](https://github.com/siteboon/claudecodeui/commit/e3b689214f11d549ffe1b3a347476d58f25c5aca)), closes [#387](https://github.com/siteboon/claudecodeui/issues/387) + +### Bug Fixes + +* add support for Codex in the shell ([#424](https://github.com/siteboon/claudecodeui/issues/424)) ([23801e9](https://github.com/siteboon/claudecodeui/commit/23801e9cc15d2b8d1bfc6e39aee2fae93226d1ad)) + +### Maintenance + +* upgrade @anthropic-ai/claude-agent-sdk to version 0.2.59 and add model usage logging ([#446](https://github.com/siteboon/claudecodeui/issues/446)) ([917c353](https://github.com/siteboon/claudecodeui/commit/917c353115653ee288bf97be01f62fad24123cbc)) +* upgrade better-sqlite to latest version to support node 25 ([#445](https://github.com/siteboon/claudecodeui/issues/445)) ([4ab94fc](https://github.com/siteboon/claudecodeui/commit/4ab94fce4257e1e20370fa83fa4c0f6fadbb8a2b)) + ## [1.20.1](https://github.com/siteboon/claudecodeui/compare/v1.19.1...v1.20.1) (2026-02-23) ### New Features diff --git a/package-lock.json b/package-lock.json index 9d42e3a5..13c1b401 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@siteboon/claude-code-ui", - "version": "1.20.1", + "version": "1.21.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@siteboon/claude-code-ui", - "version": "1.20.1", + "version": "1.21.0", "hasInstallScript": true, "license": "GPL-3.0", "dependencies": { diff --git a/package.json b/package.json index f2f52c6f..bf3770d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@siteboon/claude-code-ui", - "version": "1.20.1", + "version": "1.21.0", "description": "A web-based UI for Claude Code CLI", "type": "module", "main": "server/index.js", @@ -118,4 +118,4 @@ "typescript": "^5.9.3", "vite": "^7.0.4" } -} \ No newline at end of file +} From 9c0e864532dcc5ce7ee890d3b4db722872db2b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?X=C3=AC=20G=C3=A0?= Date: Fri, 27 Feb 2026 22:46:23 +0700 Subject: [PATCH 3/6] fix(claude): correct project encoded path (#451) fix wrong regex replace of Claude project path related #447, reopen due to forced-push to reproduce error steps, let's try Create a folder with @ in name like @test Add this folder as new project in CloudCLI Choose Claude tool in new Session Star by typing sth 'hi' In the dev tools, you will see errors ajax response said that session does not find for 'some-session-id' The main problem is current encode path doesn't encode '@' to '-' as Claude did I reversed code Claude-SDK, file 'cli.js' to find exactly regex (using in PR) that used to encode path under ~/.claude/projects/.jsonl --- server/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/index.js b/server/index.js index 497ed874..352dd7e5 100755 --- a/server/index.js +++ b/server/index.js @@ -1218,7 +1218,7 @@ function handleShellConnection(ws) { if (hasSession && sessionId) { try { // Gemini CLI enforces its own native session IDs, unlike other agents that accept arbitrary string names. - // The UI only knows about its internal generated `sessionId` (e.g. gemini_1234). + // The UI only knows about its internal generated `sessionId` (e.g. gemini_1234). // We must fetch the mapping from the backend session manager to pass the native `cliSessionId` to the shell. const sess = sessionManager.getSession(sessionId); if (sess && sess.cliSessionId) { @@ -1791,8 +1791,8 @@ app.get('/api/projects/:projectName/sessions/:sessionId/token-usage', authentica // Construct the JSONL file path // Claude stores session files in ~/.claude/projects/[encoded-project-path]/[session-id].jsonl - // The encoding replaces /, spaces, ~, and _ with - - const encodedPath = projectPath.replace(/[\\/:\s~_]/g, '-'); + // The encoding replaces any non-alphanumeric character (except -) with - + const encodedPath = projectPath.replace(/[^a-zA-Z0-9-]/g, '-'); const projectDir = path.join(homeDir, '.claude', 'projects', encodedPath); const jsonlPath = path.join(projectDir, `${safeSessionId}.jsonl`); From 9e22f42a3d3a781f448ddac9d133292fe103bb8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?X=C3=AC=20G=C3=A0?= Date: Fri, 27 Feb 2026 22:51:26 +0700 Subject: [PATCH 4/6] feat: update document title based on selected project (#448) Show dynamic browser tab title based on selected project's name, post-fixed with "CloudCLI UI" when a project is selected, improving navigation across tabs. --- .../sidebar/view/subcomponents/SidebarProjectList.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/sidebar/view/subcomponents/SidebarProjectList.tsx b/src/components/sidebar/view/subcomponents/SidebarProjectList.tsx index 55710638..1e1dbd55 100644 --- a/src/components/sidebar/view/subcomponents/SidebarProjectList.tsx +++ b/src/components/sidebar/view/subcomponents/SidebarProjectList.tsx @@ -1,3 +1,4 @@ +import { useEffect } from 'react'; import type { TFunction } from 'i18next'; import type { LoadingProgress, Project, ProjectSession, SessionProvider } from '../../../../types/app'; import type { @@ -103,6 +104,15 @@ export default function SidebarProjectList({ /> ); + useEffect(() => { + let baseTitle = 'CloudCLI UI'; + const displayName = selectedProject?.displayName?.trim(); + if (displayName) { + baseTitle = `${displayName} - ${baseTitle}`; + } + document.title = baseTitle; + }, [selectedProject]); + const showProjects = !isLoading && projects.length > 0 && filteredProjects.length > 0; return ( From 506d43144b3ec3155c3e589e7e803862c4a8f83a Mon Sep 17 00:00:00 2001 From: louis-thorp-datacom Date: Mon, 2 Mar 2026 20:49:06 +1300 Subject: [PATCH 5/6] fix(claude): move model usage log to result message only (#454) The modelUsage debug log ran on every streamed SDK message, but modelUsage is only populated on result messages. This produced repeated "Model was sent using: []" console output for every non-result message during streaming. Co-authored-by: Claude Opus 4.6 --- server/claude-sdk.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/claude-sdk.js b/server/claude-sdk.js index 485aa55f..3ba6ea24 100644 --- a/server/claude-sdk.js +++ b/server/claude-sdk.js @@ -593,9 +593,6 @@ async function queryClaudeSDK(command, options = {}, ws) { console.log('No session_id in message or already captured. message.session_id:', message.session_id, 'capturedSessionId:', capturedSessionId); } - // logs which model was used in the message - console.log("---> Model was sent using:", Object.keys(message.modelUsage || {})); - // Transform and send message to WebSocket const transformedMessage = transformMessage(message); ws.send({ @@ -606,6 +603,10 @@ async function queryClaudeSDK(command, options = {}, ws) { // Extract and send token budget updates from result messages if (message.type === 'result') { + const models = Object.keys(message.modelUsage || {}); + if (models.length > 0) { + console.log("---> Model was sent using:", models); + } const tokenBudget = extractTokenBudget(message); if (tokenBudget) { console.log('Token budget from modelUsage:', tokenBudget); From 503c3846850fb843781979b0c0e10a24b07e1a4b Mon Sep 17 00:00:00 2001 From: Menny Even Danan Date: Mon, 2 Mar 2026 02:56:36 -0500 Subject: [PATCH 6/6] chore: add Gemini-CLI support to README (#453) --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7b5d5dda..209a74da 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
-A desktop and mobile UI for [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor CLI](https://docs.cursor.com/en/cli/overview) and [Codex](https://developers.openai.com/codex). You can use it locally or remotely to view your active projects and sessions in Claude Code, Cursor, or Codex and make changes to them from everywhere (mobile or desktop). This gives you a proper interface that works everywhere. +A desktop and mobile UI for [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor CLI](https://docs.cursor.com/en/cli/overview), [Codex](https://developers.openai.com/codex), and [Gemini-CLI](https://geminicli.com/). You can use it locally or remotely to view your active projects and sessions and make changes to them from everywhere (mobile or desktop). This gives you a proper interface that works everywhere. siteboon%2Fclaudecodeui | Trendshift
English · 한국어 · 中文 · 日本語
@@ -44,14 +44,14 @@ A desktop and mobile UI for [Claude Code](https://docs.anthropic.com/en/docs/cla ## Features -- **Responsive Design** - Works seamlessly across desktop, tablet, and mobile so you can also use Claude Code, Cursor, or Codex from mobile -- **Interactive Chat Interface** - Built-in chat interface for seamless communication with Claude Code, Cursor, or Codex -- **Integrated Shell Terminal** - Direct access to Claude Code, Cursor CLI, or Codex through built-in shell functionality +- **Responsive Design** - Works seamlessly across desktop, tablet, and mobile so you can also use Agents from mobile +- **Interactive Chat Interface** - Built-in chat interface for seamless communication with the Agents +- **Integrated Shell Terminal** - Direct access to the Agents CLI through built-in shell functionality - **File Explorer** - Interactive file tree with syntax highlighting and live editing - **Git Explorer** - View, stage and commit your changes. You can also switch branches - **Session Management** - Resume conversations, manage multiple sessions, and track history - **TaskMaster AI Integration** *(Optional)* - Advanced project management with AI-powered task planning, PRD parsing, and workflow automation -- **Model Compatibility** - Works with Claude Sonnet 4.5, Opus 4.5, and GPT-5.2 +- **Model Compatibility** - Works with Claude Sonnet 4.5, Opus 4.5, GPT-5.2, and Gemini. ## Quick Start @@ -61,7 +61,8 @@ A desktop and mobile UI for [Claude Code](https://docs.anthropic.com/en/docs/cla - [Node.js](https://nodejs.org/) v22 or higher - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and configured, and/or - [Cursor CLI](https://docs.cursor.com/en/cli/overview) installed and configured, and/or -- [Codex](https://developers.openai.com/codex) installed and configured +- [Codex](https://developers.openai.com/codex) installed and configured, and/or +- [Gemini-CLI](https://geminicli.com/) installed and configured ### One-click Operation (Recommended) @@ -279,7 +280,7 @@ session counts ### Backend (Node.js + Express) - **Express Server** - RESTful API with static file serving - **WebSocket Server** - Communication for chats and project refresh -- **Agent Integration (Claude Code / Cursor CLI / Codex)** - Process spawning and management +- **Agent Integration (Claude Code / Cursor CLI / Codex / Gemini CLI)** - Process spawning and management - **File System API** - Exposing file browser for projects ### Frontend (React + Vite) @@ -327,6 +328,7 @@ This project is open source and free to use, modify, and distribute under the GP - **[Claude Code](https://docs.anthropic.com/en/docs/claude-code)** - Anthropic's official CLI - **[Cursor CLI](https://docs.cursor.com/en/cli/overview)** - Cursor's official CLI - **[Codex](https://developers.openai.com/codex)** - OpenAI Codex +- **[Gemini-CLI](https://geminicli.com/)** - Google Gemini CLI - **[React](https://react.dev/)** - User interface library - **[Vite](https://vitejs.dev/)** - Fast build tool and dev server - **[Tailwind CSS](https://tailwindcss.com/)** - Utility-first CSS framework