Compare commits

...

21 Commits

Author SHA1 Message Date
Haileyesus
21b0f14e7a chore: add github issues board plugin 2026-06-11 14:00:41 +03:00
Simos Mikelatos
f12af8a61b Merge pull request #864 from siteboon/chore/add-plugins
chore: add plugins
2026-06-11 09:51:07 +02:00
Haileyesus
f549bd99e7 docs: update available plugin readmes 2026-06-10 16:57:40 +03:00
Haileyesus
bc34085af9 chore: add more plugins list 2026-06-10 16:49:38 +03:00
Simos Mikelatos
6a53c31e90 feat: render changelog as markdown in version upgrade modal 2026-06-09 20:53:15 +00:00
Simos Mikelatos
92de0ed613 chore: remove unused modelConstants from the project 2026-06-09 20:51:19 +00:00
viper151
b6a45b3183 chore(release): v1.34.0 2026-06-09 20:34:48 +00:00
Simos Mikelatos
ce327b6fa9 feat: adding Fable 5 in claude code 2026-06-09 20:33:00 +00:00
viper151
276639099b chore(release): v1.33.3 2026-06-09 16:18:59 +00:00
Simos Mikelatos
f4f88318c2 Merge pull request #853 from siteboon/feature/chat-completion-notifications
feat: signal when chat runs complete
2026-06-09 18:14:53 +02:00
Simos Mikelatos
029d159592 Merge branch 'main' into feature/chat-completion-notifications 2026-06-09 18:13:42 +02:00
Simos Mikelatos
7c9ec8fa12 Merge pull request #859 from jakeefr/fix/editor-toolbar-offscreen-796
fix: keep editor toolbar in view on long unwrapped lines
2026-06-09 18:10:37 +02:00
Simos Mikelatos
1b4d4b7278 Merge branch 'main' into fix/editor-toolbar-offscreen-796 2026-06-09 18:10:28 +02:00
Simos Mikelatos
b1a0afe9e0 Merge pull request #856 from bourgois/fix/chat-initial-scroll-reanchor
fix(chat): re-anchor initial scroll across lazy content reflow
2026-06-09 18:06:17 +02:00
Simos Mikelatos
88eb2009bb Merge branch 'main' into fix/chat-initial-scroll-reanchor 2026-06-09 18:05:41 +02:00
Simos Mikelatos
602e6ad4ac fix: address notification review feedback 2026-06-09 16:04:15 +00:00
Simos Mikelatos
4a2453fe32 Merge pull request #848 from siteboon/chore/add-prism-plugin
chore: add prism plugin
2026-06-09 17:46:56 +02:00
Simos Mikelatos
23210bc40e Merge branch 'main' into feature/chat-completion-notifications 2026-06-09 17:39:56 +02:00
Jake
beae8c6513 fix: keep editor toolbar in view on long unwrapped lines 2026-06-09 10:38:27 -05:00
ShockStruck
33a4e72ca4 fix(chat): re-anchor initial scroll across lazy content reflow
The previous initial-scroll behavior fired one scrollToBottom() at
+200ms after the session load and cleared the pending flag. When
markdown, syntax highlighting, or images finished rendering after
that window, scrollHeight grew but nothing re-anchored the viewport.
The chat tab appeared "scrolled way up" with the latest assistant
message off-screen until the user manually scrolled or sent a new
message.

This replaces the setTimeout with a requestAnimationFrame loop that
re-scrolls every frame while scrollHeight is still growing, capped
at ~1s (60 frames) or 3 consecutive stable frames. The loop cancels
cleanly on session change via the existing pendingInitialScrollRef
flag, and the cleanup function cancels any in-flight rAF on unmount.

No behavior change for sessions whose content layout is already stable
at the first frame.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-09 15:39:26 +02:00
Haileyesus
d70dc077bf feat: signal when chat runs complete
Users can miss chat completions while the app is in the background.

They can also miss completions when their attention is elsewhere.

Add opt-out sound notifications and a temporary title marker.

This makes completion noticeable without external audio assets or persistent browser notifications.
2026-06-09 13:51:51 +03:00
39 changed files with 644 additions and 895 deletions

View File

@@ -3,6 +3,33 @@
All notable changes to CloudCLI UI will be documented in this file.
## [](https://github.com/siteboon/claudecodeui/compare/v1.33.3...vnull) (2026-06-09)
### New Features
* adding Fable 5 in claude code ([ce327b6](https://github.com/siteboon/claudecodeui/commit/ce327b6fa9329aa3e9a3a1da7225ca01d3b06ac5))
## [1.33.3](https://github.com/siteboon/claudecodeui/compare/v1.33.2...v1.33.3) (2026-06-09)
### New Features
* add file tree upload progress ([c235b05](https://github.com/siteboon/claudecodeui/commit/c235b05e1d3b626667dba4043b685512e3cd3d5d))
* signal when chat runs complete ([d70dc07](https://github.com/siteboon/claudecodeui/commit/d70dc077bfbbfcf2ff4fa5514fabf7b4485861fa))
### Bug Fixes
* address notification review feedback ([602e6ad](https://github.com/siteboon/claudecodeui/commit/602e6ad4acba612a7ea66fb3bc7485054f5675ee))
* align prism plugin name and id with manifest.json ([ca8fd0e](https://github.com/siteboon/claudecodeui/commit/ca8fd0ee235b6a3210157bd0d9af83024d4a2248))
* **chat:** re-anchor initial scroll across lazy content reflow ([33a4e72](https://github.com/siteboon/claudecodeui/commit/33a4e72ca4f84df60aadfc4ff3f3467d6f5ae948))
* keep editor toolbar in view on long unwrapped lines ([beae8c6](https://github.com/siteboon/claudecodeui/commit/beae8c6513daa7518b9de40d8bfde3bf08e7bc87))
* **sandbox:** prevent server SIGHUP on sbx exec exit ([#792](https://github.com/siteboon/claudecodeui/issues/792)) ([f4a1614](https://github.com/siteboon/claudecodeui/commit/f4a1614a0a4ab4b65e8368d5e4221f015cb7555d)), closes [#791](https://github.com/siteboon/claudecodeui/issues/791)
* slash command suggestions trigger at any / in input, not only at start ([#843](https://github.com/siteboon/claudecodeui/issues/843)) ([f7c0024](https://github.com/siteboon/claudecodeui/commit/f7c0024fe15057ad049c71e15e88adb482a4497f))
* update naming convention ([3cd8995](https://github.com/siteboon/claudecodeui/commit/3cd89956ba06f0fc3e17d349b0c50baab4012658))
### Maintenance
* add prism plugin ([01dbe2a](https://github.com/siteboon/claudecodeui/commit/01dbe2a8bfcb3b265995f01f905b218d5f576f7b))
## [1.33.2](https://github.com/siteboon/claudecodeui/compare/v1.33.1...v1.33.2) (2026-06-08)
### New Features

View File

@@ -62,7 +62,7 @@
- **Sitzungsverwaltung** Gespräche fortsetzen, mehrere Sitzungen verwalten und Verlauf nachverfolgen
- **Plugin-System** CloudCLI mit eigenen Plugins erweitern neue Tabs, Backend-Dienste und Integrationen hinzufügen. [Eigenes Plugin erstellen →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI Integration** *(Optional)* Erweitertes Projektmanagement mit KI-gestützter Aufgabenplanung, PRD-Parsing und Workflow-Automatisierung
- **Modell-Kompatibilität** Funktioniert mit Claude, GPT und Gemini (vollständige Liste unterstützter Modelle in [`public/modelConstants.js`](public/modelConstants.js))
- **Modell-Kompatibilität** Funktioniert mit Claude, GPT und Gemini (vollständige Liste unterstützter Modelle zur Laufzeit über `GET /api/providers/:provider/models`)
## Schnellstart
@@ -164,6 +164,14 @@ CloudCLI verfügt über ein Plugin-System, mit dem benutzerdefinierte Tabs mit e
| Plugin | Beschreibung |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | Zeigt Dateianzahl, Codezeilen, Dateityp-Aufschlüsselung, größte Dateien und zuletzt geänderte Dateien des aktuellen Projekts |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | Vollwertiges xterm.js-Terminal mit Multi-Tab-Unterstützung |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | Überwacht lange laufende Claude-Code-Sitzungen auf Hänger und stellt Prozesssteuerungen bereit |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | Erstellt arbeitsbereichsbezogene geplante Prompts und führt sie über eine lokale CLI wie Codex, Claude Code oder Gemini CLI aus |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | Sitzungsintelligenz für Claude Code in CloudCLI, inklusive Sichtbarkeit des Token-Verbrauchs |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | Aktive Claude-Code-Sitzungen anzeigen, verwalten und beenden |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | API-Kosten anhand von Modellpreisen und Token-Nutzung berechnen, mit Unterstützung für Preisvorlagen |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | Task-Queue-Dashboard zum Anzeigen, Filtern und Starten von Agent-Aufgaben |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | Kanban-Board für GitHub Issues mit bidirektionaler TaskMaster-Synchronisierung und automatischer Installation des /github-task CLI-Skills |
### Eigenes Plugin erstellen

View File

@@ -158,6 +158,14 @@ CloudCLI にはプラグインシステムがあり、独自のフロントエ
| プラグイン | 説明 |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | 現在のプロジェクトについて、ファイル数、コード行数、ファイル種別の内訳、最大ファイル、最近変更されたファイルを表示 |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | 複数タブに対応した本格的な xterm.js ターミナル |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | 長時間実行中の Claude Code セッションのハングを監視し、プロセス操作を提供 |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | ワークスペース単位のスケジュール済みプロンプトを作成し、Codex、Claude Code、Gemini CLI などのローカル CLI で実行 |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | CloudCLI 内で Claude Code のセッション分析を行い、トークン消費の可視化も提供 |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | アクティブな Claude Code セッションを表示、管理、終了 |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | モデル価格とトークン使用量から API コストを計算し、モデル価格プリセットにも対応 |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | エージェントタスクを表示、フィルタリング、起動するためのタスクキューダッシュボード |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | GitHub Issues 用の Kanban ボード。TaskMaster との双方向同期と /github-task CLI スキルの自動インストールに対応 |
### 自作する

View File

@@ -60,7 +60,7 @@
- **세션 관리** - 대화를 재개하고, 여러 세션을 관리하며 기록을 추적
- **플러그인 시스템** - 커스텀 탭, 백엔드 서비스, 통합을 추가하여 CloudCLI 확장. [직접 빌드 →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI 통합** *(선택사항)* - AI 중심의 작업 계획, PRD 파싱, 워크플로 자동화를 통한 고급 프로젝트 관리
- **모델 호환성** - Claude, GPT, Gemini 모델 계열에서 작동 (`public/modelConstants.js`에서 전체 지원 모델 확인)
- **모델 호환성** - Claude, GPT, Gemini 모델 계열에서 작동 (`GET /api/providers/:provider/models` API에서 전체 지원 모델 확인)
## 빠른 시작
@@ -158,6 +158,14 @@ CloudCLI는 커스텀 탭과 선택적 Node.js 백엔드가 포함된 플러그
| 플러그인 | 설명 |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | 현재 프로젝트의 파일 수, 코드 줄 수, 파일 유형 분포, 가장 큰 파일, 최근 수정 파일을 표시 |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | 다중 탭을 지원하는 전체 xterm.js 터미널 |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | 장시간 실행 중인 Claude Code 세션의 중단 상태를 감시하고 프로세스 제어를 제공 |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | 워크스페이스 범위 예약 프롬프트를 만들고 Codex, Claude Code, Gemini CLI 같은 로컬 CLI로 실행 |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | CloudCLI 안에서 Claude Code 세션 인텔리전스와 토큰 소모 가시성을 제공 |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | 활성 Claude Code 세션을 보고, 관리하고, 종료 |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | 모델 가격과 토큰 사용량으로 API 비용을 계산하고 모델 가격 프리셋을 지원 |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | 에이전트 작업을 보고, 필터링하고, 실행하는 작업 큐 대시보드 |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | GitHub Issues용 Kanban 보드. TaskMaster 양방향 동기화와 /github-task CLI 스킬 자동 설치 지원 |
### 직접 만들기

View File

@@ -62,7 +62,7 @@
- **Session Management** - Resume conversations, manage multiple sessions, and track history
- **Plugin System** - Extend CloudCLI with custom plugins — add new tabs, backend services, and integrations. [Build your own →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI Integration** *(Optional)* - Advanced project management with AI-powered task planning, PRD parsing, and workflow automation
- **Model Compatibility** - Works with Claude, GPT, and Gemini model families (see [`public/modelConstants.js`](public/modelConstants.js) for the full list of supported models)
- **Model Compatibility** - Works with Claude, GPT, and Gemini model families (the full list of supported models is available at runtime via `GET /api/providers/:provider/models`)
## Quick Start
@@ -163,8 +163,15 @@ CloudCLI has a plugin system that lets you add custom tabs with their own fronte
| Plugin | Description |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | Shows file counts, lines of code, file-type breakdown, largest files, and recently modified files for your current project |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | Full xterm.js terminal with multi-tab support|
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | Create workspace-scoped scheduled prompts and execute them through a local CLI such as Codex, Claude Code, or Gemini CLI|
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | Full xterm.js terminal with multi-tab support |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | Watches long-running Claude Code sessions for hangs and exposes process controls |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | Create workspace-scoped scheduled prompts and execute them through a local CLI such as Codex, Claude Code, or Gemini CLI |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | Session intelligence for Claude Code inside CloudCLI, including token burn visibility |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | View, manage, and kill active Claude Code sessions |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | Calculate API costs from model prices and token usage, with preset model pricing support |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | Task queue dashboard to view, filter, and launch agent tasks |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | Kanban board for GitHub Issues with bidirectional TaskMaster sync and /github-task CLI skill auto-install |
### Build Your Own
**[Plugin Starter Template →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** — fork this repo to create your own plugin. It includes a working example with frontend rendering, live context updates, and RPC communication to a backend server.

View File

@@ -62,7 +62,7 @@
- **Управление сессиями** - возобновляйте диалоги, управляйте несколькими сессиями и отслеживайте историю
- **Система плагинов** - расширяйте CloudCLI кастомными плагинами — добавляйте новые вкладки, бэкенд-сервисы и интеграции. [Создать свой →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **Интеграция с TaskMaster AI** *(опционально)* - продвинутое управление проектами с планированием задач на базе AI, разбором PRD и автоматизацией workflow
- **Совместимость с моделями** - работает с семействами моделей Claude, GPT и Gemini (см. [`public/modelConstants.js`](public/modelConstants.js) для полного списка поддерживаемых моделей)
- **Совместимость с моделями** - работает с семействами моделей Claude, GPT и Gemini (полный список поддерживаемых моделей доступен через `GET /api/providers/:provider/models`)
## Быстрый старт
@@ -164,6 +164,14 @@ CloudCLI UI — это open source UI-слой, на котором постро
| Плагин | Описание |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | Показывает количество файлов, строки кода, разбивку по типам файлов, самые большие файлы и недавно изменённые файлы для текущего проекта |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | Полноценный терминал xterm.js с поддержкой нескольких вкладок |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | Отслеживает зависания долгих сессий Claude Code и предоставляет управление процессами |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | Создаёт запланированные промпты для рабочей области и запускает их через локальную CLI, например Codex, Claude Code или Gemini CLI |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | Аналитика сессий Claude Code внутри CloudCLI, включая видимость расхода токенов |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | Просмотр, управление и завершение активных сессий Claude Code |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | Расчёт стоимости API по ценам моделей и использованию токенов, с поддержкой пресетов цен |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | Дашборд очереди задач для просмотра, фильтрации и запуска агентских задач |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | Kanban-доска для GitHub Issues с двусторонней синхронизацией TaskMaster и автоустановкой CLI-навыка /github-task |
### Создать свой

View File

@@ -62,7 +62,7 @@
- **Oturum Yönetimi** — Konuşmalara devam et, birden fazla oturumu yönet ve geçmişi takip et
- **Eklenti Sistemi** — CloudCLI'ı özel eklentilerle genişlet: yeni sekmeler, arka uç servisleri ve entegrasyonlar ekle. [Kendi eklentini yaz →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI Entegrasyonu** *(İsteğe Bağlı)* — AI destekli görev planlama, PRD ayrıştırma ve iş akışı otomasyonu ile gelişmiş proje yönetimi
- **Model Uyumluluğu** — Claude, GPT ve Gemini model aileleriyle çalışır (desteklenen tüm modeller için [`public/modelConstants.js`](public/modelConstants.js) dosyasına bak)
- **Model Uyumluluğu** — Claude, GPT ve Gemini model aileleriyle çalışır (desteklenen tüm modeller için `GET /api/providers/:provider/models` API'sine bak)
## Hızlı Başlangıç
@@ -164,6 +164,13 @@ CloudCLI, kendi frontend UI'sı ve isteğe bağlı Node.js arka ucu olan özel s
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | Mevcut projen için dosya sayıları, kod satırları, dosya türü dağılımı, en büyük dosyalar ve son değiştirilen dosyaları gösterir |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | Çoklu sekme destekli tam xterm.js terminali |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | Uzun süren Claude Code oturumlarını takılmalara karşı izler ve süreç kontrolleri sunar |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | Çalışma alanı kapsamlı zamanlanmış prompt'lar oluşturur ve bunları Codex, Claude Code veya Gemini CLI gibi yerel CLI'larla çalıştırır |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | CloudCLI içinde Claude Code oturum zekası ve token tüketimi görünürlüğü sağlar |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | Aktif Claude Code oturumlarını görüntülemeni, yönetmeni ve sonlandırmanı sağlar |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | Model fiyatları ve token kullanımından API maliyetlerini hesaplar; model fiyatı hazır ayarlarını destekler |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | Ajan görevlerini görüntülemek, filtrelemek ve başlatmak için görev kuyruğu paneli |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | GitHub Issues için Kanban panosu; çift yönlü TaskMaster senkronizasyonu ve /github-task CLI becerisi otomatik kurulumu içerir |
### Kendi Eklentini Yaz

View File

@@ -60,7 +60,7 @@
- **会话管理** - 恢复对话、管理多个会话并跟踪历史记录
- **插件系统** - 通过自定义选项卡、后端服务与集成扩展 CloudCLI。 [开始构建 →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI 集成** *(可选)* - 结合 AI 任务规划、PRD 分析与工作流自动化,实现高级项目管理
- **模型兼容性** - 支持 Claude、GPT、Gemini 模型家族(完整支持列表见 [`public/modelConstants.js`](public/modelConstants.js)
- **模型兼容性** - 支持 Claude、GPT、Gemini 模型家族(完整支持列表可通过 `GET /api/providers/:provider/models` 接口获取
## 快速开始
@@ -158,6 +158,14 @@ CloudCLI 配备插件系统,允许你添加带自定义前端 UI 和可选 Nod
| 插件 | 描述 |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | 展示当前项目的文件数、代码行数、文件类型分布、最大文件以及最近修改的文件 |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | 支持多标签页的完整 xterm.js 终端 |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | 监控长时间运行的 Claude Code 会话是否卡住,并提供进程控制 |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | 创建工作区范围的定时提示词,并通过 Codex、Claude Code 或 Gemini CLI 等本地 CLI 执行 |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | 在 CloudCLI 中提供 Claude Code 会话智能分析,包括 token 消耗可视化 |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | 查看、管理并终止活动的 Claude Code 会话 |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | 根据模型价格和 token 用量计算 API 成本,并支持模型价格预设 |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | 用于查看、筛选和启动代理任务的任务队列仪表板 |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | 用于 GitHub Issues 的看板,支持 TaskMaster 双向同步和 /github-task CLI 技能自动安装 |
### 自行构建

View File

@@ -60,7 +60,7 @@
- **工作階段管理** — 恢復對話、管理多個工作階段並追蹤歷史紀錄
- **外掛系統** — 透過自訂分頁、後端服務與整合來擴充 CloudCLI。[開始建構 →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI 整合** *(選用)* — 結合 AI 任務規劃、PRD 分析與工作流程自動化,實現進階專案管理
- **模型相容性** — 支援 Claude、GPT、Gemini 模型家族(完整支援列表見 [`shared/modelConstants.js`](shared/modelConstants.js)
- **模型相容性** — 支援 Claude、GPT、Gemini 模型家族(完整支援列表可透過 `GET /api/providers/:provider/models` 介面取得
## 快速開始
@@ -158,6 +158,14 @@ CloudCLI 配備外掛系統,允許你新增帶有自訂前端 UI 和選用 Nod
| 外掛 | 描述 |
|---|---|
| **[Project Stats](https://github.com/cloudcli-ai/cloudcli-plugin-starter)** | 展示目前專案的檔案數、程式碼行數、檔案類型分佈、最大檔案以及最近修改的檔案 |
| **[Web Terminal](https://github.com/cloudcli-ai/cloudcli-plugin-terminal)** | 支援多分頁的完整 xterm.js 終端機 |
| **[Claude Watch](https://github.com/satsuki19980613/cloudcli-claude-watch)** | 監控長時間執行的 Claude Code 工作階段是否卡住,並提供程序控制 |
| **[CloudCLI Scheduler](https://github.com/grostim/cloudcli-cron)** | 建立工作區範圍的排程提示詞,並透過 Codex、Claude Code 或 Gemini CLI 等本機 CLI 執行 |
| **[PRISM CloudCLI](https://github.com/jakeefr/cloudcli-plugin-prism)** | 在 CloudCLI 中提供 Claude Code 工作階段智慧分析,包括 token 消耗可視化 |
| **[Sessions](https://github.com/strykereye2/cloudcli-plugin-session-manager)** | 檢視、管理並終止作用中的 Claude Code 工作階段 |
| **[Token Cost Calculator](https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator)** | 根據模型價格與 token 用量計算 API 成本,並支援模型價格預設 |
| **[Task Queue](https://github.com/TadMSTR/cloudcli-plugin-task-queue)** | 用於檢視、篩選和啟動代理任務的任務佇列儀表板 |
| **[GitHub Issues Board](https://github.com/szmidtpiotr/claude-github-issue)** | 用於 GitHub Issues 的看板,支援 TaskMaster 雙向同步和 /github-task CLI 技能自動安裝 |
### 自行建構

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@cloudcli-ai/cloudcli",
"version": "1.33.2",
"version": "1.34.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@cloudcli-ai/cloudcli",
"version": "1.33.2",
"version": "1.34.0",
"hasInstallScript": true,
"license": "AGPL-3.0-or-later",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@cloudcli-ai/cloudcli",
"version": "1.33.2",
"version": "1.34.0",
"description": "A web-based UI for Claude Code CLI",
"type": "module",
"main": "dist-server/server/index.js",
@@ -11,7 +11,6 @@
"server/",
"shared/",
"public/api-docs.html",
"public/modelConstants.js",
"dist/",
"dist-server/",
"scripts/",

View File

@@ -820,31 +820,49 @@ data: {"type":"done"}</code></pre>
</div>
</div>
<script type="module">
// Import model constants
import { PROVIDERS } from './modelConstants.js';
<script>
// Dynamic URL replacement
const apiUrl = window.location.origin;
document.querySelectorAll('.api-url').forEach(el => {
el.textContent = apiUrl;
});
// Dynamically populate model documentation
window.addEventListener('DOMContentLoaded', () => {
const modelCell = document.getElementById('model-options-cell');
if (modelCell) {
const providerModels = PROVIDERS.map(provider => {
const models = provider.models.OPTIONS.map(m => `<code>${m.value}</code>`).join(', ');
return `<strong>${provider.name}:</strong> ${models} (default: <code>${provider.models.DEFAULT}</code>)`;
}).join('<br><br>');
// Populate model documentation from the live provider API
const PROVIDER_ORDER = [
{ id: 'claude', name: 'Anthropic' },
{ id: 'codex', name: 'OpenAI' },
{ id: 'gemini', name: 'Google' },
{ id: 'cursor', name: 'Cursor' },
{ id: 'opencode', name: 'OpenCode' },
];
modelCell.innerHTML = `
Model identifier for the AI provider:<br><br>
${providerModels}
`;
}
});
async function populateModels() {
const modelCell = document.getElementById('model-options-cell');
if (!modelCell) return;
const token = localStorage.getItem('auth-token');
const headers = token ? { Authorization: `Bearer ${token}` } : {};
const results = await Promise.allSettled(
PROVIDER_ORDER.map(({ id }) =>
fetch(`/api/providers/${id}/models`, { headers }).then(r => r.json())
)
);
const providerModels = results.map((result, i) => {
const { name } = PROVIDER_ORDER[i];
if (result.status === 'rejected' || !result.value?.data?.models) {
return `<strong>${name}:</strong> <em>unavailable</em>`;
}
const { OPTIONS, DEFAULT } = result.value.data.models;
const models = OPTIONS.map(m => `<code>${m.value}</code>`).join(', ');
return `<strong>${name}:</strong> ${models} (default: <code>${DEFAULT}</code>)`;
}).join('<br><br>');
modelCell.innerHTML = `Model identifier for the AI provider:<br><br>${providerModels}`;
}
document.addEventListener('DOMContentLoaded', populateModels);
// Tab switching
window.showTab = function(tabName) {

View File

@@ -1,848 +0,0 @@
/**
* Documentation Model Definitions
* Used by README links and the public API docs.
*/
/**
* Claude (Anthropic) Models
*/
export const CLAUDE_MODELS = {
OPTIONS: [
{
value: "default",
label: "Default (recommended)",
description:
"Use the default model (currently Opus 4.8 (1M context)) · $5/$25 per Mtok",
},
{
value: "sonnet",
label: "Sonnet",
description: "Sonnet 4.6 · Best for everyday tasks · $3/$15 per Mtok",
},
{
value: "sonnet[1m]",
label: "Sonnet (1M context)",
description: "Sonnet 4.6 for long sessions · $3/$15 per Mtok",
},
{
value: "opus[1m]",
label: "Opus 4.8 (1M context)",
description:
"Opus 4.8 with 1M context · Most capable for complex work · $5/$25 per Mtok",
},
{
value: "haiku",
label: "Haiku",
description: "Haiku 4.5 · Fastest for quick answers · $1/$5 per Mtok",
},
],
DEFAULT: "default",
};
/**
* Cursor Models
*/
export const CURSOR_MODELS = {
OPTIONS: [
{ value: "auto", label: "auto", description: "Auto" },
{
value: "composer-2-fast",
label: "composer-2-fast",
description: "Composer 2 Fast",
},
{
value: "composer-2",
label: "composer-2",
description: "Composer 2",
},
{
value: "gpt-5.3-codex-low",
label: "gpt-5.3-codex-low",
description: "Codex 5.3 Low",
},
{
value: "gpt-5.3-codex-low-fast",
label: "gpt-5.3-codex-low-fast",
description: "Codex 5.3 Low Fast",
},
{
value: "gpt-5.3-codex",
label: "gpt-5.3-codex",
description: "Codex 5.3",
},
{
value: "gpt-5.3-codex-fast",
label: "gpt-5.3-codex-fast",
description: "Codex 5.3 Fast",
},
{
value: "gpt-5.3-codex-high",
label: "gpt-5.3-codex-high",
description: "Codex 5.3 High",
},
{
value: "gpt-5.3-codex-high-fast",
label: "gpt-5.3-codex-high-fast",
description: "Codex 5.3 High Fast",
},
{
value: "gpt-5.3-codex-xhigh",
label: "gpt-5.3-codex-xhigh",
description: "Codex 5.3 Extra High",
},
{
value: "gpt-5.3-codex-xhigh-fast",
label: "gpt-5.3-codex-xhigh-fast",
description: "Codex 5.3 Extra High Fast",
},
{ value: "gpt-5.2", label: "gpt-5.2", description: "GPT-5.2" },
{
value: "gpt-5.2-codex-low",
label: "gpt-5.2-codex-low",
description: "Codex 5.2 Low",
},
{
value: "gpt-5.2-codex-low-fast",
label: "gpt-5.2-codex-low-fast",
description: "Codex 5.2 Low Fast",
},
{
value: "gpt-5.2-codex",
label: "gpt-5.2-codex",
description: "Codex 5.2",
},
{
value: "gpt-5.2-codex-fast",
label: "gpt-5.2-codex-fast",
description: "Codex 5.2 Fast",
},
{
value: "gpt-5.2-codex-high",
label: "gpt-5.2-codex-high",
description: "Codex 5.2 High",
},
{
value: "gpt-5.2-codex-high-fast",
label: "gpt-5.2-codex-high-fast",
description: "Codex 5.2 High Fast",
},
{
value: "gpt-5.2-codex-xhigh",
label: "gpt-5.2-codex-xhigh",
description: "Codex 5.2 Extra High",
},
{
value: "gpt-5.2-codex-xhigh-fast",
label: "gpt-5.2-codex-xhigh-fast",
description: "Codex 5.2 Extra High Fast",
},
{
value: "gpt-5.1-codex-max-low",
label: "gpt-5.1-codex-max-low",
description: "Codex 5.1 Max Low",
},
{
value: "gpt-5.1-codex-max-low-fast",
label: "gpt-5.1-codex-max-low-fast",
description: "Codex 5.1 Max Low Fast",
},
{
value: "gpt-5.1-codex-max-medium",
label: "gpt-5.1-codex-max-medium",
description: "Codex 5.1 Max",
},
{
value: "gpt-5.1-codex-max-medium-fast",
label: "gpt-5.1-codex-max-medium-fast",
description: "Codex 5.1 Max Medium Fast",
},
{
value: "gpt-5.1-codex-max-high",
label: "gpt-5.1-codex-max-high",
description: "Codex 5.1 Max High",
},
{
value: "gpt-5.1-codex-max-high-fast",
label: "gpt-5.1-codex-max-high-fast",
description: "Codex 5.1 Max High Fast",
},
{
value: "gpt-5.1-codex-max-xhigh",
label: "gpt-5.1-codex-max-xhigh",
description: "Codex 5.1 Max Extra High",
},
{
value: "gpt-5.1-codex-max-xhigh-fast",
label: "gpt-5.1-codex-max-xhigh-fast",
description: "Codex 5.1 Max Extra High Fast",
},
{
value: "composer-2.5",
label: "composer-2.5",
description: "Composer 2.5",
},
{
value: "gpt-5.5-high",
label: "gpt-5.5-high",
description: "GPT-5.5 1M High",
},
{
value: "gpt-5.5-high-fast",
label: "gpt-5.5-high-fast",
description: "GPT-5.5 High Fast",
},
{
value: "claude-opus-4-7-thinking-high",
label: "claude-opus-4-7-thinking-high",
description: "Opus 4.7 1M High Thinking",
},
{
value: "gpt-5.4-high",
label: "gpt-5.4-high",
description: "GPT-5.4 1M High",
},
{
value: "gpt-5.4-high-fast",
label: "gpt-5.4-high-fast",
description: "GPT-5.4 High Fast",
},
{
value: "claude-4.6-opus-high-thinking",
label: "claude-4.6-opus-high-thinking",
description: "Opus 4.6 1M Thinking",
},
{
value: "claude-4.6-opus-high-thinking-fast",
label: "claude-4.6-opus-high-thinking-fast",
description: "Opus 4.6 1M Thinking Fast",
},
{
value: "composer-2.5-fast",
label: "composer-2.5-fast",
description: "Composer 2.5 Fast",
},
{
value: "gpt-5.5-none",
label: "gpt-5.5-none",
description: "GPT-5.5 1M None",
},
{
value: "gpt-5.5-none-fast",
label: "gpt-5.5-none-fast",
description: "GPT-5.5 None Fast",
},
{
value: "gpt-5.5-low",
label: "gpt-5.5-low",
description: "GPT-5.5 1M Low",
},
{
value: "gpt-5.5-low-fast",
label: "gpt-5.5-low-fast",
description: "GPT-5.5 Low Fast",
},
{
value: "gpt-5.5-medium",
label: "gpt-5.5-medium",
description: "GPT-5.5 1M",
},
{
value: "gpt-5.5-medium-fast",
label: "gpt-5.5-medium-fast",
description: "GPT-5.5 Fast",
},
{
value: "gpt-5.5-extra-high",
label: "gpt-5.5-extra-high",
description: "GPT-5.5 1M Extra High",
},
{
value: "gpt-5.5-extra-high-fast",
label: "gpt-5.5-extra-high-fast",
description: "GPT-5.5 Extra High Fast",
},
{
value: "claude-4.6-sonnet-medium",
label: "claude-4.6-sonnet-medium",
description: "Sonnet 4.6 1M",
},
{
value: "claude-4.6-sonnet-medium-thinking",
label: "claude-4.6-sonnet-medium-thinking",
description: "Sonnet 4.6 1M Thinking",
},
{
value: "claude-opus-4-7-low",
label: "claude-opus-4-7-low",
description: "Opus 4.7 1M Low",
},
{
value: "claude-opus-4-7-low-fast",
label: "claude-opus-4-7-low-fast",
description: "Opus 4.7 1M Low Fast",
},
{
value: "claude-opus-4-7-medium",
label: "claude-opus-4-7-medium",
description: "Opus 4.7 1M Medium",
},
{
value: "claude-opus-4-7-medium-fast",
label: "claude-opus-4-7-medium-fast",
description: "Opus 4.7 1M Medium Fast",
},
{
value: "claude-opus-4-7-high",
label: "claude-opus-4-7-high",
description: "Opus 4.7 1M High",
},
{
value: "claude-opus-4-7-high-fast",
label: "claude-opus-4-7-high-fast",
description: "Opus 4.7 1M High Fast",
},
{
value: "claude-opus-4-7-xhigh",
label: "claude-opus-4-7-xhigh",
description: "Opus 4.7 1M",
},
{
value: "claude-opus-4-7-xhigh-fast",
label: "claude-opus-4-7-xhigh-fast",
description: "Opus 4.7 1M Fast",
},
{
value: "claude-opus-4-7-max",
label: "claude-opus-4-7-max",
description: "Opus 4.7 1M Max",
},
{
value: "claude-opus-4-7-max-fast",
label: "claude-opus-4-7-max-fast",
description: "Opus 4.7 1M Max Fast",
},
{
value: "claude-opus-4-7-thinking-low",
label: "claude-opus-4-7-thinking-low",
description: "Opus 4.7 1M Low Thinking",
},
{
value: "claude-opus-4-7-thinking-low-fast",
label: "claude-opus-4-7-thinking-low-fast",
description: "Opus 4.7 1M Low Thinking Fast",
},
{
value: "claude-opus-4-7-thinking-medium",
label: "claude-opus-4-7-thinking-medium",
description: "Opus 4.7 1M Medium Thinking",
},
{
value: "claude-opus-4-7-thinking-medium-fast",
label: "claude-opus-4-7-thinking-medium-fast",
description: "Opus 4.7 1M Medium Thinking Fast",
},
{
value: "claude-opus-4-7-thinking-high-fast",
label: "claude-opus-4-7-thinking-high-fast",
description: "Opus 4.7 1M High Thinking Fast",
},
{
value: "claude-opus-4-7-thinking-xhigh",
label: "claude-opus-4-7-thinking-xhigh",
description: "Opus 4.7 1M Thinking",
},
{
value: "claude-opus-4-7-thinking-xhigh-fast",
label: "claude-opus-4-7-thinking-xhigh-fast",
description: "Opus 4.7 1M Thinking Fast",
},
{
value: "claude-opus-4-7-thinking-max",
label: "claude-opus-4-7-thinking-max",
description: "Opus 4.7 1M Max Thinking",
},
{
value: "claude-opus-4-7-thinking-max-fast",
label: "claude-opus-4-7-thinking-max-fast",
description: "Opus 4.7 1M Max Thinking Fast",
},
{
value: "grok-build-0.1",
label: "grok-build-0.1",
description: "Grok Build 0.1 1M",
},
{
value: "gpt-5.4-low",
label: "gpt-5.4-low",
description: "GPT-5.4 1M Low",
},
{
value: "gpt-5.4-medium",
label: "gpt-5.4-medium",
description: "GPT-5.4 1M",
},
{
value: "gpt-5.4-medium-fast",
label: "gpt-5.4-medium-fast",
description: "GPT-5.4 Fast",
},
{
value: "gpt-5.4-xhigh",
label: "gpt-5.4-xhigh",
description: "GPT-5.4 1M Extra High",
},
{
value: "gpt-5.4-xhigh-fast",
label: "gpt-5.4-xhigh-fast",
description: "GPT-5.4 Extra High Fast",
},
{
value: "claude-4.6-opus-high",
label: "claude-4.6-opus-high",
description: "Opus 4.6 1M",
},
{
value: "claude-4.6-opus-max",
label: "claude-4.6-opus-max",
description: "Opus 4.6 1M Max",
},
{
value: "claude-4.6-opus-max-thinking",
label: "claude-4.6-opus-max-thinking",
description: "Opus 4.6 1M Max Thinking",
},
{
value: "claude-4.6-opus-max-thinking-fast",
label: "claude-4.6-opus-max-thinking-fast",
description: "Opus 4.6 1M Max Thinking Fast",
},
{
value: "claude-4.5-opus-high",
label: "claude-4.5-opus-high",
description: "Opus 4.5",
},
{
value: "claude-4.5-opus-high-thinking",
label: "claude-4.5-opus-high-thinking",
description: "Opus 4.5 Thinking",
},
{
value: "gpt-5.2-low",
label: "gpt-5.2-low",
description: "GPT-5.2 Low",
},
{
value: "gpt-5.2-low-fast",
label: "gpt-5.2-low-fast",
description: "GPT-5.2 Low Fast",
},
{
value: "gpt-5.2-fast",
label: "gpt-5.2-fast",
description: "GPT-5.2 Fast",
},
{
value: "gpt-5.2-high",
label: "gpt-5.2-high",
description: "GPT-5.2 High",
},
{
value: "gpt-5.2-high-fast",
label: "gpt-5.2-high-fast",
description: "GPT-5.2 High Fast",
},
{
value: "gpt-5.2-xhigh",
label: "gpt-5.2-xhigh",
description: "GPT-5.2 Extra High",
},
{
value: "gpt-5.2-xhigh-fast",
label: "gpt-5.2-xhigh-fast",
description: "GPT-5.2 Extra High Fast",
},
{
value: "gemini-3.1-pro",
label: "gemini-3.1-pro",
description: "Gemini 3.1 Pro",
},
{
value: "gpt-5.4-mini-none",
label: "gpt-5.4-mini-none",
description: "GPT-5.4 Mini None",
},
{
value: "gpt-5.4-mini-low",
label: "gpt-5.4-mini-low",
description: "GPT-5.4 Mini Low",
},
{
value: "gpt-5.4-mini-medium",
label: "gpt-5.4-mini-medium",
description: "GPT-5.4 Mini",
},
{
value: "gpt-5.4-mini-high",
label: "gpt-5.4-mini-high",
description: "GPT-5.4 Mini High",
},
{
value: "gpt-5.4-mini-xhigh",
label: "gpt-5.4-mini-xhigh",
description: "GPT-5.4 Mini Extra High",
},
{
value: "gpt-5.4-nano-none",
label: "gpt-5.4-nano-none",
description: "GPT-5.4 Nano None",
},
{
value: "gpt-5.4-nano-low",
label: "gpt-5.4-nano-low",
description: "GPT-5.4 Nano Low",
},
{
value: "gpt-5.4-nano-medium",
label: "gpt-5.4-nano-medium",
description: "GPT-5.4 Nano",
},
{
value: "gpt-5.4-nano-high",
label: "gpt-5.4-nano-high",
description: "GPT-5.4 Nano High",
},
{
value: "gpt-5.4-nano-xhigh",
label: "gpt-5.4-nano-xhigh",
description: "GPT-5.4 Nano Extra High",
},
{
value: "grok-4.3",
label: "grok-4.3",
description: "Grok 4.3 1M",
},
{
value: "claude-4.5-sonnet",
label: "claude-4.5-sonnet",
description: "Sonnet 4.5",
},
{
value: "claude-4.5-sonnet-thinking",
label: "claude-4.5-sonnet-thinking",
description: "Sonnet 4.5 Thinking",
},
{
value: "gpt-5.1-low",
label: "gpt-5.1-low",
description: "GPT-5.1 Low",
},
{
value: "gpt-5.1",
label: "gpt-5.1",
description: "GPT-5.1",
},
{
value: "gpt-5.1-high",
label: "gpt-5.1-high",
description: "GPT-5.1 High",
},
{
value: "gemini-3-flash",
label: "gemini-3-flash",
description: "Gemini 3 Flash",
},
{
value: "gemini-3.5-flash",
label: "gemini-3.5-flash",
description: "Gemini 3.5 Flash",
},
{
value: "gpt-5.1-codex-mini-low",
label: "gpt-5.1-codex-mini-low",
description: "Codex 5.1 Mini Low",
},
{
value: "gpt-5.1-codex-mini",
label: "gpt-5.1-codex-mini",
description: "Codex 5.1 Mini",
},
{
value: "gpt-5.1-codex-mini-high",
label: "gpt-5.1-codex-mini-high",
description: "Codex 5.1 Mini High",
},
{
value: "claude-4-sonnet",
label: "claude-4-sonnet",
description: "Sonnet 4",
},
{
value: "claude-4-sonnet-thinking",
label: "claude-4-sonnet-thinking",
description: "Sonnet 4 Thinking",
},
{
value: "gpt-5-mini",
label: "gpt-5-mini",
description: "GPT-5 Mini",
},
{
value: "kimi-k2.5",
label: "kimi-k2.5",
description: "Kimi K2.5",
},
],
DEFAULT: "composer-2.5-fast",
};
/**
* Codex (OpenAI) Models
*/
export const CODEX_MODELS = {
OPTIONS: [
{ value: "gpt-5.5", label: "gpt-5.5" },
{ value: "gpt-5.4", label: "gpt-5.4" },
{ value: "gpt-5.4-mini", label: "gpt-5.4-mini" },
{ value: "gpt-5.3-codex", label: "gpt-5.3-codex" },
{ value: "gpt-5.2", label: "gpt-5.2" },
],
DEFAULT: "gpt-5.4",
};
/**
* Gemini Models
*/
export const GEMINI_MODELS = {
OPTIONS: [
{ value: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro Preview" },
{ value: "gemini-3-pro-preview", label: "Gemini 3 Pro Preview" },
{ value: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview" },
{ value: "gemini-2.5-flash", label: "Gemini 2.5 Flash" },
{ value: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
{ value: "gemini-2.0-flash-lite", label: "Gemini 2.0 Flash Lite" },
{ value: "gemini-2.0-flash", label: "Gemini 2.0 Flash" },
{ value: "gemini-2.0-pro-exp", label: "Gemini 2.0 Pro Experimental" },
{
value: "gemini-2.0-flash-thinking-exp",
label: "Gemini 2.0 Flash Thinking",
},
],
DEFAULT: "gemini-3.1-pro-preview",
};
/**
* OpenCode Models
*
* OpenCode model ids include the upstream provider prefix.
*/
export const OPENCODE_MODELS = {
OPTIONS: [
{
value: "opencode/big-pickle",
label: "Big Pickle",
description: "opencode - opencode/big-pickle",
},
{
value: "opencode/deepseek-v4-flash-free",
label: "Deepseek V4 Flash Free",
description: "opencode - opencode/deepseek-v4-flash-free",
},
{
value: "opencode/nemotron-3-super-free",
label: "Nemotron 3 Super Free",
description: "opencode - opencode/nemotron-3-super-free",
},
{
value: "anthropic/claude-3-5-haiku-20241022",
label: "Claude 3.5 Haiku (2024-10-22)",
description: "anthropic - anthropic/claude-3-5-haiku-20241022",
},
{
value: "anthropic/claude-3-5-haiku-latest",
label: "Claude 3.5 Haiku Latest",
description: "anthropic - anthropic/claude-3-5-haiku-latest",
},
{
value: "anthropic/claude-3-5-sonnet-20240620",
label: "Claude 3.5 Sonnet (2024-06-20)",
description: "anthropic - anthropic/claude-3-5-sonnet-20240620",
},
{
value: "anthropic/claude-3-5-sonnet-20241022",
label: "Claude 3.5 Sonnet (2024-10-22)",
description: "anthropic - anthropic/claude-3-5-sonnet-20241022",
},
{
value: "anthropic/claude-3-7-sonnet-20250219",
label: "Claude 3.7 Sonnet (2025-02-19)",
description: "anthropic - anthropic/claude-3-7-sonnet-20250219",
},
{
value: "anthropic/claude-3-haiku-20240307",
label: "Claude 3 Haiku (2024-03-07)",
description: "anthropic - anthropic/claude-3-haiku-20240307",
},
{
value: "anthropic/claude-3-opus-20240229",
label: "Claude 3 Opus (2024-02-29)",
description: "anthropic - anthropic/claude-3-opus-20240229",
},
{
value: "anthropic/claude-3-sonnet-20240229",
label: "Claude 3 Sonnet (2024-02-29)",
description: "anthropic - anthropic/claude-3-sonnet-20240229",
},
{
value: "anthropic/claude-haiku-4-5",
label: "Claude Haiku 4.5",
description: "anthropic - anthropic/claude-haiku-4-5",
},
{
value: "anthropic/claude-haiku-4-5-20251001",
label: "Claude Haiku 4.5 (2025-10-01)",
description: "anthropic - anthropic/claude-haiku-4-5-20251001",
},
{
value: "anthropic/claude-opus-4-0",
label: "Claude Opus 4.0",
description: "anthropic - anthropic/claude-opus-4-0",
},
{
value: "anthropic/claude-opus-4-1",
label: "Claude Opus 4.1",
description: "anthropic - anthropic/claude-opus-4-1",
},
{
value: "anthropic/claude-opus-4-1-20250805",
label: "Claude Opus 4.1 (2025-08-05)",
description: "anthropic - anthropic/claude-opus-4-1-20250805",
},
{
value: "anthropic/claude-opus-4-20250514",
label: "Claude Opus 4 (2025-05-14)",
description: "anthropic - anthropic/claude-opus-4-20250514",
},
{
value: "anthropic/claude-opus-4-5",
label: "Claude Opus 4.5",
description: "anthropic - anthropic/claude-opus-4-5",
},
{
value: "anthropic/claude-opus-4-5-20251101",
label: "Claude Opus 4.5 (2025-11-01)",
description: "anthropic - anthropic/claude-opus-4-5-20251101",
},
{
value: "anthropic/claude-opus-4-6",
label: "Claude Opus 4.6",
description: "anthropic - anthropic/claude-opus-4-6",
},
{
value: "anthropic/claude-opus-4-6-fast",
label: "Claude Opus 4.6 Fast",
description: "anthropic - anthropic/claude-opus-4-6-fast",
},
{
value: "anthropic/claude-opus-4-7",
label: "Claude Opus 4.7",
description: "anthropic - anthropic/claude-opus-4-7",
},
{
value: "anthropic/claude-opus-4-7-fast",
label: "Claude Opus 4.7 Fast",
description: "anthropic - anthropic/claude-opus-4-7-fast",
},
{
value: "anthropic/claude-sonnet-4-0",
label: "Claude Sonnet 4.0",
description: "anthropic - anthropic/claude-sonnet-4-0",
},
{
value: "anthropic/claude-sonnet-4-20250514",
label: "Claude Sonnet 4 (2025-05-14)",
description: "anthropic - anthropic/claude-sonnet-4-20250514",
},
{
value: "anthropic/claude-sonnet-4-5",
label: "Claude Sonnet 4.5",
description: "anthropic - anthropic/claude-sonnet-4-5",
},
{
value: "anthropic/claude-sonnet-4-5-20250929",
label: "Claude Sonnet 4.5 (2025-09-29)",
description: "anthropic - anthropic/claude-sonnet-4-5-20250929",
},
{
value: "anthropic/claude-sonnet-4-6",
label: "Claude Sonnet 4.6",
description: "anthropic - anthropic/claude-sonnet-4-6",
},
{
value: "openai/gpt-5.2",
label: "GPT-5.2",
description: "openai - openai/gpt-5.2",
},
{
value: "openai/gpt-5.3-codex",
label: "GPT-5.3 Codex",
description: "openai - openai/gpt-5.3-codex",
},
{
value: "openai/gpt-5.3-codex-spark",
label: "GPT-5.3 Codex Spark",
description: "openai - openai/gpt-5.3-codex-spark",
},
{
value: "openai/gpt-5.4",
label: "GPT-5.4",
description: "openai - openai/gpt-5.4",
},
{
value: "openai/gpt-5.4-fast",
label: "GPT-5.4 Fast",
description: "openai - openai/gpt-5.4-fast",
},
{
value: "openai/gpt-5.4-mini",
label: "GPT-5.4 Mini",
description: "openai - openai/gpt-5.4-mini",
},
{
value: "openai/gpt-5.4-mini-fast",
label: "GPT-5.4 Mini Fast",
description: "openai - openai/gpt-5.4-mini-fast",
},
{
value: "openai/gpt-5.5",
label: "GPT-5.5",
description: "openai - openai/gpt-5.5",
},
{
value: "openai/gpt-5.5-fast",
label: "GPT-5.5 Fast",
description: "openai - openai/gpt-5.5-fast",
},
{
value: "openai/gpt-5.5-pro",
label: "GPT-5.5 Pro",
description: "openai - openai/gpt-5.5-pro",
},
],
DEFAULT: "anthropic/claude-sonnet-4-5",
};
/**
* Ordered provider registry. Display order in documentation.
*/
export const PROVIDERS = [
{ id: "claude", name: "Anthropic", models: CLAUDE_MODELS },
{ id: "codex", name: "OpenAI", models: CODEX_MODELS },
{ id: "gemini", name: "Google", models: GEMINI_MODELS },
{ id: "cursor", name: "Cursor", models: CURSOR_MODELS },
{ id: "opencode", name: "OpenCode", models: OPENCODE_MODELS },
];

View File

@@ -75,7 +75,7 @@
- **Session Management** - Resume conversations, manage multiple sessions, and track history
- **Plugin System** - Extend CloudCLI with custom plugins — add new tabs, backend services, and integrations. [Build your own →](https://github.com/cloudcli-ai/cloudcli-plugin-starter)
- **TaskMaster AI Integration** *(Optional)* - Advanced project management with AI-powered task planning, PRD parsing, and workflow automation
- **Model Compatibility** - Works with Claude, GPT, and Gemini model families (see [`public/modelConstants.js`](https://github.com/siteboon/claudecodeui/blob/main/public/modelConstants.js) for the full list of supported models)
- **Model Compatibility** - Works with Claude, GPT, and Gemini model families (the full list of supported models is available at runtime via `GET /api/providers/:provider/models`)
## Quick Start

View File

@@ -204,7 +204,7 @@ function mapCliOptionsToSDK(options = {}) {
sdkOptions.disallowedTools = settings.disallowedTools || [];
// Map model (default to sonnet)
// Valid models: sonnet, opus, haiku, opusplan, sonnet[1m]
// Valid models: sonnet, opus, haiku, opusplan, sonnet[1m], fable
sdkOptions.model = options.model || CLAUDE_FALLBACK_MODELS.DEFAULT;
// Model logged at query start below

View File

@@ -10,6 +10,7 @@ type NotificationPreferences = {
channels: {
inApp: boolean;
webPush: boolean;
sound: boolean;
};
events: {
actionRequired: boolean;
@@ -22,6 +23,7 @@ const DEFAULT_NOTIFICATION_PREFERENCES: NotificationPreferences = {
channels: {
inApp: false,
webPush: false,
sound: true,
},
events: {
actionRequired: true,
@@ -37,6 +39,7 @@ function normalizeNotificationPreferences(value: unknown): NotificationPreferenc
channels: {
inApp: source.channels?.inApp === true,
webPush: source.channels?.webPush === true,
sound: source.channels?.sound !== false,
},
events: {
actionRequired: source.events?.actionRequired !== false,

View File

@@ -83,7 +83,7 @@ The existing provider folders are `claude`, `codex`, `cursor`, `gemini`, and
- Update `server/modules/providers/provider.routes.ts`.
- Update `server/routes/agent.js` if the provider is launchable from the agent runtime.
- Update `server/index.js` if the provider needs runtime boot or shutdown wiring.
- Update `public/modelConstants.js` if the provider appears in README or public API docs.
- Update the `PROVIDER_ORDER` list in `public/api-docs.html` if the provider should appear in the public API docs.
- Update `src/components/chat/hooks/useChatProviderState.ts` and
`src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx` if
the provider should be selectable in chat.

View File

@@ -20,6 +20,11 @@ export const CLAUDE_FALLBACK_MODELS: ProviderModelsDefinition = {
label: 'Default (recommended)',
description: 'Use the default model (currently Opus 4.8 (1M context)) · $5/$25 per Mtok',
},
{
value: 'fable',
label: 'Fable',
description: 'Fable 5 · Most capable for your hardest and longest-running tasks · Uses your limits ~2× faster than Opus',
},
{
value: "sonnet",
label: "Sonnet",

View File

@@ -646,7 +646,7 @@ class ResponseCollector {
*
* @param {string} model - (Optional) Model identifier for providers.
*
* Claude models: 'sonnet' (default), 'opus', 'haiku', 'opusplan', 'sonnet[1m]'
* Claude models: 'sonnet' (default), 'opus', 'haiku', 'opusplan', 'sonnet[1m]', 'fable'
* Cursor models: 'gpt-5' (default), 'gpt-5.2', 'gpt-5.2-high', 'sonnet-4.5', 'opus-4.5',
* 'gemini-3-pro', 'composer-1', 'auto', 'gpt-5.1', 'gpt-5.1-high',
* 'gpt-5.1-codex', 'gpt-5.1-codex-high', 'gpt-5.1-codex-max',

View File

@@ -68,7 +68,7 @@ export type AuthenticatedWebSocketRequest = IncomingMessage & {
export type LLMProvider = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode';
/**
* One selectable model row (matches the documentation `public/modelConstants.js` option shape).
* One selectable model row in a provider model catalog.
*/
export type ProviderModelOption = {
value: string;

View File

@@ -2,6 +2,8 @@ import { useEffect, useRef } from 'react';
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
import { usePaletteOps } from '../../../contexts/PaletteOpsContext';
import { showCompletionTitleIndicator } from '../../../utils/pageTitleNotification';
import { playChatCompletionSound } from '../../../utils/notificationSound';
import type { PendingPermissionRequest, SessionNavigationOptions } from '../types/types';
import type { ProjectSession, LLMProvider } from '../../../types/app';
import type { SessionStore, NormalizedMessage } from '../../../stores/useSessionStore';
@@ -285,6 +287,9 @@ export function useChatRealtimeHandlers({
break;
}
showCompletionTitleIndicator();
void playChatCompletionSound();
const actualSessionId =
typeof msg.actualSessionId === 'string' && msg.actualSessionId.trim().length > 0
? msg.actualSessionId

View File

@@ -383,12 +383,47 @@ export function useChatSessionState({
setIsUserScrolledUp(false);
}, [selectedProject?.projectId, selectedSession?.id]);
// Initial scroll to bottom
// Initial scroll to bottom — robust to lazy content reflow.
// The previous implementation fired one scrollToBottom() at +200ms and
// cleared the pending flag. When markdown blocks, code highlighting, or
// images finished rendering after that window, scrollHeight grew but
// nothing re-anchored the viewport, leaving the chat tab visually
// "scrolled way up" with the latest assistant message off-screen.
//
// This version re-scrolls every animation frame while scrollHeight is
// still growing, capped at ~1s (60 frames) or 3 consecutive stable
// frames. Cancels cleanly on session change via the pending flag.
useEffect(() => {
if (!pendingInitialScrollRef.current || !scrollContainerRef.current || isLoadingSessionMessages) return;
if (chatMessages.length === 0) { pendingInitialScrollRef.current = false; return; }
pendingInitialScrollRef.current = false;
if (!searchScrollActiveRef.current) setTimeout(() => scrollToBottom(), 200);
if (searchScrollActiveRef.current) { pendingInitialScrollRef.current = false; return; }
const container = scrollContainerRef.current;
let frame = 0;
let lastHeight = 0;
let stableCount = 0;
let rafId = 0;
const tick = () => {
if (!pendingInitialScrollRef.current || !scrollContainerRef.current) return;
container.scrollTop = container.scrollHeight;
if (container.scrollHeight === lastHeight) {
stableCount++;
} else {
stableCount = 0;
lastHeight = container.scrollHeight;
}
frame++;
if (stableCount < 3 && frame < 60) {
rafId = requestAnimationFrame(tick);
} else {
pendingInitialScrollRef.current = false;
}
};
rafId = requestAnimationFrame(tick);
return () => {
if (rafId) cancelAnimationFrame(rafId);
};
}, [chatMessages.length, isLoadingSessionMessages, scrollToBottom]);
// Main session loading effect — store-based

View File

@@ -102,7 +102,7 @@ export default function EditorSidebar({
const useFlexLayout = editorExpanded || (fillSpace && !hasManualWidth);
return (
<div ref={containerRef} className={`flex h-full min-w-0 flex-shrink-0 ${editorExpanded ? 'flex-1' : ''}`}>
<div ref={containerRef} className={`flex h-full min-w-0 ${editorExpanded ? 'flex-1' : ''}`}>
{!editorExpanded && (
<div
ref={resizeHandleRef}

View File

@@ -4,11 +4,14 @@ import {
Activity,
BarChart3,
BookOpen,
Calculator,
Clock,
Download,
ExternalLink,
Github,
GitBranch,
Loader2,
ListTodo,
RefreshCw,
ServerCrash,
ShieldAlert,
@@ -27,6 +30,10 @@ const TERMINAL_PLUGIN_URL = 'https://github.com/cloudcli-ai/cloudcli-plugin-term
const SCHEDULED_PROMPT_PLUGIN_URL = 'https://github.com/grostim/cloudcli-cron';
const CLAUDE_WATCH_PLUGIN_URL = 'https://github.com/satsuki19980613/cloudcli-claude-watch';
const PRISM_CLOUDCLI_PLUGIN_URL = 'https://github.com/jakeefr/cloudcli-plugin-prism';
const SESSION_MANAGER_PLUGIN_URL = 'https://github.com/strykereye2/cloudcli-plugin-session-manager';
const TOKEN_COST_CALCULATOR_PLUGIN_URL = 'https://github.com/NightmareAway/cloudcli-plugin-token-cost-calculator';
const TASK_QUEUE_PLUGIN_URL = 'https://github.com/TadMSTR/cloudcli-plugin-task-queue';
const GITHUB_ISSUES_BOARD_PLUGIN_URL = 'https://github.com/szmidtpiotr/claude-github-issue';
type PluginRecommendation = {
id: string;
@@ -79,8 +86,40 @@ const UNOFFICIAL_PLUGIN_RECOMMENDATIONS: PluginRecommendation[] = [
repoUrl: PRISM_CLOUDCLI_PLUGIN_URL,
installedNames: ['prism'],
icon: Activity,
source: 'unofficial'
}
source: 'unofficial',
},
{
id: 'session-manager',
translationKey: 'sessionManagerPlugin',
repoUrl: SESSION_MANAGER_PLUGIN_URL,
installedNames: ['session-manager'],
icon: Activity,
source: 'unofficial',
},
{
id: 'token-cost-calculator',
translationKey: 'tokenCostCalculatorPlugin',
repoUrl: TOKEN_COST_CALCULATOR_PLUGIN_URL,
installedNames: ['token-cost-calculator'],
icon: Calculator,
source: 'unofficial',
},
{
id: 'task-queue',
translationKey: 'taskQueuePlugin',
repoUrl: TASK_QUEUE_PLUGIN_URL,
installedNames: ['task-queue'],
icon: ListTodo,
source: 'unofficial',
},
{
id: 'claude-github-issue',
translationKey: 'githubIssuesBoardPlugin',
repoUrl: GITHUB_ISSUES_BOARD_PLUGIN_URL,
installedNames: ['claude-github-issue'],
icon: Github,
source: 'unofficial',
},
];
function repoSlug(repoUrl: string) {

View File

@@ -1,6 +1,8 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useTheme } from '../../../contexts/ThemeContext';
import { authenticatedFetch } from '../../../utils/api';
import { setNotificationSoundEnabled } from '../../../utils/notificationSound';
import { useProviderAuthStatus } from '../../provider-auth/hooks/useProviderAuthStatus';
import {
DEFAULT_CODE_EDITOR_SETTINGS,
@@ -107,6 +109,7 @@ const createDefaultNotificationPreferences = (): NotificationPreferencesState =>
channels: {
inApp: true,
webPush: false,
sound: true,
},
events: {
actionRequired: true,
@@ -115,6 +118,25 @@ const createDefaultNotificationPreferences = (): NotificationPreferencesState =>
},
});
const normalizeNotificationPreferences = (
preferences?: Partial<NotificationPreferencesState> | null,
): NotificationPreferencesState => {
const defaults = createDefaultNotificationPreferences();
return {
channels: {
inApp: preferences?.channels?.inApp ?? defaults.channels.inApp,
webPush: preferences?.channels?.webPush ?? defaults.channels.webPush,
sound: preferences?.channels?.sound ?? defaults.channels.sound,
},
events: {
actionRequired: preferences?.events?.actionRequired ?? defaults.events.actionRequired,
stop: preferences?.events?.stop ?? defaults.events.stop,
error: preferences?.events?.error ?? defaults.events.error,
},
};
};
export function useSettingsController({ isOpen, initialTab }: UseSettingsControllerArgs) {
const { isDarkMode, toggleDarkMode } = useTheme() as ThemeContextValue;
const closeTimerRef = useRef<number | null>(null);
@@ -186,7 +208,7 @@ export function useSettingsController({ isOpen, initialTab }: UseSettingsControl
if (notificationResponse.ok) {
const notificationData = await toResponseJson<NotificationPreferencesResponse>(notificationResponse);
if (notificationData.success && notificationData.preferences) {
setNotificationPreferences(notificationData.preferences);
setNotificationPreferences(normalizeNotificationPreferences(notificationData.preferences));
} else {
setNotificationPreferences(createDefaultNotificationPreferences());
}
@@ -301,6 +323,10 @@ export function useSettingsController({ isOpen, initialTab }: UseSettingsControl
void refreshProviderAuthStatuses();
}, [initialTab, isOpen, loadSettings, refreshProviderAuthStatuses]);
useEffect(() => {
setNotificationSoundEnabled(notificationPreferences.channels.sound);
}, [notificationPreferences.channels.sound]);
useEffect(() => {
localStorage.setItem('codeEditorTheme', codeEditorSettings.theme);
localStorage.setItem('codeEditorWordWrap', String(codeEditorSettings.wordWrap));

View File

@@ -1,4 +1,5 @@
import type { Dispatch, SetStateAction } from 'react';
import type { LLMProvider } from '../../../types/app';
import type { ProviderAuthStatus } from '../../provider-auth/types';
@@ -29,6 +30,7 @@ export type NotificationPreferencesState = {
channels: {
inApp: boolean;
webPush: boolean;
sound: boolean;
};
events: {
actionRequired: boolean;

View File

@@ -1,5 +1,8 @@
import { Bell, BellOff, BellRing, Loader2 } from 'lucide-react';
import { Bell, BellOff, BellRing, Loader2, Play, Volume2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { Button } from '../../../../shared/view/ui';
import { playChatCompletionSound } from '../../../../utils/notificationSound';
import type { NotificationPreferencesState } from '../../types/types';
type NotificationsSettingsTabProps = {
@@ -82,6 +85,54 @@ export default function NotificationsSettingsTab({
)}
</div>
<div className="space-y-4 rounded-lg border border-border bg-card p-4">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2">
<Volume2 className="h-4 w-4 text-blue-600" />
<h4 className="font-medium text-foreground">
{t('notifications.sound.title', { defaultValue: 'Sound' })}
</h4>
</div>
<p className="text-sm text-muted-foreground">
{t('notifications.sound.description', {
defaultValue: 'Play a short tone when a chat run finishes.',
})}
</p>
</div>
<label className="flex shrink-0 items-center gap-2 text-sm text-foreground">
<input
type="checkbox"
checked={notificationPreferences.channels.sound}
onChange={(event) =>
onNotificationPreferencesChange({
...notificationPreferences,
channels: {
...notificationPreferences.channels,
sound: event.target.checked,
},
})
}
className="h-4 w-4"
/>
{t('notifications.sound.enabled', { defaultValue: 'Enabled' })}
</label>
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={() => {
void playChatCompletionSound({ force: true });
}}
>
<Play className="h-4 w-4" />
{t('notifications.sound.test', { defaultValue: 'Test sound' })}
</Button>
</div>
<div className="space-y-4 bg-card border border-border rounded-lg p-4">
<h4 className="font-medium text-foreground">{t('notifications.events.title')}</h4>
<div className="space-y-3">

View File

@@ -1,4 +1,6 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState, type ReactNode } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { useTranslation } from "react-i18next";
import { authenticatedFetch } from "../../../utils/api";
import { ReleaseInfo } from "../../../types/sharedTypes";
@@ -154,8 +156,10 @@ export function VersionUpgradeModal({
)}
</div>
<div className="max-h-64 overflow-y-auto rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-600 dark:bg-gray-700/50">
<div className="prose prose-sm max-w-none whitespace-pre-wrap text-sm text-gray-700 dark:prose-invert dark:text-gray-300">
{cleanChangelog(releaseInfo.body)}
<div className="prose prose-sm max-w-none text-sm text-gray-700 dark:prose-invert dark:text-gray-300">
<ReactMarkdown remarkPlugins={[remarkGfm]} components={changelogComponents}>
{cleanChangelog(releaseInfo.body)}
</ReactMarkdown>
</div>
</div>
</div>
@@ -236,6 +240,14 @@ export function VersionUpgradeModal({
);
};
const changelogComponents = {
a: ({ href, children }: { href?: string; children?: ReactNode }) => (
<a href={href} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline dark:text-blue-400">
{children}
</a>
),
};
// Clean up changelog by removing GitHub-specific metadata
const cleanChangelog = (body: string) => {
if (!body) return '';

View File

@@ -94,9 +94,35 @@
"git": "Git",
"apiTokens": "API & Token",
"tasks": "Aufgaben",
"notifications": "Benachrichtigungen",
"plugins": "Plugins",
"about": "Info"
},
"notifications": {
"title": "Benachrichtigungen",
"description": "Lege fest, welche Benachrichtigungen du erhältst.",
"webPush": {
"title": "Web-Push-Benachrichtigungen",
"enable": "Push-Benachrichtigungen aktivieren",
"disable": "Push-Benachrichtigungen deaktivieren",
"enabled": "Push-Benachrichtigungen sind aktiviert",
"loading": "Wird aktualisiert...",
"unsupported": "Push-Benachrichtigungen werden in diesem Browser nicht unterstützt.",
"denied": "Push-Benachrichtigungen sind blockiert. Bitte erlaube sie in den Browsereinstellungen."
},
"sound": {
"title": "Ton",
"description": "Spielt einen kurzen Ton ab, wenn ein Chat-Lauf abgeschlossen ist.",
"enabled": "Aktiviert",
"test": "Ton testen"
},
"events": {
"title": "Ereignistypen",
"actionRequired": "Aktion erforderlich",
"stop": "Lauf gestoppt",
"error": "Lauf fehlgeschlagen"
}
},
"appearanceSettings": {
"darkMode": {
"label": "Darkmode",

View File

@@ -110,6 +110,12 @@
"unsupported": "Push notifications are not supported in this browser.",
"denied": "Push notifications are blocked. Please allow them in your browser settings."
},
"sound": {
"title": "Sound",
"description": "Play a short tone when a chat run finishes.",
"enabled": "Enabled",
"test": "Test sound"
},
"events": {
"title": "Event Types",
"actionRequired": "Action required",
@@ -508,6 +514,30 @@
"description": "Session intelligence for Claude Code, inside CloudCLI. See why your sessions are burning tokens without leaving the browser.",
"install": "Install"
},
"sessionManagerPlugin": {
"name": "Sessions",
"badge": "unofficial",
"description": "View, manage, and kill active Claude Code sessions.",
"install": "Install"
},
"tokenCostCalculatorPlugin": {
"name": "Token Cost Calculator",
"badge": "unofficial",
"description": "Calculate API costs from model prices and token usage, with preset model pricing support.",
"install": "Install"
},
"taskQueuePlugin": {
"name": "Task Queue",
"badge": "unofficial",
"description": "Task queue dashboard to view, filter, and launch agent tasks.",
"install": "Install"
},
"githubIssuesBoardPlugin": {
"name": "GitHub Issues Board",
"badge": "unofficial",
"description": "Kanban board for GitHub Issues with bidirectional TaskMaster sync and /github-task CLI skill auto-install",
"install": "Install"
},
"morePlugins": "More",
"enable": "Enable",
"disable": "Disable",

View File

@@ -110,6 +110,12 @@
"unsupported": "Le notifiche push non sono supportate in questo browser.",
"denied": "Le notifiche push sono bloccate. Abilitale nelle impostazioni del browser."
},
"sound": {
"title": "Suono",
"description": "Riproduci un breve tono quando termina un'esecuzione della chat.",
"enabled": "Attivato",
"test": "Prova suono"
},
"events": {
"title": "Tipi di evento",
"actionRequired": "Azione richiesta",

View File

@@ -110,6 +110,12 @@
"unsupported": "このブラウザではプッシュ通知がサポートされていません。",
"denied": "プッシュ通知がブロックされています。ブラウザの設定で許可してください。"
},
"sound": {
"title": "サウンド",
"description": "チャット実行が完了したときに短い音を再生します。",
"enabled": "有効",
"test": "サウンドをテスト"
},
"events": {
"title": "イベント種別",
"actionRequired": "対応が必要",

View File

@@ -110,6 +110,12 @@
"unsupported": "이 브라우저에서는 푸시 알림이 지원되지 않습니다.",
"denied": "푸시 알림이 차단되었습니다. 브라우저 설정에서 허용해 주세요."
},
"sound": {
"title": "소리",
"description": "채팅 실행이 완료되면 짧은 알림음을 재생합니다.",
"enabled": "사용",
"test": "소리 테스트"
},
"events": {
"title": "이벤트 유형",
"actionRequired": "작업 필요",

View File

@@ -94,9 +94,35 @@
"git": "Git",
"apiTokens": "API и токены",
"tasks": "Задачи",
"notifications": "Уведомления",
"plugins": "Плагины",
"about": "О программе"
},
"notifications": {
"title": "Уведомления",
"description": "Управляйте тем, какие события уведомлений вы получаете.",
"webPush": {
"title": "Web Push уведомления",
"enable": "Включить Push уведомления",
"disable": "Отключить Push уведомления",
"enabled": "Push уведомления включены",
"loading": "Обновление...",
"unsupported": "Push уведомления не поддерживаются в этом браузере.",
"denied": "Push уведомления заблокированы. Разрешите их в настройках браузера."
},
"sound": {
"title": "Звук",
"description": "Воспроизводить короткий сигнал при завершении запуска чата.",
"enabled": "Включено",
"test": "Проверить звук"
},
"events": {
"title": "Типы событий",
"actionRequired": "Требуется действие",
"stop": "Запуск остановлен",
"error": "Запуск завершился с ошибкой"
}
},
"appearanceSettings": {
"darkMode": {
"label": "Темная тема",

View File

@@ -110,6 +110,12 @@
"unsupported": "Bu tarayıcıda push bildirimleri desteklenmiyor.",
"denied": "Push bildirimleri engellendi. Lütfen tarayıcı ayarlarından izin ver."
},
"sound": {
"title": "Ses",
"description": "Sohbet çalışması tamamlandığında kısa bir ton çal.",
"enabled": "Etkin",
"test": "Sesi test et"
},
"events": {
"title": "Etkinlik Türleri",
"actionRequired": "Aksiyon gerekli",

View File

@@ -110,6 +110,12 @@
"unsupported": "此浏览器不支持推送通知。",
"denied": "推送通知已被阻止,请在浏览器设置中允许。"
},
"sound": {
"title": "声音",
"description": "聊天运行完成时播放短提示音。",
"enabled": "已启用",
"test": "测试声音"
},
"events": {
"title": "事件类型",
"actionRequired": "需要处理",

View File

@@ -110,6 +110,12 @@
"unsupported": "此瀏覽器不支援推播通知。",
"denied": "推播通知已被封鎖,請在瀏覽器設定中允許。"
},
"sound": {
"title": "聲音",
"description": "聊天執行完成時播放短提示音。",
"enabled": "已啟用",
"test": "測試聲音"
},
"events": {
"title": "事件類型",
"actionRequired": "需要處理",

View File

@@ -0,0 +1,83 @@
const NOTIFICATION_SOUND_ENABLED_STORAGE_KEY = 'notificationSoundEnabled';
const AudioContextConstructor =
typeof window !== 'undefined'
? window.AudioContext || (window as typeof window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext
: undefined;
let audioContext: AudioContext | null = null;
export const isNotificationSoundEnabled = (): boolean => {
if (typeof localStorage === 'undefined') {
return true;
}
return localStorage.getItem(NOTIFICATION_SOUND_ENABLED_STORAGE_KEY) !== 'false';
};
export const setNotificationSoundEnabled = (enabled: boolean): void => {
if (typeof localStorage === 'undefined') {
return;
}
localStorage.setItem(NOTIFICATION_SOUND_ENABLED_STORAGE_KEY, String(enabled));
};
const getAudioContext = (): AudioContext | null => {
if (!AudioContextConstructor) {
return null;
}
if (!audioContext) {
audioContext = new AudioContextConstructor();
}
return audioContext;
};
const playTone = (
context: AudioContext,
frequency: number,
startsAt: number,
duration: number,
peakVolume: number,
): void => {
const oscillator = context.createOscillator();
const gain = context.createGain();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(frequency, startsAt);
// Shape the volume so the synthesized tone starts and stops cleanly.
gain.gain.setValueAtTime(0.0001, startsAt);
gain.gain.exponentialRampToValueAtTime(peakVolume, startsAt + 0.015);
gain.gain.exponentialRampToValueAtTime(0.0001, startsAt + duration);
oscillator.connect(gain);
gain.connect(context.destination);
oscillator.start(startsAt);
oscillator.stop(startsAt + duration + 0.02);
};
export const playChatCompletionSound = async ({ force = false } = {}): Promise<void> => {
if (!force && !isNotificationSoundEnabled()) {
return;
}
const context = getAudioContext();
if (!context) {
return;
}
try {
if (context.state === 'suspended') {
await context.resume();
}
const now = context.currentTime;
playTone(context, 740, now, 0.12, 0.075);
playTone(context, 988, now + 0.11, 0.16, 0.06);
} catch (error) {
// Browsers may block audio until the page receives a user gesture.
console.warn('Unable to play notification sound:', error);
}
};

View File

@@ -0,0 +1,112 @@
const COMPLETION_TITLE_INDICATOR = '[Done]';
const TITLE_INDICATOR_CLEAR_DELAY_MS = 2000;
let clearTimer: number | null = null;
let returnListenersAttached = false;
const getIndicatorPrefix = () => `${COMPLETION_TITLE_INDICATOR} `;
const stripIndicator = (title: string): string => {
const prefix = getIndicatorPrefix();
return title.startsWith(prefix) ? title.slice(prefix.length) : title;
};
const pageIsActive = (): boolean => (
document.visibilityState === 'visible' && document.hasFocus()
);
const removeReturnListeners = (): void => {
if (!returnListenersAttached || typeof window === 'undefined') {
return;
}
document.removeEventListener('visibilitychange', handleUserReturn);
window.removeEventListener('focus', handleUserReturn, true);
window.removeEventListener('click', handleUserReturn, true);
returnListenersAttached = false;
};
const clearTitleIndicator = (): void => {
if (clearTimer !== null) {
window.clearTimeout(clearTimer);
clearTimer = null;
}
removeReturnListeners();
removePageInactiveListener();
if (document.title.startsWith(getIndicatorPrefix())) {
document.title = stripIndicator(document.title);
}
};
const removePageInactiveListener = (): void => {
document.removeEventListener('visibilitychange', handlePageInactive);
};
const scheduleClear = (): void => {
if (clearTimer !== null) {
window.clearTimeout(clearTimer);
}
clearTimer = window.setTimeout(() => {
clearTitleIndicator();
}, TITLE_INDICATOR_CLEAR_DELAY_MS);
removePageInactiveListener();
document.addEventListener('visibilitychange', handlePageInactive, { once: true });
};
function handleUserReturn(): void {
if (!pageIsActive()) {
return;
}
// Background completions keep the marker indefinitely. A tab click normally
// surfaces as visibility/focus, while an in-page click is a useful fallback.
scheduleClear();
}
function handlePageInactive(): void {
if (document.visibilityState !== 'hidden') {
return;
}
if (clearTimer !== null) {
window.clearTimeout(clearTimer);
clearTimer = null;
}
if (!returnListenersAttached) {
document.addEventListener('visibilitychange', handleUserReturn);
window.addEventListener('focus', handleUserReturn, true);
window.addEventListener('click', handleUserReturn, true);
returnListenersAttached = true;
}
}
export const showCompletionTitleIndicator = (): void => {
if (typeof document === 'undefined' || typeof window === 'undefined') {
return;
}
const baseTitle = stripIndicator(document.title || 'CloudCLI UI');
document.title = `${getIndicatorPrefix()}${baseTitle}`;
if (pageIsActive()) {
scheduleClear();
return;
}
if (clearTimer !== null) {
window.clearTimeout(clearTimer);
clearTimer = null;
}
if (!returnListenersAttached) {
document.addEventListener('visibilitychange', handleUserReturn);
window.addEventListener('focus', handleUserReturn, true);
window.addEventListener('click', handleUserReturn, true);
returnListenersAttached = true;
}
};