diff --git a/README.md b/README.md index 75f37762f9..6f024db235 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ - [简体中文](locales/zh-CN/README.md) - [繁體中文](locales/zh-TW/README.md) - ... - + --- @@ -58,18 +58,17 @@ Roo Code adapts to how you work: - Ask Mode: fast answers, explanations, and docs - Debug Mode: trace issues, add logs, isolate root causes - Custom Modes: build specialized modes for your team or workflow -- Roomote Control: Roomote Control lets you remotely control tasks running in your local VS Code instance. -Learn more: [Using Modes](https://docs.roocode.com/basic-usage/using-modes) • [Custom Modes](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Learn more: [Using Modes](https://docs.roocode.com/basic-usage/using-modes) • [Custom Modes](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutorial & Feature Videos
-| | | | -| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
Installing Roo Code |
Configuring Profiles |
Codebase Indexing | -|
Custom Modes |
Checkpoints |
Context Management | +| | | | +| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
Installing Roo Code |
Configuring Profiles |
Codebase Indexing | +|
Custom Modes |
Checkpoints |
Context Management |

diff --git a/locales/ca/README.md b/locales/ca/README.md index 0c09d8c661..be4aae4cc0 100644 --- a/locales/ca/README.md +++ b/locales/ca/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code s'adapta a la teva manera de treballar, no a l'inrevés: - Mode Pregunta: respostes ràpides, explicacions i documents - Mode Depuració: rastrejar problemes, afegir registres, aïllar les causes arrel - Modes personalitzats: crea modes especialitzats per al teu equip o flux de treball -- Roomote Control: Roomote Control et permet controlar a distància tasques que s'executen a la teva instància local de VS Code. -Més informació: [Ús de Modes](https://docs.roocode.com/basic-usage/using-modes) • [Modes personalitzats](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Més informació: [Ús de Modes](https://docs.roocode.com/basic-usage/using-modes) • [Modes personalitzats](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutorials i vídeos de funcionalitats @@ -69,7 +68,7 @@ Més informació: [Ús de Modes](https://docs.roocode.com/basic-usage/using-mode | | | | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Instal·lant Roo Code |
Configurant perfils |
Indexació de la base de codi | -|
Modes personalitzats |
Punts de control |
Gestió de Context | +|
Modes personalitzats |
Punts de control |
Gestió de Context |

diff --git a/locales/de/README.md b/locales/de/README.md index 526d601e70..634996646d 100644 --- a/locales/de/README.md +++ b/locales/de/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code passt sich an deine Arbeitsweise an, nicht umgekehrt: - Fragen-Modus: schnelle Antworten, Erklärungen und Dokumentationen - Debug-Modus: Probleme aufspüren, Protokolle hinzufügen, Ursachen isolieren - Benutzerdefinierte Modi: erstelle spezialisierte Modi für dein Team oder deinen Workflow -- Roomote Control: Mit Roomote Control kannst du Aufgaben in deiner lokalen VS Code-Instanz aus der Ferne steuern. -Mehr erfahren: [Modi verwenden](https://docs.roocode.com/basic-usage/using-modes) • [Benutzerdefinierte Modi](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Mehr erfahren: [Modi verwenden](https://docs.roocode.com/basic-usage/using-modes) • [Benutzerdefinierte Modi](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutorial- & Feature-Videos @@ -69,7 +68,7 @@ Mehr erfahren: [Modi verwenden](https://docs.roocode.com/basic-usage/using-modes | | | | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Roo Code installieren |
Profile konfigurieren |
Codebasis-Indizierung | -|
Benutzerdefinierte Modi |
Checkpoints |
Kontextverwaltung | +|
Benutzerdefinierte Modi |
Checkpoints |
Kontextverwaltung |

diff --git a/locales/es/README.md b/locales/es/README.md index 9e378b7fd7..6764151149 100644 --- a/locales/es/README.md +++ b/locales/es/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code se adapta a tu forma de trabajar, no al revés: - Modo Pregunta: respuestas rápidas, explicaciones y documentos - Modo Depuración: rastrear problemas, agregar registros, aislar causas raíz - Modos Personalizados: crea modos especializados para tu equipo o flujo de trabajo -- Roomote Control: Roomote Control te permite controlar de forma remota tareas que se ejecutan en tu instancia local de VS Code. -Más info: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [Modos Personalizados](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Más info: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [Modos Personalizados](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutoriales y vídeos de funcionalidades @@ -69,7 +68,7 @@ Más info: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [M | | | | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Instalando Roo Code |
Configurando perfiles |
Indexación de la base de código | -|
Modos personalizados |
Checkpoints |
Gestión de Contexto | +|
Modos personalizados |
Checkpoints |
Gestión de Contexto |

diff --git a/locales/fr/README.md b/locales/fr/README.md index 5197e76f0e..36e693f041 100644 --- a/locales/fr/README.md +++ b/locales/fr/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code s'adapte à votre façon de travailler, pas l'inverse : - Mode Demande : réponses rapides, explications et documents - Mode Débogage : tracer les problèmes, ajouter des journaux, isoler les causes profondes - Modes Personnalisés : créez des modes spécialisés pour votre équipe ou votre flux de travail -- Roomote Control : Roomote Control te permet de piloter à distance les tâches exécutées dans ton instance VS Code locale. -En savoir plus : [Utiliser les Modes](https://docs.roocode.com/basic-usage/using-modes) • [Modes personnalisés](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +En savoir plus : [Utiliser les Modes](https://docs.roocode.com/basic-usage/using-modes) • [Modes personnalisés](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutoriels & Vidéos de fonctionnalités @@ -69,7 +68,7 @@ En savoir plus : [Utiliser les Modes](https://docs.roocode.com/basic-usage/using | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Installer Roo Code |
Configurer les profils |
Indexation de la base de code | -|
Modes personnalisés |
Checkpoints |
Gestion du Contexte | +|
Modes personnalisés |
Checkpoints |
Gestion du Contexte |

diff --git a/locales/hi/README.md b/locales/hi/README.md index 8d12b68994..27cb624213 100644 --- a/locales/hi/README.md +++ b/locales/hi/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ - पूछें मोड: त्वरित उत्तर, स्पष्टीकरण और डॉक्स - डीबग मोड: समस्याओं का पता लगाएं, लॉग जोड़ें, मूल कारणों को अलग करें - कस्टम मोड: अपनी टीम या वर्कफ़्लो के लिए विशेष मोड बनाएं -- Roomote Control: Roomote Control से तुम अपनी लोकल VS Code इंस्टेंस में चल रही टास्क को रिमोट से कंट्रोल कर सकते हो। -और जानो: [मोड्स का इस्तेमाल](https://docs.roocode.com/basic-usage/using-modes) • [कस्टम मोड्स](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +और जानो: [मोड्स का इस्तेमाल](https://docs.roocode.com/basic-usage/using-modes) • [कस्टम मोड्स](https://docs.roocode.com/advanced-usage/custom-modes) ## ट्यूटोरियल और फ़ीचर वीडियो @@ -69,7 +68,7 @@ | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
रू कोड इंस्टॉल करना |
प्रोफाइल कॉन्फ़िगर करना |
कोडबेस इंडेक्सिंग | -|
कस्टम मोड |
चेकपॉइंट्स |
संदर्भ प्रबंधन | +|
कस्टम मोड |
चेकपॉइंट्स |
संदर्भ प्रबंधन |

diff --git a/locales/id/README.md b/locales/id/README.md index 657b1ab750..0d208c18a3 100644 --- a/locales/id/README.md +++ b/locales/id/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code beradaptasi dengan cara Anda bekerja, bukan sebaliknya: - Mode Tanya: jawaban cepat, penjelasan, dan dokumen - Mode Debug: melacak masalah, menambahkan log, mengisolasi akar penyebab - Mode Kustom: buat mode khusus untuk tim atau alur kerja Anda -- Roomote Control: Roomote Control memungkinkan kamu mengontrol dari jarak jauh tugas yang berjalan di VS Code lokalmu. -Pelajari lebih lanjut: [Menggunakan Mode](https://docs.roocode.com/basic-usage/using-modes) • [Mode Kustom](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Pelajari lebih lanjut: [Menggunakan Mode](https://docs.roocode.com/basic-usage/using-modes) • [Mode Kustom](https://docs.roocode.com/advanced-usage/custom-modes) ## Video Tutorial & Fitur @@ -69,7 +68,7 @@ Pelajari lebih lanjut: [Menggunakan Mode](https://docs.roocode.com/basic-usage/u | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Menginstal Roo Code |
Mengonfigurasi Profil |
Pengindeksan Basis Kode | -|
Mode Kustom |
Pos Pemeriksaan |
Manajemen Konteks | +|
Mode Kustom |
Pos Pemeriksaan |
Manajemen Konteks |

diff --git a/locales/it/README.md b/locales/it/README.md index 9bd5ce9e81..69a7393967 100644 --- a/locales/it/README.md +++ b/locales/it/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code si adatta al tuo modo di lavorare, non il contrario: - Modalità Chiedi: risposte rapide, spiegazioni e documenti - Modalità Debug: traccia problemi, aggiungi log, isola le cause principali - Modalità Personalizzate: crea modalità specializzate per il tuo team o flusso di lavoro -- Roomote Control: Roomote Control ti permette di controllare da remoto le attività in esecuzione sulla tua istanza locale di VS Code. -Scopri di più: [Usare le Modalità](https://docs.roocode.com/basic-usage/using-modes) • [Modalità personalizzate](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Scopri di più: [Usare le Modalità](https://docs.roocode.com/basic-usage/using-modes) • [Modalità personalizzate](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutorial e video sulle funzionalità @@ -69,7 +68,7 @@ Scopri di più: [Usare le Modalità](https://docs.roocode.com/basic-usage/using- | | | | | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Installazione di Roo Code |
Configurazione dei profili |
Indicizzazione della codebase | -|
Modalità personalizzate |
Checkpoint |
Gestione del Contesto | +|
Modalità personalizzate |
Checkpoint |
Gestione del Contesto |

diff --git a/locales/ja/README.md b/locales/ja/README.md index 3b7a7a6e6e..dd5332b961 100644 --- a/locales/ja/README.md +++ b/locales/ja/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Codeは、あなたの働き方に合わせるように適応します。 - 質問モード:迅速な回答、説明、ドキュメント - デバッグモード:問題の追跡、ログの追加、根本原因の特定 - カスタムモード:チームやワークフローに特化したモードの構築 -- Roomote Control: Roomote Control はローカルの VS Code で実行中のタスクをリモート操作できます。 -詳しくは: [モードの使い方](https://docs.roocode.com/basic-usage/using-modes) • [カスタムモード](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +詳しくは: [モードの使い方](https://docs.roocode.com/basic-usage/using-modes) • [カスタムモード](https://docs.roocode.com/advanced-usage/custom-modes) ## チュートリアルと機能のビデオ @@ -69,7 +68,7 @@ Roo Codeは、あなたの働き方に合わせるように適応します。 | | | | | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Roo Codeのインストール |
プロファイルの設定 |
コードベースのインデックス作成 | -|
カスタムモード |
チェックポイント |
コンテキスト管理 | +|
カスタムモード |
チェックポイント |
コンテキスト管理 |

diff --git a/locales/ko/README.md b/locales/ko/README.md index a53a1b965f..1070244b78 100644 --- a/locales/ko/README.md +++ b/locales/ko/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code는 당신의 작업 방식에 맞춰 적응합니다. - 질문 모드: 빠른 답변, 설명 및 문서 - 디버그 모드: 문제 추적, 로그 추가, 근본 원인 격리 - 사용자 지정 모드: 팀이나 워크플로우를 위한 특수 모드 구축 -- Roomote Control: Roomote Control은 로컬 VS Code 인스턴스에서 실행 중인 작업을 원격으로 제어할 수 있어. -자세히: [모드 사용](https://docs.roocode.com/basic-usage/using-modes) • [사용자 지정 모드](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +자세히: [모드 사용](https://docs.roocode.com/basic-usage/using-modes) • [사용자 지정 모드](https://docs.roocode.com/advanced-usage/custom-modes) ## 튜토리얼 및 기능 비디오 @@ -69,7 +68,7 @@ Roo Code는 당신의 작업 방식에 맞춰 적응합니다. | | | | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Roo Code 설치하기 |
프로필 구성하기 |
코드베이스 인덱싱 | -|
사용자 지정 모드 |
체크포인트 |
컨텍스트 관리 | +|
사용자 지정 모드 |
체크포인트 |
컨텍스트 관리 |

diff --git a/locales/nl/README.md b/locales/nl/README.md index fa5454b9c5..52e7138f8c 100644 --- a/locales/nl/README.md +++ b/locales/nl/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code past zich aan jouw werkwijze aan, niet andersom: - Vraag Modus: snelle antwoorden, uitleg en documenten - Debug Modus: spoor problemen op, voeg logs toe, isoleer de oorzaak - Aangepaste Modi: bouw gespecialiseerde modi voor je team of workflow -- Roomote Control: Roomote Control laat je taken op je lokale VS Code-instantie op afstand besturen. -Meer info: [Modi gebruiken](https://docs.roocode.com/basic-usage/using-modes) • [Aangepaste modi](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Meer info: [Modi gebruiken](https://docs.roocode.com/basic-usage/using-modes) • [Aangepaste modi](https://docs.roocode.com/advanced-usage/custom-modes) ## Tutorial & Feature Videos diff --git a/locales/pl/README.md b/locales/pl/README.md index b8553a08c7..8f79597598 100644 --- a/locales/pl/README.md +++ b/locales/pl/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code dostosowuje się do Twojego sposobu pracy, a nie odwrotnie: - Tryb Zapytaj: szybkie odpowiedzi, wyjaśnienia i dokumenty - Tryb Debugowanie: śledzenie problemów, dodawanie logów, izolowanie przyczyn źródłowych - Tryby niestandardowe: buduj specjalistyczne tryby dla swojego zespołu lub przepływu pracy -- Roomote Control: Roomote Control pozwala zdalnie sterować zadaniami uruchomionymi na twojej lokalnej instancji VS Code. -Więcej: [Korzystanie z trybów](https://docs.roocode.com/basic-usage/using-modes) • [Tryby niestandardowe](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Więcej: [Korzystanie z trybów](https://docs.roocode.com/basic-usage/using-modes) • [Tryby niestandardowe](https://docs.roocode.com/advanced-usage/custom-modes) ## Filmy instruktażowe i prezentujące funkcje @@ -69,7 +68,7 @@ Więcej: [Korzystanie z trybów](https://docs.roocode.com/basic-usage/using-mode | | | | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Instalacja Roo Code |
Konfiguracja profili |
Indeksowanie bazy kodu | -|
Tryby niestandardowe |
Punkty kontrolne |
Zarządzanie Kontekstem | +|
Tryby niestandardowe |
Punkty kontrolne |
Zarządzanie Kontekstem |

diff --git a/locales/pt-BR/README.md b/locales/pt-BR/README.md index 3b128b0fd3..50269e00ed 100644 --- a/locales/pt-BR/README.md +++ b/locales/pt-BR/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ O Roo Code se adapta à sua maneira de trabalhar, e não o contrário: - Modo Pergunta: respostas rápidas, explicações e documentos - Modo Depuração: rastreie problemas, adicione logs, isole as causas raiz - Modos Personalizados: crie modos especializados para sua equipe ou fluxo de trabalho -- Roomote Control: O Roomote Control permite controlar remotamente tarefas em execução na sua instância local do VS Code. -Saiba mais: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [Modos personalizados](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Saiba mais: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [Modos personalizados](https://docs.roocode.com/advanced-usage/custom-modes) ## Vídeos de tutorial e recursos @@ -69,7 +68,7 @@ Saiba mais: [Usar Modos](https://docs.roocode.com/basic-usage/using-modes) • [ | | | | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Instalando o Roo Code |
Configurando perfis |
Indexação da base de código | -|
Modos personalizados |
Checkpoints |
Gerenciamento de Contexto | +|
Modos personalizados |
Checkpoints |
Gerenciamento de Contexto |

diff --git a/locales/ru/README.md b/locales/ru/README.md index 9abf4ae511..a323ff417c 100644 --- a/locales/ru/README.md +++ b/locales/ru/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code адаптируется к вашему стилю работы, а н - Режим Вопрос: быстрые ответы, объяснения и документация - Режим Отладка: отслеживание проблем, добавление логов, изоляция первопричин - Пользовательские режимы: создавайте специализированные режимы для вашей команды или рабочего процесса -- Roomote Control: Roomote Control позволяет удаленно управлять задачами, запущенными в вашей локальной инстансе VS Code. -Подробнее: [Использование режимов](https://docs.roocode.com/basic-usage/using-modes) • [Пользовательские режимы](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Подробнее: [Использование режимов](https://docs.roocode.com/basic-usage/using-modes) • [Пользовательские режимы](https://docs.roocode.com/advanced-usage/custom-modes) ## Обучающие видео и видео о функциях @@ -69,7 +68,7 @@ Roo Code адаптируется к вашему стилю работы, а н | | | | | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |
Установка Roo Code |
Настройка профилей |
Индексация кодовой базы | -|
Пользовательские режимы |
Контрольные точки |
Управление Контекстом | +|
Пользовательские режимы |
Контрольные точки |
Управление Контекстом |

diff --git a/locales/tr/README.md b/locales/tr/README.md index ac5a788407..2847a23c06 100644 --- a/locales/tr/README.md +++ b/locales/tr/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,18 +58,17 @@ Roo Code, sizin çalışma şeklinize uyum sağlar, tam tersi değil: - Sor Modu: hızlı cevaplar, açıklamalar ve belgeler - Hata Ayıklama Modu: sorunları izleyin, günlükler ekleyin, kök nedenleri izole edin - Özel Modlar: ekibiniz veya iş akışınız için özel modlar oluşturun -- Roomote Control: Roomote Control, yerel VS Code örneğinde çalışan işleri uzaktan kontrol etmeni sağlar. -Daha fazla: [Modları kullanma](https://docs.roocode.com/basic-usage/using-modes) • [Özel modlar](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Daha fazla: [Modları kullanma](https://docs.roocode.com/basic-usage/using-modes) • [Özel modlar](https://docs.roocode.com/advanced-usage/custom-modes) ## Eğitim ve Özellik Videoları

-| | | | -| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
Roo Code Kurulumu |
Profilleri Yapılandırma |
Kod Tabanı İndeksleme | -|
Özel Modlar |
Kontrol Noktaları |
Bağlam Yönetimi | +| | | | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
Roo Code Kurulumu |
Profilleri Yapılandırma |
Kod Tabanı İndeksleme | +|
Özel Modlar |
Kontrol Noktaları |
Bağlam Yönetimi |

diff --git a/locales/vi/README.md b/locales/vi/README.md index bedaa3c26a..aa9b4ff674 100644 --- a/locales/vi/README.md +++ b/locales/vi/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,18 +58,17 @@ Roo Code thích ứng với cách bạn làm việc, chứ không phải ngượ - Chế độ Hỏi: câu trả lời nhanh, giải thích và tài liệu - Chế độ Gỡ lỗi: theo dõi sự cố, thêm nhật ký, cô lập nguyên nhân gốc rễ - Chế độ Tùy chỉnh: xây dựng các chế độ chuyên biệt cho nhóm hoặc quy trình làm việc của bạn -- Roomote Control: Roomote Control cho phép bạn điều khiển từ xa các tác vụ đang chạy trên VS Code cục bộ của bạn. -Xem thêm: [Sử dụng Chế độ](https://docs.roocode.com/basic-usage/using-modes) • [Chế độ tùy chỉnh](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +Xem thêm: [Sử dụng Chế độ](https://docs.roocode.com/basic-usage/using-modes) • [Chế độ tùy chỉnh](https://docs.roocode.com/advanced-usage/custom-modes) ## Video hướng dẫn & tính năng

-| | | | -| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
Cài đặt Roo Code |
Định cấu hình Hồ sơ |
Lập chỉ mục cơ sở mã | -|
Chế độ tùy chỉnh |
Điểm kiểm tra |
Quản lý Ngữ cảnh | +| | | | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
Cài đặt Roo Code |
Định cấu hình Hồ sơ |
Lập chỉ mục cơ sở mã | +|
Chế độ tùy chỉnh |
Điểm kiểm tra |
Quản lý Ngữ cảnh |

diff --git a/locales/zh-CN/README.md b/locales/zh-CN/README.md index a21e147f96..ef26871f31 100644 --- a/locales/zh-CN/README.md +++ b/locales/zh-CN/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,17 +58,16 @@ Roo Code 适应您的工作方式,而不是相反: - 提问模式:快速回答、解释和文档 - 调试模式:跟踪问题、添加日志、隔离根本原因 - 自定义模式:为您的团队或工作流程构建专门的模式 -- Roomote Control:Roomote Control 允许你远程控制在本地 VS Code 实例中运行的任务。 -了解更多:[使用模式](https://docs.roocode.com/basic-usage/using-modes) • [自定义模式](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +了解更多:[使用模式](https://docs.roocode.com/basic-usage/using-modes) • [自定义模式](https://docs.roocode.com/advanced-usage/custom-modes) ## 教程和功能视频

-| | | | -| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
安装 Roo Code |
配置个人资料 |
代码库索引 | +| | | | +| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
安装 Roo Code |
配置个人资料 |
代码库索引 | |
自定义模式 |
检查点 |
上下文管理 |
diff --git a/locales/zh-TW/README.md b/locales/zh-TW/README.md index fe985d7ec8..db94c425c9 100644 --- a/locales/zh-TW/README.md +++ b/locales/zh-TW/README.md @@ -35,7 +35,7 @@ - [简体中文](../zh-CN/README.md) - [繁體中文](../zh-TW/README.md) - ... - + --- @@ -58,9 +58,8 @@ Roo Code 會配合您的工作方式,而非要您配合它: - 詢問模式:快速回答、解釋和文件 - 偵錯模式:追蹤問題、新增日誌、鎖定根本原因 - 自訂模式:為您的團隊或工作流程建置專門的模式 -- Roomote Control:Roomote Control 讓您能遠端控制在本機 VS Code 執行個體中運行的工作。 -更多資訊:[使用模式](https://docs.roocode.com/basic-usage/using-modes) • [自訂模式](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control) +更多資訊:[使用模式](https://docs.roocode.com/basic-usage/using-modes) • [自訂模式](https://docs.roocode.com/advanced-usage/custom-modes) ## 教學和功能影片 diff --git a/packages/cloud/package.json b/packages/cloud/package.json index 2d4456d273..92ecaa1764 100644 --- a/packages/cloud/package.json +++ b/packages/cloud/package.json @@ -15,7 +15,6 @@ "ioredis": "^5.6.1", "jwt-decode": "^4.0.0", "p-wait-for": "^5.0.2", - "socket.io-client": "^4.8.1", "zod": "^3.25.76" }, "devDependencies": { diff --git a/packages/cloud/src/StaticSettingsService.ts b/packages/cloud/src/StaticSettingsService.ts index 492a0a8d4b..2365208f9d 100644 --- a/packages/cloud/src/StaticSettingsService.ts +++ b/packages/cloud/src/StaticSettingsService.ts @@ -42,15 +42,12 @@ export class StaticSettingsService implements SettingsService { } /** - * Returns static user settings with roomoteControlEnabled and extensionBridgeEnabled as true + * Returns static user settings with task sync enabled */ public getUserSettings(): UserSettingsData | undefined { return { - features: { - roomoteControlEnabled: true, - }, + features: {}, settings: { - extensionBridgeEnabled: true, taskSyncEnabled: true, }, version: 1, @@ -58,14 +55,11 @@ export class StaticSettingsService implements SettingsService { } public getUserFeatures(): UserFeatures { - return { - roomoteControlEnabled: true, - } + return {} } public getUserSettingsConfig(): UserSettingsConfig { return { - extensionBridgeEnabled: true, taskSyncEnabled: true, } } diff --git a/packages/cloud/src/StaticTokenAuthService.ts b/packages/cloud/src/StaticTokenAuthService.ts index 2ff7b75f0e..c2450b0c22 100644 --- a/packages/cloud/src/StaticTokenAuthService.ts +++ b/packages/cloud/src/StaticTokenAuthService.ts @@ -30,7 +30,6 @@ export class StaticTokenAuthService extends EventEmitter impl this.userInfo = { id: payload?.r?.u || payload?.sub || undefined, organizationId: payload?.r?.o || undefined, - extensionBridgeEnabled: true, } } diff --git a/packages/cloud/src/WebAuthService.ts b/packages/cloud/src/WebAuthService.ts index 69ad28e8ec..501bf95bb5 100644 --- a/packages/cloud/src/WebAuthService.ts +++ b/packages/cloud/src/WebAuthService.ts @@ -625,8 +625,6 @@ export class WebAuthService extends EventEmitter implements A )?.email_address } - let extensionBridgeEnabled = true - // Fetch organization info if user is in organization context try { const storedOrgId = this.getStoredOrganizationId() @@ -641,8 +639,6 @@ export class WebAuthService extends EventEmitter implements A if (userMembership) { this.setUserOrganizationInfo(userInfo, userMembership) - extensionBridgeEnabled = await this.isExtensionBridgeEnabledForOrganization(storedOrgId) - this.log("[auth] User in organization context:", { id: userMembership.organization.id, name: userMembership.organization.name, @@ -662,10 +658,6 @@ export class WebAuthService extends EventEmitter implements A if (primaryOrgMembership) { this.setUserOrganizationInfo(userInfo, primaryOrgMembership) - extensionBridgeEnabled = await this.isExtensionBridgeEnabledForOrganization( - primaryOrgMembership.organization.id, - ) - this.log("[auth] Legacy credentials: Found organization membership:", { id: primaryOrgMembership.organization.id, name: primaryOrgMembership.organization.name, @@ -680,9 +672,6 @@ export class WebAuthService extends EventEmitter implements A // Don't throw - organization info is optional } - // Set the extension bridge enabled flag - userInfo.extensionBridgeEnabled = extensionBridgeEnabled - return userInfo } @@ -729,36 +718,6 @@ export class WebAuthService extends EventEmitter implements A throw new Error(errorMessage) } - private async getOrganizationMetadata( - organizationId: string, - ): Promise<{ public_metadata?: Record } | null> { - try { - const response = await fetch(`${getClerkBaseUrl()}/v1/organizations/${organizationId}`, { - headers: { - Authorization: `Bearer ${this.credentials!.clientToken}`, - "User-Agent": this.userAgent(), - }, - signal: AbortSignal.timeout(10000), - }) - - if (!response.ok) { - this.log(`[auth] Failed to fetch organization metadata: ${response.status} ${response.statusText}`) - return null - } - - const data = await response.json() - return data.response || data - } catch (error) { - this.log("[auth] Error fetching organization metadata:", error) - return null - } - } - - private async isExtensionBridgeEnabledForOrganization(organizationId: string): Promise { - const orgMetadata = await this.getOrganizationMetadata(organizationId) - return orgMetadata?.public_metadata?.extension_bridge_enabled === true - } - private async clerkLogout(credentials: AuthCredentials): Promise { const formData = new URLSearchParams() formData.append("_is_native", "1") diff --git a/packages/cloud/src/__tests__/CloudSettingsService.parsing.test.ts b/packages/cloud/src/__tests__/CloudSettingsService.parsing.test.ts index 8d69303c38..b0486b971c 100644 --- a/packages/cloud/src/__tests__/CloudSettingsService.parsing.test.ts +++ b/packages/cloud/src/__tests__/CloudSettingsService.parsing.test.ts @@ -105,12 +105,8 @@ describe("CloudSettingsService - Response Parsing", () => { }, }, user: { - features: { - roomoteControlEnabled: true, - }, - settings: { - extensionBridgeEnabled: true, - }, + features: {}, + settings: {}, version: 1, }, } diff --git a/packages/cloud/src/__tests__/StaticTokenAuthService.spec.ts b/packages/cloud/src/__tests__/StaticTokenAuthService.spec.ts index a3756082ea..c37f2a7df9 100644 --- a/packages/cloud/src/__tests__/StaticTokenAuthService.spec.ts +++ b/packages/cloud/src/__tests__/StaticTokenAuthService.spec.ts @@ -89,7 +89,6 @@ describe("StaticTokenAuthService", () => { const userInfo = serviceWithJWT.getUserInfo() expect(userInfo?.id).toBe("user_2xmBhejNeDTwanM8CgIOnMgVxzC") expect(userInfo?.organizationId).toBe("org_123abc") - expect(userInfo?.extensionBridgeEnabled).toBe(true) }) it("should parse job token without orgId (null orgId case)", () => { @@ -98,7 +97,6 @@ describe("StaticTokenAuthService", () => { const userInfo = serviceWithJWT.getUserInfo() expect(userInfo?.id).toBe("user_2xmBhejNeDTwanM8CgIOnMgVxzC") expect(userInfo?.organizationId).toBeUndefined() - expect(userInfo?.extensionBridgeEnabled).toBe(true) }) it("should parse auth token and extract userId from r.u", () => { @@ -107,7 +105,6 @@ describe("StaticTokenAuthService", () => { const userInfo = serviceWithAuthToken.getUserInfo() expect(userInfo?.id).toBe("user_123") expect(userInfo?.organizationId).toBeUndefined() - expect(userInfo?.extensionBridgeEnabled).toBe(true) }) it("should handle legacy JWT format with sub field", () => { @@ -116,7 +113,6 @@ describe("StaticTokenAuthService", () => { const userInfo = serviceWithLegacyJWT.getUserInfo() expect(userInfo?.id).toBe("user_123") expect(userInfo?.organizationId).toBeUndefined() - expect(userInfo?.extensionBridgeEnabled).toBe(true) }) it("should handle invalid JWT gracefully", () => { @@ -125,7 +121,6 @@ describe("StaticTokenAuthService", () => { const userInfo = serviceWithInvalidJWT.getUserInfo() expect(userInfo?.id).toBeUndefined() expect(userInfo?.organizationId).toBeUndefined() - expect(userInfo?.extensionBridgeEnabled).toBe(true) expect(mockLog).toHaveBeenCalledWith("[auth] Failed to parse JWT:", expect.any(Error)) }) @@ -183,9 +178,7 @@ describe("StaticTokenAuthService", () => { authService.broadcast() expect(spy).toHaveBeenCalledWith({ - userInfo: expect.objectContaining({ - extensionBridgeEnabled: true, - }), + userInfo: expect.objectContaining({}), }) }) @@ -199,7 +192,6 @@ describe("StaticTokenAuthService", () => { expect(spy).toHaveBeenCalledWith({ userInfo: { - extensionBridgeEnabled: true, id: "user_2xmBhejNeDTwanM8CgIOnMgVxzC", organizationId: "org_123abc", }, @@ -220,10 +212,9 @@ describe("StaticTokenAuthService", () => { }) describe("getUserInfo", () => { - it("should return object with extensionBridgeEnabled flag", () => { + it("should return user info object", () => { const userInfo = authService.getUserInfo() - expect(userInfo).toHaveProperty("extensionBridgeEnabled") - expect(userInfo?.extensionBridgeEnabled).toBe(true) + expect(userInfo).toBeDefined() }) }) @@ -305,9 +296,7 @@ describe("StaticTokenAuthService", () => { }) expect(userInfoSpy).toHaveBeenCalledWith({ - userInfo: expect.objectContaining({ - extensionBridgeEnabled: true, - }), + userInfo: expect.objectContaining({}), }) }) }) diff --git a/packages/cloud/src/__tests__/WebAuthService.spec.ts b/packages/cloud/src/__tests__/WebAuthService.spec.ts index 3398e3f2a3..aa406e400d 100644 --- a/packages/cloud/src/__tests__/WebAuthService.spec.ts +++ b/packages/cloud/src/__tests__/WebAuthService.spec.ts @@ -636,7 +636,6 @@ describe("WebAuthService", () => { name: "John Doe", email: "john@example.com", picture: "https://example.com/avatar.jpg", - extensionBridgeEnabled: true, }, }) }) @@ -801,7 +800,6 @@ describe("WebAuthService", () => { name: "Jane Smith", email: "jane@example.com", picture: "https://example.com/jane.jpg", - extensionBridgeEnabled: true, }) }) @@ -869,7 +867,6 @@ describe("WebAuthService", () => { name: "Jane Smith", email: "jane@example.com", picture: "https://example.com/jane.jpg", - extensionBridgeEnabled: false, organizationId: "org_1", organizationName: "Org 1", organizationRole: "member", @@ -920,7 +917,6 @@ describe("WebAuthService", () => { name: "John Doe", email: undefined, picture: undefined, - extensionBridgeEnabled: true, }) }) }) @@ -1045,7 +1041,6 @@ describe("WebAuthService", () => { name: "Test User", email: undefined, picture: undefined, - extensionBridgeEnabled: true, }, }) }) diff --git a/packages/cloud/src/bridge/BaseChannel.ts b/packages/cloud/src/bridge/BaseChannel.ts deleted file mode 100644 index 1b2615b24c..0000000000 --- a/packages/cloud/src/bridge/BaseChannel.ts +++ /dev/null @@ -1,142 +0,0 @@ -import type { Socket } from "socket.io-client" -import * as vscode from "vscode" - -import type { StaticAppProperties, GitProperties } from "@roo-code/types" - -export interface BaseChannelOptions { - instanceId: string - appProperties: StaticAppProperties - gitProperties?: GitProperties - isCloudAgent: boolean -} - -/** - * Abstract base class for communication channels in the bridge system. - * Provides common functionality for bidirectional communication between - * the VSCode extension and web application. - * - * @template TCommand - Type of commands this channel can receive. - * @template TEvent - Type of events this channel can publish. - */ -export abstract class BaseChannel { - protected socket: Socket | null = null - protected readonly instanceId: string - protected readonly appProperties: StaticAppProperties - protected readonly gitProperties?: GitProperties - protected readonly isCloudAgent: boolean - - constructor(options: BaseChannelOptions) { - this.instanceId = options.instanceId - this.appProperties = options.appProperties - this.gitProperties = options.gitProperties - this.isCloudAgent = options.isCloudAgent - } - - /** - * Called when socket connects. - */ - public async onConnect(socket: Socket): Promise { - this.socket = socket - await this.handleConnect(socket) - } - - /** - * Called when socket disconnects. - */ - public onDisconnect(): void { - this.socket = null - this.handleDisconnect() - } - - /** - * Called when socket reconnects. - */ - public async onReconnect(socket: Socket): Promise { - this.socket = socket - await this.handleReconnect(socket) - } - - /** - * Cleanup resources. - */ - public async cleanup(socket: Socket | null): Promise { - if (socket) { - await this.handleCleanup(socket) - } - - this.socket = null - } - - /** - * Emit a socket event with error handling. - */ - protected publish( - eventName: TEventName, - data: TEventData, - callback?: (params: Params) => void, - ): boolean { - if (!this.socket) { - console.error(`[${this.constructor.name}#emit] socket not available for ${eventName}`) - return false - } - - try { - // console.log(`[${this.constructor.name}#emit] emit() -> ${eventName}`, data) - this.socket.emit(eventName, data, callback) - - return true - } catch (error) { - console.error( - `[${this.constructor.name}#emit] emit() failed -> ${eventName}: ${ - error instanceof Error ? error.message : String(error) - }`, - ) - - return false - } - } - - /** - * Handle incoming commands - template method that ensures common functionality - * is executed before subclass-specific logic. - * - * This method should be called by subclasses to handle commands. - * It will execute common functionality and then delegate to the abstract - * handleCommandImplementation method. - */ - public async handleCommand(command: TCommand): Promise { - // Common functionality: focus the sidebar. - await vscode.commands.executeCommand(`${this.appProperties.appName}.SidebarProvider.focus`) - - // Delegate to subclass-specific implementation. - await this.handleCommandImplementation(command) - } - - /** - * Handle command-specific logic - must be implemented by subclasses. - * This method is called after common functionality has been executed. - */ - protected abstract handleCommandImplementation(command: TCommand): Promise - - /** - * Handle connection-specific logic. - */ - protected abstract handleConnect(socket: Socket): Promise - - /** - * Handle disconnection-specific logic. - */ - protected handleDisconnect(): void { - // Default implementation - can be overridden. - } - - /** - * Handle reconnection-specific logic. - */ - protected abstract handleReconnect(socket: Socket): Promise - - /** - * Handle cleanup-specific logic. - */ - protected abstract handleCleanup(socket: Socket): Promise -} diff --git a/packages/cloud/src/bridge/BridgeOrchestrator.ts b/packages/cloud/src/bridge/BridgeOrchestrator.ts deleted file mode 100644 index 16ad0244f0..0000000000 --- a/packages/cloud/src/bridge/BridgeOrchestrator.ts +++ /dev/null @@ -1,355 +0,0 @@ -import crypto from "crypto" -import os from "os" - -import { - type TaskProviderLike, - type TaskLike, - type CloudUserInfo, - type ExtensionBridgeCommand, - type TaskBridgeCommand, - type StaticAppProperties, - type GitProperties, - ConnectionState, - ExtensionSocketEvents, - TaskSocketEvents, -} from "@roo-code/types" - -import { SocketTransport } from "./SocketTransport.js" -import { ExtensionChannel } from "./ExtensionChannel.js" -import { TaskChannel } from "./TaskChannel.js" - -export interface BridgeOrchestratorOptions { - userId: string - socketBridgeUrl: string - token: string - provider: TaskProviderLike - sessionId: string - isCloudAgent: boolean -} - -/** - * Central orchestrator for the extension bridge system. - * Coordinates communication between the VSCode extension and web application - * through WebSocket connections and manages extension/task channels. - */ -export class BridgeOrchestrator { - private static instance: BridgeOrchestrator | null = null - - private static pendingTask: TaskLike | null = null - - // Core - private readonly userId: string - private readonly socketBridgeUrl: string - private readonly token: string - private readonly provider: TaskProviderLike - private readonly instanceId: string - private readonly appProperties: StaticAppProperties - private readonly gitProperties?: GitProperties - private readonly isCloudAgent?: boolean - - // Components - private socketTransport: SocketTransport - private extensionChannel: ExtensionChannel - private taskChannel: TaskChannel - - // Reconnection - private readonly MAX_RECONNECT_ATTEMPTS = Infinity - private readonly RECONNECT_DELAY = 1_000 - private readonly RECONNECT_DELAY_MAX = 30_000 - - public static getInstance(): BridgeOrchestrator | null { - return BridgeOrchestrator.instance - } - - public static isEnabled(user: CloudUserInfo | null, remoteControlEnabled: boolean): boolean { - // Always disabled if signed out. - if (!user) { - return false - } - - // Disabled by the user's organization? - if (!user.extensionBridgeEnabled) { - return false - } - - // Disabled by the user? - if (!remoteControlEnabled) { - return false - } - - return true - } - - public static async connectOrDisconnect( - userInfo: CloudUserInfo, - remoteControlEnabled: boolean, - options: BridgeOrchestratorOptions, - ): Promise { - if (BridgeOrchestrator.isEnabled(userInfo, remoteControlEnabled)) { - await BridgeOrchestrator.connect(options) - } else { - await BridgeOrchestrator.disconnect() - } - } - - public static async connect(options: BridgeOrchestratorOptions) { - const instance = BridgeOrchestrator.instance - - if (!instance) { - try { - console.log(`[BridgeOrchestrator#connectOrDisconnect] Connecting...`) - - // Populate telemetry properties before registering the instance. - await options.provider.getTelemetryProperties() - - BridgeOrchestrator.instance = new BridgeOrchestrator(options) - await BridgeOrchestrator.instance.connect() - } catch (error) { - console.error( - `[BridgeOrchestrator#connectOrDisconnect] connect() failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - } else { - if ( - instance.connectionState === ConnectionState.FAILED || - instance.connectionState === ConnectionState.DISCONNECTED - ) { - console.log( - `[BridgeOrchestrator#connectOrDisconnect] Re-connecting... (state: ${instance.connectionState})`, - ) - - instance.reconnect().catch((error) => { - console.error( - `[BridgeOrchestrator#connectOrDisconnect] reconnect() failed: ${error instanceof Error ? error.message : String(error)}`, - ) - }) - } else { - console.log( - `[BridgeOrchestrator#connectOrDisconnect] Already connected or connecting (state: ${instance.connectionState})`, - ) - } - } - } - - public static async disconnect() { - const instance = BridgeOrchestrator.instance - - if (instance) { - try { - console.log( - `[BridgeOrchestrator#connectOrDisconnect] Disconnecting... (state: ${instance.connectionState})`, - ) - - await instance.disconnect() - } catch (error) { - console.error( - `[BridgeOrchestrator#connectOrDisconnect] disconnect() failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } finally { - BridgeOrchestrator.instance = null - } - } else { - console.log(`[BridgeOrchestrator#connectOrDisconnect] Already disconnected`) - } - } - - /** - * @TODO: What if subtasks also get spawned? We'd probably want deferred - * subscriptions for those too. - */ - public static async subscribeToTask(task: TaskLike): Promise { - const instance = BridgeOrchestrator.instance - - if (instance && instance.socketTransport.isConnected()) { - console.log(`[BridgeOrchestrator#subscribeToTask] Subscribing to task ${task.taskId}`) - await instance.subscribeToTask(task) - } else { - console.log(`[BridgeOrchestrator#subscribeToTask] Deferring subscription for task ${task.taskId}`) - BridgeOrchestrator.pendingTask = task - } - } - - private constructor(options: BridgeOrchestratorOptions) { - this.userId = options.userId - this.socketBridgeUrl = options.socketBridgeUrl - this.token = options.token - this.provider = options.provider - this.instanceId = options.sessionId || crypto.randomUUID() - this.appProperties = { ...options.provider.appProperties, hostname: os.hostname() } - this.gitProperties = options.provider.gitProperties - this.isCloudAgent = options.isCloudAgent - - this.socketTransport = new SocketTransport({ - url: this.socketBridgeUrl, - socketOptions: { - query: { - token: this.token, - clientType: "extension", - instanceId: this.instanceId, - }, - transports: ["websocket", "polling"], - reconnection: true, - reconnectionAttempts: this.MAX_RECONNECT_ATTEMPTS, - reconnectionDelay: this.RECONNECT_DELAY, - reconnectionDelayMax: this.RECONNECT_DELAY_MAX, - }, - onConnect: () => this.handleConnect(), - onDisconnect: () => this.handleDisconnect(), - onReconnect: () => this.handleReconnect(), - }) - - this.extensionChannel = new ExtensionChannel({ - instanceId: this.instanceId, - appProperties: this.appProperties, - gitProperties: this.gitProperties, - userId: this.userId, - provider: this.provider, - isCloudAgent: this.isCloudAgent, - }) - - this.taskChannel = new TaskChannel({ - instanceId: this.instanceId, - appProperties: this.appProperties, - gitProperties: this.gitProperties, - isCloudAgent: this.isCloudAgent, - }) - } - - private setupSocketListeners() { - const socket = this.socketTransport.getSocket() - - if (!socket) { - console.error("[BridgeOrchestrator] Socket not available") - return - } - - // Remove any existing listeners first to prevent duplicates. - socket.off(ExtensionSocketEvents.RELAYED_COMMAND) - socket.off(TaskSocketEvents.RELAYED_COMMAND) - socket.off("connected") - - socket.on(ExtensionSocketEvents.RELAYED_COMMAND, (message: ExtensionBridgeCommand) => { - console.log( - `[BridgeOrchestrator] on(${ExtensionSocketEvents.RELAYED_COMMAND}) -> ${message.type} for ${message.instanceId}`, - ) - - this.extensionChannel?.handleCommand(message) - }) - - socket.on(TaskSocketEvents.RELAYED_COMMAND, (message: TaskBridgeCommand) => { - console.log( - `[BridgeOrchestrator] on(${TaskSocketEvents.RELAYED_COMMAND}) -> ${message.type} for ${message.taskId}`, - ) - - this.taskChannel.handleCommand(message) - }) - } - - private async handleConnect() { - const socket = this.socketTransport.getSocket() - - if (!socket) { - console.error("[BridgeOrchestrator#handleConnect] Socket not available") - return - } - - await this.extensionChannel.onConnect(socket) - await this.taskChannel.onConnect(socket) - - if (BridgeOrchestrator.pendingTask) { - console.log( - `[BridgeOrchestrator#handleConnect] Subscribing to task ${BridgeOrchestrator.pendingTask.taskId}`, - ) - - try { - await this.subscribeToTask(BridgeOrchestrator.pendingTask) - BridgeOrchestrator.pendingTask = null - } catch (error) { - console.error( - `[BridgeOrchestrator#handleConnect] subscribeToTask() failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - } - } - - private handleDisconnect() { - this.extensionChannel.onDisconnect() - this.taskChannel.onDisconnect() - } - - private async handleReconnect() { - const socket = this.socketTransport.getSocket() - - if (!socket) { - console.error("[BridgeOrchestrator] Socket not available after reconnect") - return - } - - // Re-setup socket listeners to ensure they're properly configured - // after automatic reconnection (Socket.IO's built-in reconnection) - // The socket.off() calls in setupSocketListeners prevent duplicates - this.setupSocketListeners() - - await this.extensionChannel.onReconnect(socket) - await this.taskChannel.onReconnect(socket) - } - - // Task API - - public async subscribeToTask(task: TaskLike): Promise { - const socket = this.socketTransport.getSocket() - - if (!socket || !this.socketTransport.isConnected()) { - console.warn("[BridgeOrchestrator] Cannot subscribe to task: not connected. Will retry when connected.") - this.taskChannel.addPendingTask(task) - - if ( - this.connectionState === ConnectionState.DISCONNECTED || - this.connectionState === ConnectionState.FAILED - ) { - await this.connect() - } - - return - } - - await this.taskChannel.subscribeToTask(task, socket) - } - - public async unsubscribeFromTask(taskId: string): Promise { - const socket = this.socketTransport.getSocket() - - if (!socket) { - return - } - - await this.taskChannel.unsubscribeFromTask(taskId, socket) - } - - // Shared API - - public get connectionState(): ConnectionState { - return this.socketTransport.getConnectionState() - } - - private async connect(): Promise { - await this.socketTransport.connect() - this.setupSocketListeners() - } - - public async disconnect(): Promise { - await this.extensionChannel.cleanup(this.socketTransport.getSocket()) - await this.taskChannel.cleanup(this.socketTransport.getSocket()) - await this.socketTransport.disconnect() - BridgeOrchestrator.instance = null - BridgeOrchestrator.pendingTask = null - } - - public async reconnect(): Promise { - await this.socketTransport.reconnect() - - // After a manual reconnect, we have a new socket instance - // so we need to set up listeners again. - this.setupSocketListeners() - } -} diff --git a/packages/cloud/src/bridge/ExtensionChannel.ts b/packages/cloud/src/bridge/ExtensionChannel.ts deleted file mode 100644 index 26fce96228..0000000000 --- a/packages/cloud/src/bridge/ExtensionChannel.ts +++ /dev/null @@ -1,282 +0,0 @@ -import type { Socket } from "socket.io-client" - -import { - type TaskProviderLike, - type TaskProviderEvents, - type ExtensionInstance, - type ExtensionBridgeCommand, - type ExtensionBridgeEvent, - RooCodeEventName, - TaskStatus, - ExtensionBridgeCommandName, - ExtensionBridgeEventName, - ExtensionSocketEvents, - HEARTBEAT_INTERVAL_MS, -} from "@roo-code/types" - -import { type BaseChannelOptions, BaseChannel } from "./BaseChannel.js" - -interface ExtensionChannelOptions extends BaseChannelOptions { - userId: string - provider: TaskProviderLike -} - -/** - * Manages the extension-level communication channel. - * Handles extension registration, heartbeat, and extension-specific commands. - */ -export class ExtensionChannel extends BaseChannel< - ExtensionBridgeCommand, - ExtensionSocketEvents, - ExtensionBridgeEvent | ExtensionInstance -> { - private userId: string - private provider: TaskProviderLike - private extensionInstance: ExtensionInstance - private heartbeatInterval: NodeJS.Timeout | null = null - private eventListeners: Map void> = new Map() - - constructor(options: ExtensionChannelOptions) { - super({ - instanceId: options.instanceId, - appProperties: options.appProperties, - gitProperties: options.gitProperties, - isCloudAgent: options.isCloudAgent, - }) - - this.userId = options.userId - this.provider = options.provider - - this.extensionInstance = { - instanceId: this.instanceId, - userId: this.userId, - workspacePath: this.provider.cwd, - appProperties: this.appProperties, - gitProperties: this.gitProperties, - lastHeartbeat: Date.now(), - task: { taskId: "", taskStatus: TaskStatus.None }, - taskHistory: [], - isCloudAgent: this.isCloudAgent, - } - - this.setupListeners() - } - - protected async handleCommandImplementation(command: ExtensionBridgeCommand): Promise { - if (command.instanceId !== this.instanceId) { - console.log(`[ExtensionChannel] command -> instance id mismatch | ${this.instanceId}`, { - messageInstanceId: command.instanceId, - }) - - return - } - - switch (command.type) { - case ExtensionBridgeCommandName.StartTask: { - console.log(`[ExtensionChannel] command -> createTask() | ${command.instanceId}`, { - text: command.payload.text?.substring(0, 100) + "...", - hasImages: !!command.payload.images, - mode: command.payload.mode, - providerProfile: command.payload.providerProfile, - }) - - this.provider.createTask( - command.payload.text, - command.payload.images, - undefined, // parentTask - undefined, // options - { mode: command.payload.mode, currentApiConfigName: command.payload.providerProfile }, - ) - - break - } - case ExtensionBridgeCommandName.StopTask: { - const instance = await this.updateInstance() - - if (instance.task.taskStatus === TaskStatus.Running) { - console.log(`[ExtensionChannel] command -> cancelTask() | ${command.instanceId}`) - this.provider.cancelTask() - this.provider.postStateToWebview() - } else if (instance.task.taskId) { - console.log(`[ExtensionChannel] command -> clearTask() | ${command.instanceId}`) - this.provider.clearTask() - this.provider.postStateToWebview() - } - - break - } - case ExtensionBridgeCommandName.ResumeTask: { - console.log(`[ExtensionChannel] command -> resumeTask() | ${command.instanceId}`, { - taskId: command.payload.taskId, - }) - - this.provider.resumeTask(command.payload.taskId) - this.provider.postStateToWebview() - break - } - } - } - - protected async handleConnect(socket: Socket): Promise { - await this.registerInstance(socket) - this.startHeartbeat(socket) - } - - protected async handleReconnect(socket: Socket): Promise { - await this.registerInstance(socket) - this.startHeartbeat(socket) - } - - protected override handleDisconnect(): void { - this.stopHeartbeat() - } - - protected async handleCleanup(socket: Socket): Promise { - this.stopHeartbeat() - this.cleanupListeners() - await this.unregisterInstance(socket) - } - - private async registerInstance(_socket: Socket): Promise { - const instance = await this.updateInstance() - await this.publish(ExtensionSocketEvents.REGISTER, instance) - } - - private async unregisterInstance(_socket: Socket): Promise { - const instance = await this.updateInstance() - await this.publish(ExtensionSocketEvents.UNREGISTER, instance) - } - - private startHeartbeat(socket: Socket): void { - this.stopHeartbeat() - - this.heartbeatInterval = setInterval(async () => { - const instance = await this.updateInstance() - - try { - socket.emit(ExtensionSocketEvents.HEARTBEAT, instance) - // Heartbeat is too frequent to log - } catch (error) { - console.error( - `[ExtensionChannel] emit() failed -> ${ExtensionSocketEvents.HEARTBEAT}: ${ - error instanceof Error ? error.message : String(error) - }`, - ) - } - }, HEARTBEAT_INTERVAL_MS) - } - - private stopHeartbeat(): void { - if (this.heartbeatInterval) { - clearInterval(this.heartbeatInterval) - this.heartbeatInterval = null - } - } - - private setupListeners(): void { - const eventMapping = [ - { from: RooCodeEventName.TaskCreated, to: ExtensionBridgeEventName.TaskCreated }, - { from: RooCodeEventName.TaskStarted, to: ExtensionBridgeEventName.TaskStarted }, - { from: RooCodeEventName.TaskCompleted, to: ExtensionBridgeEventName.TaskCompleted }, - { from: RooCodeEventName.TaskAborted, to: ExtensionBridgeEventName.TaskAborted }, - { from: RooCodeEventName.TaskFocused, to: ExtensionBridgeEventName.TaskFocused }, - { from: RooCodeEventName.TaskUnfocused, to: ExtensionBridgeEventName.TaskUnfocused }, - { from: RooCodeEventName.TaskActive, to: ExtensionBridgeEventName.TaskActive }, - { from: RooCodeEventName.TaskInteractive, to: ExtensionBridgeEventName.TaskInteractive }, - { from: RooCodeEventName.TaskResumable, to: ExtensionBridgeEventName.TaskResumable }, - { from: RooCodeEventName.TaskIdle, to: ExtensionBridgeEventName.TaskIdle }, - { from: RooCodeEventName.TaskPaused, to: ExtensionBridgeEventName.TaskPaused }, - { from: RooCodeEventName.TaskUnpaused, to: ExtensionBridgeEventName.TaskUnpaused }, - { from: RooCodeEventName.TaskSpawned, to: ExtensionBridgeEventName.TaskSpawned }, - { from: RooCodeEventName.TaskDelegated, to: ExtensionBridgeEventName.TaskDelegated }, - { from: RooCodeEventName.TaskDelegationCompleted, to: ExtensionBridgeEventName.TaskDelegationCompleted }, - { from: RooCodeEventName.TaskDelegationResumed, to: ExtensionBridgeEventName.TaskDelegationResumed }, - { from: RooCodeEventName.TaskUserMessage, to: ExtensionBridgeEventName.TaskUserMessage }, - { from: RooCodeEventName.TaskTokenUsageUpdated, to: ExtensionBridgeEventName.TaskTokenUsageUpdated }, - ] as const - - eventMapping.forEach(({ from, to }) => { - // Create and store the listener function for cleanup. - const listener = async (...args: unknown[]) => { - const baseEvent: { - type: ExtensionBridgeEventName - instance: ExtensionInstance - timestamp: number - } = { - type: to, - instance: await this.updateInstance(), - timestamp: Date.now(), - } - - let eventToPublish: ExtensionBridgeEvent - - // Add payload for delegation events while avoiding `any` - if (to === ExtensionBridgeEventName.TaskDelegationCompleted) { - const [parentTaskId, childTaskId, summary] = args as [string, string, string] - eventToPublish = { - ...(baseEvent as unknown as ExtensionBridgeEvent), - payload: { parentTaskId, childTaskId, summary }, - } as unknown as ExtensionBridgeEvent - } else if (to === ExtensionBridgeEventName.TaskDelegationResumed) { - const [parentTaskId, childTaskId] = args as [string, string] - eventToPublish = { - ...(baseEvent as unknown as ExtensionBridgeEvent), - payload: { parentTaskId, childTaskId }, - } as unknown as ExtensionBridgeEvent - } else { - eventToPublish = baseEvent as unknown as ExtensionBridgeEvent - } - - this.publish(ExtensionSocketEvents.EVENT, eventToPublish) - } - - this.eventListeners.set(from, listener) - this.provider.on(from, listener) - }) - } - - private cleanupListeners(): void { - this.eventListeners.forEach((listener, eventName) => { - // Cast is safe because we only store valid event names from eventMapping. - this.provider.off(eventName as keyof TaskProviderEvents, listener) - }) - - this.eventListeners.clear() - } - - private async updateInstance(): Promise { - const task = this.provider?.getCurrentTask() - const taskHistory = this.provider?.getRecentTasks() ?? [] - - const mode = await this.provider?.getMode() - const modes = (await this.provider?.getModes()) ?? [] - - const providerProfile = await this.provider?.getProviderProfile() - const providerProfiles = (await this.provider?.getProviderProfiles()) ?? [] - - this.extensionInstance = { - ...this.extensionInstance, - lastHeartbeat: Date.now(), - task: task - ? { - taskId: task.taskId, - parentTaskId: task.parentTaskId, - childTaskId: task.childTaskId, - taskStatus: task.taskStatus, - taskAsk: task?.taskAsk, - queuedMessages: task.queuedMessages, - tokenUsage: task.tokenUsage, - ...task.metadata, - } - : { taskId: "", taskStatus: TaskStatus.None }, - taskAsk: task?.taskAsk, - taskHistory, - mode, - providerProfile, - modes, - providerProfiles, - } - - return this.extensionInstance - } -} diff --git a/packages/cloud/src/bridge/SocketTransport.ts b/packages/cloud/src/bridge/SocketTransport.ts deleted file mode 100644 index 2df3cf95eb..0000000000 --- a/packages/cloud/src/bridge/SocketTransport.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { io, type Socket, type SocketOptions, type ManagerOptions } from "socket.io-client" - -import { ConnectionState, type RetryConfig } from "@roo-code/types" - -export interface SocketTransportOptions { - url: string - socketOptions: Partial - onConnect?: () => void | Promise - onDisconnect?: (reason: string) => void - onReconnect?: () => void | Promise - logger?: { - log: (message: string, ...args: unknown[]) => void - error: (message: string, ...args: unknown[]) => void - warn: (message: string, ...args: unknown[]) => void - } -} - -/** - * Manages the WebSocket transport layer for the bridge system. - * Handles connection lifecycle, retries, and reconnection logic. - */ -export class SocketTransport { - private socket: Socket | null = null - private connectionState: ConnectionState = ConnectionState.DISCONNECTED - private retryTimeout: NodeJS.Timeout | null = null - private isPreviouslyConnected: boolean = false - - private readonly retryConfig: RetryConfig = { - maxInitialAttempts: Infinity, - initialDelay: 1_000, - maxDelay: 15_000, - backoffMultiplier: 2, - } - - private readonly CONNECTION_TIMEOUT = 2_000 - private readonly options: SocketTransportOptions - - constructor(options: SocketTransportOptions, retryConfig?: Partial) { - this.options = options - - if (retryConfig) { - this.retryConfig = { ...this.retryConfig, ...retryConfig } - } - } - - // This is the initial connnect attempt. We need to implement our own - // infinite retry mechanism since Socket.io's automatic reconnection only - // kicks in after a successful initial connection. - public async connect(): Promise { - if (this.connectionState === ConnectionState.CONNECTED) { - console.log(`[SocketTransport#connect] Already connected`) - return - } - - if (this.connectionState === ConnectionState.CONNECTING || this.connectionState === ConnectionState.RETRYING) { - console.log(`[SocketTransport#connect] Already in progress`) - return - } - - let attempt = 0 - let delay = this.retryConfig.initialDelay - - while (attempt < this.retryConfig.maxInitialAttempts) { - console.log(`[SocketTransport#connect] attempt = ${attempt + 1}, delay = ${delay}ms`) - this.connectionState = attempt === 0 ? ConnectionState.CONNECTING : ConnectionState.RETRYING - - try { - await this._connect() - break - } catch (_error) { - attempt++ - - if (this.socket) { - this.socket.disconnect() - this.socket = null - } - - const promise = new Promise((resolve) => { - this.retryTimeout = setTimeout(resolve, delay) - }) - - await promise - - delay = Math.min(delay * this.retryConfig.backoffMultiplier, this.retryConfig.maxDelay) - } - } - - if (this.retryTimeout) { - clearTimeout(this.retryTimeout) - this.retryTimeout = null - } - - if (this.socket?.connected) { - console.log(`[SocketTransport#connect] connected - ${this.options.url}`) - } else { - // Since we have infinite retries this should never happen. - this.connectionState = ConnectionState.FAILED - console.error(`[SocketTransport#connect] Giving up`) - } - } - - private async _connect(): Promise { - return new Promise((resolve, reject) => { - this.socket = io(this.options.url, this.options.socketOptions) - - let connectionTimeout: NodeJS.Timeout | null = setTimeout(() => { - console.error(`[SocketTransport#_connect] failed to connect after ${this.CONNECTION_TIMEOUT}ms`) - - if (this.connectionState !== ConnectionState.CONNECTED) { - this.socket?.disconnect() - reject(new Error("Connection timeout")) - } - }, this.CONNECTION_TIMEOUT) - - // https://socket.io/docs/v4/client-api/#event-connect - this.socket.on("connect", async () => { - console.log( - `[SocketTransport#_connect] on(connect): isPreviouslyConnected = ${this.isPreviouslyConnected}`, - ) - - if (connectionTimeout) { - clearTimeout(connectionTimeout) - connectionTimeout = null - } - - this.connectionState = ConnectionState.CONNECTED - - if (this.isPreviouslyConnected) { - if (this.options.onReconnect) { - await this.options.onReconnect() - } - } else { - if (this.options.onConnect) { - await this.options.onConnect() - } - } - - this.isPreviouslyConnected = true - resolve() - }) - - // https://socket.io/docs/v4/client-api/#event-connect_error - this.socket.on("connect_error", (error) => { - if (connectionTimeout && this.connectionState !== ConnectionState.CONNECTED) { - console.error(`[SocketTransport] on(connect_error): ${error.message}`) - clearTimeout(connectionTimeout) - connectionTimeout = null - reject(error) - } - }) - - // https://socket.io/docs/v4/client-api/#event-disconnect - this.socket.on("disconnect", (reason, details) => { - console.log( - `[SocketTransport#_connect] on(disconnect) (reason: ${reason}, details: ${JSON.stringify(details)})`, - ) - this.connectionState = ConnectionState.DISCONNECTED - - if (this.options.onDisconnect) { - this.options.onDisconnect(reason) - } - - // Don't attempt to reconnect if we're manually disconnecting. - const isManualDisconnect = reason === "io client disconnect" - - if (!isManualDisconnect && this.isPreviouslyConnected) { - // After successful initial connection, rely entirely on - // Socket.IO's reconnection logic. - console.log("[SocketTransport#_connect] will attempt to reconnect") - } else { - console.log("[SocketTransport#_connect] will *NOT* attempt to reconnect") - } - }) - - // https://socket.io/docs/v4/client-api/#event-error - // Fired upon a connection error. - this.socket.io.on("error", (error) => { - // Connection error. - if (connectionTimeout && this.connectionState !== ConnectionState.CONNECTED) { - console.error(`[SocketTransport#_connect] on(error): ${error.message}`) - clearTimeout(connectionTimeout) - connectionTimeout = null - reject(error) - } - - // Post-connection error. - if (this.connectionState === ConnectionState.CONNECTED) { - console.error(`[SocketTransport#_connect] on(error): ${error.message}`) - } - }) - - // https://socket.io/docs/v4/client-api/#event-reconnect - // Fired upon a successful reconnection. - this.socket.io.on("reconnect", (attempt) => { - console.log(`[SocketTransport#_connect] on(reconnect) - ${attempt}`) - this.connectionState = ConnectionState.CONNECTED - - if (this.options.onReconnect) { - this.options.onReconnect() - } - }) - - // https://socket.io/docs/v4/client-api/#event-reconnect_attempt - // Fired upon an attempt to reconnect. - this.socket.io.on("reconnect_attempt", (attempt) => { - console.log(`[SocketTransport#_connect] on(reconnect_attempt) - ${attempt}`) - }) - - // https://socket.io/docs/v4/client-api/#event-reconnect_error - // Fired upon a reconnection attempt error. - this.socket.io.on("reconnect_error", (error) => { - console.error(`[SocketTransport#_connect] on(reconnect_error): ${error.message}`) - }) - - // https://socket.io/docs/v4/client-api/#event-reconnect_failed - // Fired when couldn't reconnect within `reconnectionAttempts`. - // Since we use infinite retries, this should never fire. - this.socket.io.on("reconnect_failed", () => { - console.error(`[SocketTransport#_connect] on(reconnect_failed) - giving up`) - this.connectionState = ConnectionState.FAILED - }) - - // This is a custom event fired by the server. - this.socket.on("auth_error", (error) => { - console.error( - `[SocketTransport#_connect] on(auth_error): ${error instanceof Error ? error.message : String(error)}`, - ) - - if (connectionTimeout && this.connectionState !== ConnectionState.CONNECTED) { - clearTimeout(connectionTimeout) - connectionTimeout = null - reject(new Error(error.message || "Authentication failed")) - } - }) - }) - } - - public async disconnect(): Promise { - console.log(`[SocketTransport#disconnect] Disconnecting...`) - - if (this.retryTimeout) { - clearTimeout(this.retryTimeout) - this.retryTimeout = null - } - - if (this.socket) { - this.socket.removeAllListeners() - this.socket.io.removeAllListeners() - this.socket.disconnect() - this.socket = null - } - - this.connectionState = ConnectionState.DISCONNECTED - console.log(`[SocketTransport#disconnect] Disconnected`) - } - - public getSocket(): Socket | null { - return this.socket - } - - public getConnectionState(): ConnectionState { - return this.connectionState - } - - public isConnected(): boolean { - return this.connectionState === ConnectionState.CONNECTED && this.socket?.connected === true - } - - public async reconnect(): Promise { - console.log(`[SocketTransport#reconnect] Manually reconnecting...`) - - if (this.connectionState === ConnectionState.CONNECTED) { - console.log(`[SocketTransport#reconnect] Already connected`) - return - } - - this.isPreviouslyConnected = false - await this.disconnect() - await this.connect() - } -} diff --git a/packages/cloud/src/bridge/TaskChannel.ts b/packages/cloud/src/bridge/TaskChannel.ts deleted file mode 100644 index 433e740d4e..0000000000 --- a/packages/cloud/src/bridge/TaskChannel.ts +++ /dev/null @@ -1,241 +0,0 @@ -import type { Socket } from "socket.io-client" - -import { - type ClineMessage, - type TaskEvents, - type TaskLike, - type TaskBridgeCommand, - type TaskBridgeEvent, - type JoinResponse, - type LeaveResponse, - RooCodeEventName, - TaskBridgeEventName, - TaskBridgeCommandName, - TaskSocketEvents, -} from "@roo-code/types" - -import { type BaseChannelOptions, BaseChannel } from "./BaseChannel.js" - -type TaskEventListener = { - [K in keyof TaskEvents]: (...args: TaskEvents[K]) => void | Promise -}[keyof TaskEvents] - -type TaskEventMapping = { - from: keyof TaskEvents - to: TaskBridgeEventName - createPayload: (task: TaskLike, ...args: any[]) => any // eslint-disable-line @typescript-eslint/no-explicit-any -} - -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface TaskChannelOptions extends BaseChannelOptions {} - -/** - * Manages task-level communication channels. - * Handles task subscriptions, messaging, and task-specific commands. - */ -export class TaskChannel extends BaseChannel< - TaskBridgeCommand, - TaskSocketEvents, - TaskBridgeEvent | { taskId: string } -> { - private subscribedTasks: Map = new Map() - private pendingTasks: Map = new Map() - private taskListeners: Map> = new Map() - - private readonly eventMapping: readonly TaskEventMapping[] = [ - { - from: RooCodeEventName.Message, - to: TaskBridgeEventName.Message, - createPayload: (task: TaskLike, data: { action: string; message: ClineMessage }) => ({ - type: TaskBridgeEventName.Message, - taskId: task.taskId, - action: data.action, - message: data.message, - }), - }, - { - from: RooCodeEventName.TaskModeSwitched, - to: TaskBridgeEventName.TaskModeSwitched, - createPayload: (task: TaskLike, mode: string) => ({ - type: TaskBridgeEventName.TaskModeSwitched, - taskId: task.taskId, - mode, - }), - }, - { - from: RooCodeEventName.TaskInteractive, - to: TaskBridgeEventName.TaskInteractive, - createPayload: (task: TaskLike, _taskId: string) => ({ - type: TaskBridgeEventName.TaskInteractive, - taskId: task.taskId, - }), - }, - ] as const - - constructor(options: TaskChannelOptions) { - super(options) - } - - protected async handleCommandImplementation(command: TaskBridgeCommand): Promise { - const task = this.subscribedTasks.get(command.taskId) - - if (!task) { - console.error(`[TaskChannel] Unable to find task ${command.taskId}`) - return - } - - switch (command.type) { - case TaskBridgeCommandName.Message: - console.log( - `[TaskChannel] ${TaskBridgeCommandName.Message} ${command.taskId} -> submitUserMessage()`, - command, - ) - - await task.submitUserMessage( - command.payload.text, - command.payload.images, - command.payload.mode, - command.payload.providerProfile, - ) - - break - - case TaskBridgeCommandName.ApproveAsk: - console.log( - `[TaskChannel] ${TaskBridgeCommandName.ApproveAsk} ${command.taskId} -> approveAsk()`, - command, - ) - - task.approveAsk(command.payload) - break - - case TaskBridgeCommandName.DenyAsk: - console.log(`[TaskChannel] ${TaskBridgeCommandName.DenyAsk} ${command.taskId} -> denyAsk()`, command) - task.denyAsk(command.payload) - break - } - } - - protected async handleConnect(socket: Socket): Promise { - // Rejoin all subscribed tasks. - for (const taskId of this.subscribedTasks.keys()) { - await this.publish(TaskSocketEvents.JOIN, { taskId }) - } - - // Subscribe to any pending tasks. - for (const task of this.pendingTasks.values()) { - await this.subscribeToTask(task, socket) - } - - this.pendingTasks.clear() - } - - protected async handleReconnect(_socket: Socket): Promise { - // Rejoin all subscribed tasks. - for (const taskId of this.subscribedTasks.keys()) { - await this.publish(TaskSocketEvents.JOIN, { taskId }) - } - } - - protected async handleCleanup(socket: Socket): Promise { - const unsubscribePromises = [] - - for (const taskId of this.subscribedTasks.keys()) { - unsubscribePromises.push(this.unsubscribeFromTask(taskId, socket)) - } - - await Promise.allSettled(unsubscribePromises) - this.subscribedTasks.clear() - this.taskListeners.clear() - this.pendingTasks.clear() - } - - /** - * Add a task to the pending queue (will be subscribed when connected). - */ - public addPendingTask(task: TaskLike): void { - this.pendingTasks.set(task.taskId, task) - } - - public async subscribeToTask(task: TaskLike, _socket: Socket): Promise { - const taskId = task.taskId - - await this.publish(TaskSocketEvents.JOIN, { taskId }, (response: JoinResponse) => { - if (response.success) { - console.log(`[TaskChannel#subscribeToTask] subscribed to ${taskId}`) - this.subscribedTasks.set(taskId, task) - this.setupTaskListeners(task) - } else { - console.error(`[TaskChannel#subscribeToTask] failed to subscribe to ${taskId}: ${response.error}`) - } - }) - } - - public async unsubscribeFromTask(taskId: string, _socket: Socket): Promise { - const task = this.subscribedTasks.get(taskId) - - if (!task) { - return - } - - await this.publish(TaskSocketEvents.LEAVE, { taskId }, (response: LeaveResponse) => { - if (response.success) { - console.log(`[TaskChannel#unsubscribeFromTask] unsubscribed from ${taskId}`) - } else { - console.error(`[TaskChannel#unsubscribeFromTask] failed to unsubscribe from ${taskId}`) - } - - // If we failed to unsubscribe then something is probably wrong and - // we should still discard this task from `subscribedTasks`. - this.removeTaskListeners(task) - this.subscribedTasks.delete(taskId) - }) - } - - private setupTaskListeners(task: TaskLike): void { - if (this.taskListeners.has(task.taskId)) { - console.warn(`[TaskChannel] Listeners already exist for task, removing old listeners for ${task.taskId}`) - this.removeTaskListeners(task) - } - - const listeners = new Map() - - this.eventMapping.forEach(({ from, to, createPayload }) => { - const listener = (...args: unknown[]) => { - const payload = createPayload(task, ...args) - this.publish(TaskSocketEvents.EVENT, payload) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - task.on(from, listener as any) - listeners.set(to, listener) - }) - - this.taskListeners.set(task.taskId, listeners) - } - - private removeTaskListeners(task: TaskLike): void { - const listeners = this.taskListeners.get(task.taskId) - - if (!listeners) { - return - } - - this.eventMapping.forEach(({ from, to }) => { - const listener = listeners.get(to) - if (listener) { - try { - task.off(from, listener as any) // eslint-disable-line @typescript-eslint/no-explicit-any - } catch (error) { - console.error( - `[TaskChannel] task.off(${from}) failed for task ${task.taskId}: ${ - error instanceof Error ? error.message : String(error) - }`, - ) - } - } - }) - - this.taskListeners.delete(task.taskId) - } -} diff --git a/packages/cloud/src/bridge/__tests__/ExtensionChannel.test.ts b/packages/cloud/src/bridge/__tests__/ExtensionChannel.test.ts deleted file mode 100644 index 188e2cc029..0000000000 --- a/packages/cloud/src/bridge/__tests__/ExtensionChannel.test.ts +++ /dev/null @@ -1,402 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import type { Socket } from "socket.io-client" - -import { - type TaskProviderLike, - type TaskProviderEvents, - type StaticAppProperties, - RooCodeEventName, - ExtensionBridgeEventName, - ExtensionSocketEvents, -} from "@roo-code/types" - -import { ExtensionChannel } from "../ExtensionChannel.js" - -describe("ExtensionChannel", () => { - let mockSocket: Socket - let mockProvider: TaskProviderLike - let extensionChannel: ExtensionChannel - const instanceId = "test-instance-123" - const userId = "test-user-456" - - const appProperties: StaticAppProperties = { - appName: "roo-code", - appVersion: "1.0.0", - vscodeVersion: "1.0.0", - platform: "darwin", - editorName: "Roo Code", - hostname: "test-host", - } - - // Track registered event listeners - const eventListeners = new Map unknown>>() - - beforeEach(() => { - // Reset the event listeners tracker - eventListeners.clear() - - // Create mock socket - mockSocket = { - emit: vi.fn(), - on: vi.fn(), - off: vi.fn(), - disconnect: vi.fn(), - } as unknown as Socket - - // Create mock provider with event listener tracking - mockProvider = { - cwd: "/test/workspace", - appProperties: { - version: "1.0.0", - extensionVersion: "1.0.0", - }, - gitProperties: undefined, - getCurrentTask: vi.fn().mockReturnValue(undefined), - getCurrentTaskStack: vi.fn().mockReturnValue([]), - getRecentTasks: vi.fn().mockReturnValue([]), - createTask: vi.fn(), - cancelTask: vi.fn(), - clearTask: vi.fn(), - resumeTask: vi.fn(), - getState: vi.fn(), - postStateToWebview: vi.fn(), - postMessageToWebview: vi.fn(), - getTelemetryProperties: vi.fn(), - getMode: vi.fn().mockResolvedValue("code"), - getModes: vi.fn().mockResolvedValue([ - { slug: "code", name: "Code", description: "Code mode" }, - { slug: "architect", name: "Architect", description: "Architect mode" }, - ]), - getProviderProfile: vi.fn().mockResolvedValue("default"), - getProviderProfiles: vi.fn().mockResolvedValue([{ name: "default", description: "Default profile" }]), - on: vi.fn((event: keyof TaskProviderEvents, listener: (...args: unknown[]) => unknown) => { - if (!eventListeners.has(event)) { - eventListeners.set(event, new Set()) - } - eventListeners.get(event)!.add(listener) - return mockProvider - }), - off: vi.fn((event: keyof TaskProviderEvents, listener: (...args: unknown[]) => unknown) => { - const listeners = eventListeners.get(event) - if (listeners) { - listeners.delete(listener) - if (listeners.size === 0) { - eventListeners.delete(event) - } - } - return mockProvider - }), - } as unknown as TaskProviderLike - - // Create extension channel instance - extensionChannel = new ExtensionChannel({ - instanceId, - appProperties, - userId, - provider: mockProvider, - isCloudAgent: false, - }) - }) - - afterEach(() => { - vi.clearAllMocks() - }) - - describe("Event Listener Management", () => { - it("should register event listeners on initialization", () => { - // Verify that listeners were registered for all expected events - const expectedEvents: RooCodeEventName[] = [ - RooCodeEventName.TaskCreated, - RooCodeEventName.TaskStarted, - RooCodeEventName.TaskCompleted, - RooCodeEventName.TaskAborted, - RooCodeEventName.TaskFocused, - RooCodeEventName.TaskUnfocused, - RooCodeEventName.TaskActive, - RooCodeEventName.TaskInteractive, - RooCodeEventName.TaskResumable, - RooCodeEventName.TaskIdle, - RooCodeEventName.TaskPaused, - RooCodeEventName.TaskUnpaused, - RooCodeEventName.TaskSpawned, - RooCodeEventName.TaskDelegated, - RooCodeEventName.TaskDelegationCompleted, - RooCodeEventName.TaskDelegationResumed, - - RooCodeEventName.TaskUserMessage, - RooCodeEventName.TaskTokenUsageUpdated, - ] - - // Check that on() was called for each event - expect(mockProvider.on).toHaveBeenCalledTimes(expectedEvents.length) - - // Verify each event was registered - expectedEvents.forEach((eventName) => { - expect(mockProvider.on).toHaveBeenCalledWith(eventName, expect.any(Function)) - }) - - // Verify listeners are tracked in our Map - expect(eventListeners.size).toBe(expectedEvents.length) - }) - - it("should remove all event listeners during cleanup", async () => { - // Verify initial state - listeners are registered - const initialListenerCount = eventListeners.size - expect(initialListenerCount).toBeGreaterThan(0) - - // Get the count of listeners for each event before cleanup - const listenerCountsBefore = new Map() - eventListeners.forEach((listeners, event) => { - listenerCountsBefore.set(event, listeners.size) - }) - - // Perform cleanup - await extensionChannel.cleanup(mockSocket) - - // Verify that off() was called for each registered event - expect(mockProvider.off).toHaveBeenCalledTimes(initialListenerCount) - - // Verify all listeners were removed from our tracking Map - expect(eventListeners.size).toBe(0) - - // Verify that the same listener functions that were added were removed - const onCalls = (mockProvider.on as any).mock.calls - const offCalls = (mockProvider.off as any).mock.calls - - // Each on() call should have a corresponding off() call with the same listener - onCalls.forEach(([eventName, listener]: [keyof TaskProviderEvents, any]) => { - const hasMatchingOff = offCalls.some( - ([offEvent, offListener]: [keyof TaskProviderEvents, any]) => - offEvent === eventName && offListener === listener, - ) - expect(hasMatchingOff).toBe(true) - }) - }) - - it("should not have duplicate listeners after multiple channel creations", () => { - // Create a second channel with the same provider - const secondChannel = new ExtensionChannel({ - instanceId: "instance-2", - appProperties, - userId, - provider: mockProvider, - isCloudAgent: false, - }) - - // Each event should have exactly 2 listeners (one from each channel) - eventListeners.forEach((listeners) => { - expect(listeners.size).toBe(2) - }) - - // Clean up the first channel - extensionChannel.cleanup(mockSocket) - - // Each event should now have exactly 1 listener (from the second channel) - eventListeners.forEach((listeners) => { - expect(listeners.size).toBe(1) - }) - - // Clean up the second channel - secondChannel.cleanup(mockSocket) - - // All listeners should be removed - expect(eventListeners.size).toBe(0) - }) - - it("should handle cleanup even if called multiple times", async () => { - // First cleanup - await extensionChannel.cleanup(mockSocket) - const firstOffCallCount = (mockProvider.off as any).mock.calls.length - - // Second cleanup (should be safe to call again) - await extensionChannel.cleanup(mockSocket) - const secondOffCallCount = (mockProvider.off as any).mock.calls.length - - // The second cleanup shouldn't try to remove listeners again - // since the internal Map was cleared - expect(secondOffCallCount).toBe(firstOffCallCount) - }) - - it("should properly forward events to socket when listeners are triggered", async () => { - // Connect the socket to enable publishing - await extensionChannel.onConnect(mockSocket) - - // Clear the mock calls from the connection (which emits a register event) - ;(mockSocket.emit as any).mockClear() - - // Get a listener that was registered for TaskStarted - const taskStartedListeners = eventListeners.get(RooCodeEventName.TaskStarted) - expect(taskStartedListeners).toBeDefined() - expect(taskStartedListeners!.size).toBe(1) - - // Trigger the listener - const listener = Array.from(taskStartedListeners!)[0] - if (listener) { - await listener("test-task-id") - } - - // Verify the event was published to the socket - expect(mockSocket.emit).toHaveBeenCalledWith( - ExtensionSocketEvents.EVENT, - expect.objectContaining({ - type: ExtensionBridgeEventName.TaskStarted, - instance: expect.objectContaining({ - instanceId, - userId, - }), - timestamp: expect.any(Number), - }), - undefined, - ) - }) - - it("should forward delegation events to socket", async () => { - await extensionChannel.onConnect(mockSocket) - ;(mockSocket.emit as any).mockClear() - - const delegatedListeners = eventListeners.get(RooCodeEventName.TaskDelegated) - expect(delegatedListeners).toBeDefined() - expect(delegatedListeners!.size).toBe(1) - - const listener = Array.from(delegatedListeners!)[0] - if (listener) { - await (listener as any)("parent-id", "child-id") - } - - expect(mockSocket.emit).toHaveBeenCalledWith( - ExtensionSocketEvents.EVENT, - expect.objectContaining({ - type: ExtensionBridgeEventName.TaskDelegated, - instance: expect.any(Object), - timestamp: expect.any(Number), - }), - undefined, - ) - }) - - it("should forward TaskDelegationCompleted with correct payload", async () => { - await extensionChannel.onConnect(mockSocket) - ;(mockSocket.emit as any).mockClear() - - const completedListeners = eventListeners.get(RooCodeEventName.TaskDelegationCompleted) - expect(completedListeners).toBeDefined() - - const listener = Array.from(completedListeners!)[0] - if (listener) { - await (listener as any)("parent-1", "child-1", "Summary text") - } - - expect(mockSocket.emit).toHaveBeenCalledWith( - ExtensionSocketEvents.EVENT, - expect.objectContaining({ - type: ExtensionBridgeEventName.TaskDelegationCompleted, - instance: expect.any(Object), - timestamp: expect.any(Number), - payload: expect.objectContaining({ - parentTaskId: "parent-1", - childTaskId: "child-1", - summary: "Summary text", - }), - }), - undefined, - ) - }) - - it("should forward TaskDelegationResumed with correct payload", async () => { - await extensionChannel.onConnect(mockSocket) - ;(mockSocket.emit as any).mockClear() - - const resumedListeners = eventListeners.get(RooCodeEventName.TaskDelegationResumed) - expect(resumedListeners).toBeDefined() - - const listener = Array.from(resumedListeners!)[0] - if (listener) { - await (listener as any)("parent-2", "child-2") - } - - expect(mockSocket.emit).toHaveBeenCalledWith( - ExtensionSocketEvents.EVENT, - expect.objectContaining({ - type: ExtensionBridgeEventName.TaskDelegationResumed, - instance: expect.any(Object), - timestamp: expect.any(Number), - payload: expect.objectContaining({ - parentTaskId: "parent-2", - childTaskId: "child-2", - }), - }), - undefined, - ) - }) - - it("should propagate all three delegation events in order", async () => { - await extensionChannel.onConnect(mockSocket) - ;(mockSocket.emit as any).mockClear() - - // Trigger TaskDelegated - const delegatedListener = Array.from(eventListeners.get(RooCodeEventName.TaskDelegated)!)[0] - await (delegatedListener as any)("p1", "c1") - - // Trigger TaskDelegationCompleted - const completedListener = Array.from(eventListeners.get(RooCodeEventName.TaskDelegationCompleted)!)[0] - await (completedListener as any)("p1", "c1", "result") - - // Trigger TaskDelegationResumed - const resumedListener = Array.from(eventListeners.get(RooCodeEventName.TaskDelegationResumed)!)[0] - await (resumedListener as any)("p1", "c1") - - // Verify all three events were emitted - const emittedEvents = (mockSocket.emit as any).mock.calls.map((call: any[]) => call[1]?.type) - expect(emittedEvents).toContain(ExtensionBridgeEventName.TaskDelegated) - expect(emittedEvents).toContain(ExtensionBridgeEventName.TaskDelegationCompleted) - expect(emittedEvents).toContain(ExtensionBridgeEventName.TaskDelegationResumed) - - // Verify correct order: Delegated → Completed → Resumed - const delegatedIdx = emittedEvents.indexOf(ExtensionBridgeEventName.TaskDelegated) - const completedIdx = emittedEvents.indexOf(ExtensionBridgeEventName.TaskDelegationCompleted) - const resumedIdx = emittedEvents.indexOf(ExtensionBridgeEventName.TaskDelegationResumed) - - expect(delegatedIdx).toBeLessThan(completedIdx) - expect(completedIdx).toBeLessThan(resumedIdx) - }) - }) - - describe("Memory Leak Prevention", () => { - it("should not accumulate listeners over multiple connect/disconnect cycles", async () => { - // Simulate multiple connect/disconnect cycles - for (let i = 0; i < 5; i++) { - await extensionChannel.onConnect(mockSocket) - extensionChannel.onDisconnect() - } - - // Listeners should still be the same count (not accumulated) - expect(eventListeners.size).toBe(18) - - // Each event should have exactly 1 listener - eventListeners.forEach((listeners) => { - expect(listeners.size).toBe(1) - }) - }) - - it("should properly clean up heartbeat interval", async () => { - // Spy on setInterval and clearInterval - const setIntervalSpy = vi.spyOn(global, "setInterval") - const clearIntervalSpy = vi.spyOn(global, "clearInterval") - - // Connect to start heartbeat - await extensionChannel.onConnect(mockSocket) - expect(setIntervalSpy).toHaveBeenCalled() - - // Get the interval ID - const intervalId = setIntervalSpy.mock.results[0]?.value - - // Cleanup should stop the heartbeat - await extensionChannel.cleanup(mockSocket) - expect(clearIntervalSpy).toHaveBeenCalledWith(intervalId) - - setIntervalSpy.mockRestore() - clearIntervalSpy.mockRestore() - }) - }) -}) diff --git a/packages/cloud/src/bridge/__tests__/TaskChannel.test.ts b/packages/cloud/src/bridge/__tests__/TaskChannel.test.ts deleted file mode 100644 index f4f1526607..0000000000 --- a/packages/cloud/src/bridge/__tests__/TaskChannel.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-function-type */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import type { Socket } from "socket.io-client" - -import { - type TaskLike, - type ClineMessage, - type StaticAppProperties, - RooCodeEventName, - TaskBridgeEventName, - TaskBridgeCommandName, - TaskSocketEvents, - TaskStatus, -} from "@roo-code/types" - -import { TaskChannel } from "../TaskChannel.js" - -describe("TaskChannel", () => { - let mockSocket: Socket - let taskChannel: TaskChannel - let mockTask: TaskLike - const instanceId = "test-instance-123" - const taskId = "test-task-456" - - const appProperties: StaticAppProperties = { - appName: "roo-code", - appVersion: "1.0.0", - vscodeVersion: "1.0.0", - platform: "darwin", - editorName: "Roo Code", - hostname: "test-host", - } - - beforeEach(() => { - // Create mock socket - mockSocket = { - emit: vi.fn(), - on: vi.fn(), - off: vi.fn(), - disconnect: vi.fn(), - } as unknown as Socket - - // Create mock task with event emitter functionality - const listeners = new Map unknown>>() - mockTask = { - taskId, - taskStatus: TaskStatus.Running, - taskAsk: undefined, - metadata: {}, - on: vi.fn((event: string, listener: (...args: unknown[]) => unknown) => { - if (!listeners.has(event)) { - listeners.set(event, new Set()) - } - listeners.get(event)!.add(listener) - return mockTask - }), - off: vi.fn((event: string, listener: (...args: unknown[]) => unknown) => { - const eventListeners = listeners.get(event) - if (eventListeners) { - eventListeners.delete(listener) - if (eventListeners.size === 0) { - listeners.delete(event) - } - } - return mockTask - }), - approveAsk: vi.fn(), - denyAsk: vi.fn(), - submitUserMessage: vi.fn(), - abortTask: vi.fn(), - // Helper to trigger events in tests - _triggerEvent: (event: string, ...args: any[]) => { - const eventListeners = listeners.get(event) - if (eventListeners) { - eventListeners.forEach((listener) => listener(...args)) - } - }, - _getListenerCount: (event: string) => { - return listeners.get(event)?.size || 0 - }, - } as unknown as TaskLike & { - _triggerEvent: (event: string, ...args: any[]) => void - _getListenerCount: (event: string) => number - } - - // Create task channel instance - taskChannel = new TaskChannel({ - instanceId, - appProperties, - isCloudAgent: false, - }) - }) - - afterEach(() => { - vi.clearAllMocks() - }) - - describe("Event Mapping Refactoring", () => { - it("should use the unified event mapping approach", () => { - // Access the private eventMapping through type assertion - const channel = taskChannel as any - - // Verify eventMapping exists and has the correct structure - expect(channel.eventMapping).toBeDefined() - expect(Array.isArray(channel.eventMapping)).toBe(true) - expect(channel.eventMapping.length).toBe(3) - - // Verify each mapping has the required properties - channel.eventMapping.forEach((mapping: any) => { - expect(mapping).toHaveProperty("from") - expect(mapping).toHaveProperty("to") - expect(mapping).toHaveProperty("createPayload") - expect(typeof mapping.createPayload).toBe("function") - }) - - // Verify specific mappings - expect(channel.eventMapping[0].from).toBe(RooCodeEventName.Message) - expect(channel.eventMapping[0].to).toBe(TaskBridgeEventName.Message) - - expect(channel.eventMapping[1].from).toBe(RooCodeEventName.TaskModeSwitched) - expect(channel.eventMapping[1].to).toBe(TaskBridgeEventName.TaskModeSwitched) - - expect(channel.eventMapping[2].from).toBe(RooCodeEventName.TaskInteractive) - expect(channel.eventMapping[2].to).toBe(TaskBridgeEventName.TaskInteractive) - }) - - it("should setup listeners using the event mapping", async () => { - // Mock the publish method to simulate successful subscription - const channel = taskChannel as any - channel.publish = vi.fn((event: string, data: any, callback?: Function) => { - if (event === TaskSocketEvents.JOIN && callback) { - // Simulate successful join response - callback({ success: true }) - } - return true - }) - - // Connect and subscribe to task - await taskChannel.onConnect(mockSocket) - await channel.subscribeToTask(mockTask, mockSocket) - - // Wait for async operations - await new Promise((resolve) => setTimeout(resolve, 0)) - - // Verify listeners were registered for all mapped events - const task = mockTask as any - expect(task._getListenerCount(RooCodeEventName.Message)).toBe(1) - expect(task._getListenerCount(RooCodeEventName.TaskModeSwitched)).toBe(1) - expect(task._getListenerCount(RooCodeEventName.TaskInteractive)).toBe(1) - }) - - it("should correctly transform Message event payloads", async () => { - // Setup channel with task - const channel = taskChannel as any - let publishCalls: any[] = [] - - channel.publish = vi.fn((event: string, data: any, callback?: Function) => { - publishCalls.push({ event, data }) - - if (event === TaskSocketEvents.JOIN && callback) { - callback({ success: true }) - } - - return true - }) - - await taskChannel.onConnect(mockSocket) - await channel.subscribeToTask(mockTask, mockSocket) - await new Promise((resolve) => setTimeout(resolve, 0)) - - // Clear previous calls - publishCalls = [] - - // Trigger Message event - const messageData = { - action: "test-action", - message: { type: "say", text: "Hello" } as ClineMessage, - } - - ;(mockTask as any)._triggerEvent(RooCodeEventName.Message, messageData) - - // Verify the event was published with correct payload - expect(publishCalls.length).toBe(1) - expect(publishCalls[0]).toEqual({ - event: TaskSocketEvents.EVENT, - data: { - type: TaskBridgeEventName.Message, - taskId: taskId, - action: messageData.action, - message: messageData.message, - }, - }) - }) - - it("should correctly transform TaskModeSwitched event payloads", async () => { - // Setup channel with task - const channel = taskChannel as any - let publishCalls: any[] = [] - - channel.publish = vi.fn((event: string, data: any, callback?: Function) => { - publishCalls.push({ event, data }) - - if (event === TaskSocketEvents.JOIN && callback) { - callback({ success: true }) - } - - return true - }) - - await taskChannel.onConnect(mockSocket) - await channel.subscribeToTask(mockTask, mockSocket) - await new Promise((resolve) => setTimeout(resolve, 0)) - - // Clear previous calls - publishCalls = [] - - // Trigger TaskModeSwitched event - const mode = "architect" - ;(mockTask as any)._triggerEvent(RooCodeEventName.TaskModeSwitched, mode) - - // Verify the event was published with correct payload - expect(publishCalls.length).toBe(1) - expect(publishCalls[0]).toEqual({ - event: TaskSocketEvents.EVENT, - data: { - type: TaskBridgeEventName.TaskModeSwitched, - taskId: taskId, - mode: mode, - }, - }) - }) - - it("should correctly transform TaskInteractive event payloads", async () => { - // Setup channel with task - const channel = taskChannel as any - let publishCalls: any[] = [] - - channel.publish = vi.fn((event: string, data: any, callback?: Function) => { - publishCalls.push({ event, data }) - if (event === TaskSocketEvents.JOIN && callback) { - callback({ success: true }) - } - return true - }) - - await taskChannel.onConnect(mockSocket) - await channel.subscribeToTask(mockTask, mockSocket) - await new Promise((resolve) => setTimeout(resolve, 0)) - - // Clear previous calls - publishCalls = [] - - // Trigger TaskInteractive event - ;(mockTask as any)._triggerEvent(RooCodeEventName.TaskInteractive, taskId) - - // Verify the event was published with correct payload - expect(publishCalls.length).toBe(1) - expect(publishCalls[0]).toEqual({ - event: TaskSocketEvents.EVENT, - data: { - type: TaskBridgeEventName.TaskInteractive, - taskId: taskId, - }, - }) - }) - - it("should properly clean up listeners using event mapping", async () => { - // Setup channel with task - const channel = taskChannel as any - - channel.publish = vi.fn((event: string, data: any, callback?: Function) => { - if (event === TaskSocketEvents.JOIN && callback) { - callback({ success: true }) - } - if (event === TaskSocketEvents.LEAVE && callback) { - callback({ success: true }) - } - return true - }) - - await taskChannel.onConnect(mockSocket) - await channel.subscribeToTask(mockTask, mockSocket) - await new Promise((resolve) => setTimeout(resolve, 0)) - - // Verify listeners are registered - const task = mockTask as any - expect(task._getListenerCount(RooCodeEventName.Message)).toBe(1) - expect(task._getListenerCount(RooCodeEventName.TaskModeSwitched)).toBe(1) - expect(task._getListenerCount(RooCodeEventName.TaskInteractive)).toBe(1) - - // Clean up - await taskChannel.cleanup(mockSocket) - - // Verify all listeners were removed - expect(task._getListenerCount(RooCodeEventName.Message)).toBe(0) - expect(task._getListenerCount(RooCodeEventName.TaskModeSwitched)).toBe(0) - expect(task._getListenerCount(RooCodeEventName.TaskInteractive)).toBe(0) - }) - - it("should handle duplicate listener prevention", async () => { - // Setup channel with task - await taskChannel.onConnect(mockSocket) - - // Subscribe to the same task twice - const channel = taskChannel as any - channel.subscribedTasks.set(taskId, mockTask) - channel.setupTaskListeners(mockTask) - - // Try to setup listeners again (should remove old ones first) - const warnSpy = vi.spyOn(console, "warn") - channel.setupTaskListeners(mockTask) - - // Verify warning was logged - expect(warnSpy).toHaveBeenCalledWith( - `[TaskChannel] Listeners already exist for task, removing old listeners for ${taskId}`, - ) - - // Verify only one set of listeners exists - const task = mockTask as any - expect(task._getListenerCount(RooCodeEventName.Message)).toBe(1) - expect(task._getListenerCount(RooCodeEventName.TaskModeSwitched)).toBe(1) - expect(task._getListenerCount(RooCodeEventName.TaskInteractive)).toBe(1) - - warnSpy.mockRestore() - }) - }) - - describe("Command Handling", () => { - beforeEach(async () => { - // Setup channel with a subscribed task - await taskChannel.onConnect(mockSocket) - const channel = taskChannel as any - channel.subscribedTasks.set(taskId, mockTask) - }) - - it("should handle Message command", async () => { - const command = { - type: TaskBridgeCommandName.Message, - taskId, - timestamp: Date.now(), - payload: { - text: "Hello, world!", - images: ["image1.png"], - }, - } - - await taskChannel.handleCommand(command) - - expect(mockTask.submitUserMessage).toHaveBeenCalledWith( - command.payload.text, - command.payload.images, - undefined, - undefined, - ) - }) - - it("should handle ApproveAsk command", async () => { - const command = { - type: TaskBridgeCommandName.ApproveAsk, - taskId, - timestamp: Date.now(), - payload: { - text: "Approved", - }, - } - - await taskChannel.handleCommand(command) - - expect(mockTask.approveAsk).toHaveBeenCalledWith(command.payload) - }) - - it("should handle DenyAsk command", async () => { - const command = { - type: TaskBridgeCommandName.DenyAsk, - taskId, - timestamp: Date.now(), - payload: { - text: "Denied", - }, - } - - await taskChannel.handleCommand(command) - - expect(mockTask.denyAsk).toHaveBeenCalledWith(command.payload) - }) - - it("should log error for unknown task", async () => { - const errorSpy = vi.spyOn(console, "error") - - const command = { - type: TaskBridgeCommandName.Message, - taskId: "unknown-task", - timestamp: Date.now(), - payload: { - text: "Hello", - }, - } - - await taskChannel.handleCommand(command) - - expect(errorSpy).toHaveBeenCalledWith(`[TaskChannel] Unable to find task unknown-task`) - - errorSpy.mockRestore() - }) - }) -}) diff --git a/packages/cloud/src/bridge/index.ts b/packages/cloud/src/bridge/index.ts deleted file mode 100644 index 94873c09fd..0000000000 --- a/packages/cloud/src/bridge/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { type BridgeOrchestratorOptions, BridgeOrchestrator } from "./BridgeOrchestrator.js" -export { type SocketTransportOptions, SocketTransport } from "./SocketTransport.js" - -export { BaseChannel } from "./BaseChannel.js" -export { ExtensionChannel } from "./ExtensionChannel.js" -export { TaskChannel } from "./TaskChannel.js" diff --git a/packages/cloud/src/index.ts b/packages/cloud/src/index.ts index 65b92ebc13..8792176fee 100644 --- a/packages/cloud/src/index.ts +++ b/packages/cloud/src/index.ts @@ -2,7 +2,5 @@ export * from "./config.js" export { CloudService } from "./CloudService.js" -export { BridgeOrchestrator } from "./bridge/index.js" - export { RetryQueue } from "./retry-queue/index.js" export type { QueuedRequest, QueueStats, RetryQueueConfig, RetryQueueEvents } from "./retry-queue/index.js" diff --git a/packages/types/src/__tests__/cloud.test.ts b/packages/types/src/__tests__/cloud.test.ts index 4e9e792a29..9c2a32a99c 100644 --- a/packages/types/src/__tests__/cloud.test.ts +++ b/packages/types/src/__tests__/cloud.test.ts @@ -21,43 +21,9 @@ describe("organizationFeaturesSchema", () => { expect(result.data).toEqual({}) }) - it("should validate with roomoteControlEnabled as true", () => { - const input = { roomoteControlEnabled: true } - const result = organizationFeaturesSchema.safeParse(input) - expect(result.success).toBe(true) - expect(result.data).toEqual(input) - }) - - it("should validate with roomoteControlEnabled as false", () => { - const input = { roomoteControlEnabled: false } - const result = organizationFeaturesSchema.safeParse(input) - expect(result.success).toBe(true) - expect(result.data).toEqual(input) - }) - - it("should reject non-boolean roomoteControlEnabled", () => { - const input = { roomoteControlEnabled: "true" } - const result = organizationFeaturesSchema.safeParse(input) - expect(result.success).toBe(false) - }) - - it("should allow additional properties (for future extensibility)", () => { - const input = { roomoteControlEnabled: true, futureProperty: "test" } - const result = organizationFeaturesSchema.safeParse(input) - expect(result.success).toBe(true) - expect(result.data?.roomoteControlEnabled).toBe(true) - // Note: Additional properties are stripped by Zod, which is expected behavior - }) - it("should have correct TypeScript type", () => { - // Type-only test to ensure TypeScript compilation - const features: OrganizationFeatures = { - roomoteControlEnabled: true, - } - expect(features.roomoteControlEnabled).toBe(true) - const emptyFeatures: OrganizationFeatures = {} - expect(emptyFeatures.roomoteControlEnabled).toBeUndefined() + expect(emptyFeatures).toEqual({}) }) }) @@ -87,43 +53,7 @@ describe("organizationSettingsSchema with features", () => { expect(result.data?.features).toEqual({}) }) - it("should validate with features.roomoteControlEnabled as true", () => { - const input = { - ...validBaseSettings, - features: { - roomoteControlEnabled: true, - }, - } - const result = organizationSettingsSchema.safeParse(input) - expect(result.success).toBe(true) - expect(result.data?.features?.roomoteControlEnabled).toBe(true) - }) - - it("should validate with features.roomoteControlEnabled as false", () => { - const input = { - ...validBaseSettings, - features: { - roomoteControlEnabled: false, - }, - } - const result = organizationSettingsSchema.safeParse(input) - expect(result.success).toBe(true) - expect(result.data?.features?.roomoteControlEnabled).toBe(false) - }) - - it("should reject invalid features object", () => { - const input = { - ...validBaseSettings, - features: { - roomoteControlEnabled: "invalid", - }, - } - const result = organizationSettingsSchema.safeParse(input) - expect(result.success).toBe(false) - }) - it("should have correct TypeScript type for features", () => { - // Type-only test to ensure TypeScript compilation const settings: OrganizationSettings = { version: 1, defaultSettings: {}, @@ -131,11 +61,9 @@ describe("organizationSettingsSchema with features", () => { allowAll: true, providers: {}, }, - features: { - roomoteControlEnabled: true, - }, + features: {}, } - expect(settings.features?.roomoteControlEnabled).toBe(true) + expect(settings.features).toEqual({}) const settingsWithoutFeatures: OrganizationSettings = { version: 1, @@ -165,9 +93,7 @@ describe("organizationSettingsSchema with features", () => { }, }, }, - features: { - roomoteControlEnabled: true, - }, + features: {}, hiddenMcps: ["test-mcp"], hideMarketplaceMcps: true, mcps: [], @@ -415,7 +341,6 @@ describe("organizationCloudSettingsSchema with llmEnhancedFeaturesEnabled", () = describe("userSettingsConfigSchema with llmEnhancedFeaturesEnabled", () => { it("should validate without llmEnhancedFeaturesEnabled property", () => { const input = { - extensionBridgeEnabled: true, taskSyncEnabled: true, } const result = userSettingsConfigSchema.safeParse(input) @@ -425,7 +350,6 @@ describe("userSettingsConfigSchema with llmEnhancedFeaturesEnabled", () => { it("should validate with llmEnhancedFeaturesEnabled as true", () => { const input = { - extensionBridgeEnabled: true, taskSyncEnabled: true, llmEnhancedFeaturesEnabled: true, } @@ -436,7 +360,6 @@ describe("userSettingsConfigSchema with llmEnhancedFeaturesEnabled", () => { it("should validate with llmEnhancedFeaturesEnabled as false", () => { const input = { - extensionBridgeEnabled: true, taskSyncEnabled: true, llmEnhancedFeaturesEnabled: false, } @@ -456,15 +379,12 @@ describe("userSettingsConfigSchema with llmEnhancedFeaturesEnabled", () => { it("should have correct TypeScript type", () => { // Type-only test to ensure TypeScript compilation const settings: UserSettingsConfig = { - extensionBridgeEnabled: true, taskSyncEnabled: true, llmEnhancedFeaturesEnabled: true, } expect(settings.llmEnhancedFeaturesEnabled).toBe(true) - const settingsWithoutLlmFeatures: UserSettingsConfig = { - extensionBridgeEnabled: false, - } + const settingsWithoutLlmFeatures: UserSettingsConfig = {} expect(settingsWithoutLlmFeatures.llmEnhancedFeaturesEnabled).toBeUndefined() }) diff --git a/packages/types/src/cloud.ts b/packages/types/src/cloud.ts index 2de8ce9168..c991cdb1e6 100644 --- a/packages/types/src/cloud.ts +++ b/packages/types/src/cloud.ts @@ -41,7 +41,6 @@ export interface CloudUserInfo { organizationName?: string organizationRole?: string organizationImageUrl?: string - extensionBridgeEnabled?: boolean } /** @@ -143,9 +142,7 @@ export type OrganizationCloudSettings = z.infer @@ -171,14 +168,11 @@ export type OrganizationSettings = z.infer * User Settings Schemas */ -export const userFeaturesSchema = z.object({ - roomoteControlEnabled: z.boolean().optional(), -}) +export const userFeaturesSchema = z.object({}) export type UserFeatures = z.infer export const userSettingsConfigSchema = z.object({ - extensionBridgeEnabled: z.boolean().optional(), taskSyncEnabled: z.boolean().optional(), llmEnhancedFeaturesEnabled: z.boolean().optional(), }) @@ -430,206 +424,6 @@ export const extensionInstanceSchema = z.object({ export type ExtensionInstance = z.infer -/** - * ExtensionBridgeEvent - */ - -export enum ExtensionBridgeEventName { - TaskCreated = RooCodeEventName.TaskCreated, - TaskStarted = RooCodeEventName.TaskStarted, - TaskCompleted = RooCodeEventName.TaskCompleted, - TaskAborted = RooCodeEventName.TaskAborted, - TaskFocused = RooCodeEventName.TaskFocused, - TaskUnfocused = RooCodeEventName.TaskUnfocused, - TaskActive = RooCodeEventName.TaskActive, - TaskInteractive = RooCodeEventName.TaskInteractive, - TaskResumable = RooCodeEventName.TaskResumable, - TaskIdle = RooCodeEventName.TaskIdle, - - TaskPaused = RooCodeEventName.TaskPaused, - TaskUnpaused = RooCodeEventName.TaskUnpaused, - TaskSpawned = RooCodeEventName.TaskSpawned, - TaskDelegated = RooCodeEventName.TaskDelegated, - TaskDelegationCompleted = RooCodeEventName.TaskDelegationCompleted, - TaskDelegationResumed = RooCodeEventName.TaskDelegationResumed, - - TaskUserMessage = RooCodeEventName.TaskUserMessage, - - TaskTokenUsageUpdated = RooCodeEventName.TaskTokenUsageUpdated, - - ModeChanged = RooCodeEventName.ModeChanged, - ProviderProfileChanged = RooCodeEventName.ProviderProfileChanged, - - InstanceRegistered = "instance_registered", - InstanceUnregistered = "instance_unregistered", - HeartbeatUpdated = "heartbeat_updated", -} - -export const extensionBridgeEventSchema = z.discriminatedUnion("type", [ - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskCreated), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskStarted), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskCompleted), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskAborted), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskFocused), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskUnfocused), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskActive), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskInteractive), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskResumable), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskIdle), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskPaused), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskUnpaused), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskSpawned), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskDelegated), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskDelegationCompleted), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskDelegationResumed), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskUserMessage), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - - z.object({ - type: z.literal(ExtensionBridgeEventName.TaskTokenUsageUpdated), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - - z.object({ - type: z.literal(ExtensionBridgeEventName.ModeChanged), - instance: extensionInstanceSchema, - mode: z.string(), - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.ProviderProfileChanged), - instance: extensionInstanceSchema, - providerProfile: z.object({ name: z.string(), provider: z.string().optional() }), - timestamp: z.number(), - }), - - z.object({ - type: z.literal(ExtensionBridgeEventName.InstanceRegistered), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.InstanceUnregistered), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeEventName.HeartbeatUpdated), - instance: extensionInstanceSchema, - timestamp: z.number(), - }), -]) - -export type ExtensionBridgeEvent = z.infer - -/** - * ExtensionBridgeCommand - */ - -export enum ExtensionBridgeCommandName { - StartTask = "start_task", - StopTask = "stop_task", - ResumeTask = "resume_task", -} - -export const extensionBridgeCommandSchema = z.discriminatedUnion("type", [ - z.object({ - type: z.literal(ExtensionBridgeCommandName.StartTask), - instanceId: z.string(), - payload: z.object({ - text: z.string(), - images: z.array(z.string()).optional(), - mode: z.string().optional(), - providerProfile: z.string().optional(), - }), - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeCommandName.StopTask), - instanceId: z.string(), - payload: z.object({ taskId: z.string() }), - timestamp: z.number(), - }), - z.object({ - type: z.literal(ExtensionBridgeCommandName.ResumeTask), - instanceId: z.string(), - payload: z.object({ taskId: z.string() }), - timestamp: z.number(), - }), -]) - -export type ExtensionBridgeCommand = z.infer - /** * TaskBridgeEvent */ diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 47b574e4b7..2d8c52cb04 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -366,9 +366,7 @@ export type ExtensionState = Pick< apiModelId?: string mcpServers?: McpServer[] mdmCompliant?: boolean - remoteControlEnabled: boolean taskSyncEnabled: boolean - featureRoomoteControlEnabled: boolean openAiCodexIsAuthenticated?: boolean debug?: boolean @@ -472,7 +470,6 @@ export interface WebviewMessage { | "deleteMessageConfirm" | "submitEditedMessage" | "editMessageConfirm" - | "remoteControlEnabled" | "taskSyncEnabled" | "searchCommits" | "setApiConfigPassword" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b461926f5..42a502c8c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -495,9 +495,6 @@ importers: p-wait-for: specifier: ^5.0.2 version: 5.0.2 - socket.io-client: - specifier: ^4.8.1 - version: 4.8.1 zod: specifier: 3.25.76 version: 3.25.76 @@ -971,9 +968,6 @@ importers: simple-git: specifier: ^3.27.0 version: 3.27.0 - socket.io-client: - specifier: ^4.8.1 - version: 4.8.1 sound-play: specifier: ^1.1.0 version: 1.1.0 @@ -1200,9 +1194,6 @@ importers: '@tanstack/react-query': specifier: ^5.68.0 version: 5.76.1(react@18.3.1) - '@types/qrcode': - specifier: ^1.5.5 - version: 1.5.5 '@vscode/codicons': specifier: ^0.0.36 version: 0.0.36 @@ -1266,9 +1257,6 @@ importers: pretty-bytes: specifier: ^7.0.0 version: 7.0.0 - qrcode: - specifier: ^1.5.4 - version: 1.5.4 react: specifier: ^18.3.1 version: 18.3.1 @@ -4093,9 +4081,6 @@ packages: resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} - '@socket.io/component-emitter@3.1.2': - resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -4580,9 +4565,6 @@ packages: '@types/ps-tree@1.1.6': resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==} - '@types/qrcode@1.5.5': - resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==} - '@types/react-dom@18.3.7': resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} peerDependencies: @@ -5275,10 +5257,6 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -5429,9 +5407,6 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -5865,15 +5840,6 @@ packages: supports-color: optional: true - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -5892,10 +5858,6 @@ packages: supports-color: optional: true - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - decamelize@4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} @@ -6024,9 +5986,6 @@ packages: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} - dijkstrajs@1.0.3: - resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - dingbat-to-unicode@1.0.1: resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==} @@ -6262,13 +6221,6 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - engine.io-client@6.6.3: - resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==} - - engine.io-parser@5.2.3: - resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} - engines: {node: '>=10.0.0'} - enhanced-resolve@5.18.1: resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} engines: {node: '>=10.13.0'} @@ -8896,10 +8848,6 @@ packages: pkg-types@2.2.0: resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==} - pngjs@5.0.0: - resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} - engines: {node: '>=10.13.0'} - points-on-curve@0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} @@ -9123,11 +9071,6 @@ packages: resolution: {integrity: sha512-CnzhOgrZj8DvkDqI+Yx+9or33i3Y9uUYbKyYpP4C13jWwXx/keQ38RMTMmxuLCWQlxjZrOH0Foq7P2fGP7adDQ==} engines: {node: '>=18'} - qrcode@1.5.4: - resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} - engines: {node: '>=10.13.0'} - hasBin: true - qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -9431,9 +9374,6 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} @@ -9632,9 +9572,6 @@ packages: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -9750,14 +9687,6 @@ packages: resolution: {integrity: sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==} engines: {node: '>= 18'} - socket.io-client@4.8.1: - resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} - engines: {node: '>=10.0.0'} - - socket.io-parser@4.2.4: - resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} - engines: {node: '>=10.0.0'} - socks-proxy-agent@8.0.5: resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} engines: {node: '>= 14'} @@ -10869,9 +10798,6 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -10921,10 +10847,6 @@ packages: workerpool@9.2.0: resolution: {integrity: sha512-PKZqBOCo6CYkVOwAxWxQaSF2Fvb5Iv2fCeTP7buyWI2GiynWr46NcXSgK/idoV6e60dgCBfgYc+Un3HMvmqP8w==} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -10940,18 +10862,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@8.18.2: resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} engines: {node: '>=10.0.0'} @@ -10995,17 +10905,10 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xmlhttprequest-ssl@2.1.2: - resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} - engines: {node: '>=0.4.0'} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -11025,10 +10928,6 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -11041,10 +10940,6 @@ packages: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} @@ -14310,8 +14205,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@socket.io/component-emitter@3.1.2': {} - '@standard-schema/spec@1.1.0': {} '@standard-schema/utils@0.3.0': {} @@ -14798,10 +14691,6 @@ snapshots: '@types/ps-tree@1.1.6': {} - '@types/qrcode@1.5.5': - dependencies: - '@types/node': 24.2.1 - '@types/react-dom@18.3.7(@types/react@18.3.23)': dependencies: '@types/react': 18.3.23 @@ -15655,8 +15544,6 @@ snapshots: camelcase-css@2.0.1: {} - camelcase@5.3.1: {} - camelcase@6.3.0: {} camelize@1.0.1: {} @@ -15818,12 +15705,6 @@ snapshots: client-only@0.0.1: {} - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -16274,10 +16155,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.7: - dependencies: - ms: 2.1.3 - debug@4.4.1(supports-color@8.1.1): dependencies: ms: 2.1.3 @@ -16288,8 +16165,6 @@ snapshots: dependencies: ms: 2.1.3 - decamelize@1.2.0: {} - decamelize@4.0.0: {} decimal.js-light@2.5.1: {} @@ -16387,8 +16262,6 @@ snapshots: diff@5.2.0: {} - dijkstrajs@1.0.3: {} - dingbat-to-unicode@1.0.1: {} dir-glob@3.0.1: @@ -16537,20 +16410,6 @@ snapshots: dependencies: once: 1.4.0 - engine.io-client@6.6.3: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 - engine.io-parser: 5.2.3 - ws: 8.17.1 - xmlhttprequest-ssl: 2.1.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - engine.io-parser@5.2.3: {} - enhanced-resolve@5.18.1: dependencies: graceful-fs: 4.2.11 @@ -19773,8 +19632,6 @@ snapshots: exsolve: 1.0.7 pathe: 2.0.3 - pngjs@5.0.0: {} - points-on-curve@0.2.0: {} points-on-path@0.2.1: @@ -20045,12 +19902,6 @@ snapshots: - supports-color - utf-8-validate - qrcode@1.5.4: - dependencies: - dijkstrajs: 1.0.3 - pngjs: 5.0.0 - yargs: 15.4.1 - qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -20459,8 +20310,6 @@ snapshots: require-directory@2.1.1: {} - require-main-filename@2.0.0: {} - resize-observer-polyfill@1.5.1: {} resolve-from@4.0.0: {} @@ -20708,8 +20557,6 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: {} - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -20873,24 +20720,6 @@ snapshots: smol-toml@1.3.4: {} - socket.io-client@4.8.1: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 - engine.io-client: 6.6.3 - socket.io-parser: 4.2.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - socket.io-parser@4.2.4: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.3 @@ -22247,8 +22076,6 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 - which-module@2.0.1: {} - which-pm-runs@1.1.0: {} which-typed-array@1.1.19: @@ -22296,12 +22123,6 @@ snapshots: workerpool@9.2.0: {} - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -22322,8 +22143,6 @@ snapshots: wrappy@1.0.2: {} - ws@8.17.1: {} - ws@8.18.2: {} ws@8.18.3: {} @@ -22341,12 +22160,8 @@ snapshots: xmlchars@2.2.0: {} - xmlhttprequest-ssl@2.1.2: {} - xtend@4.0.2: {} - y18n@4.0.3: {} - y18n@5.0.8: {} yallist@3.1.1: {} @@ -22357,11 +22172,6 @@ snapshots: yaml@2.8.0: {} - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - yargs-parser@20.2.9: {} yargs-parser@21.1.1: {} @@ -22373,20 +22183,6 @@ snapshots: flat: 5.0.2 is-plain-obj: 2.1.0 - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - yargs@16.2.0: dependencies: cliui: 7.0.4 diff --git a/src/__tests__/extension.spec.ts b/src/__tests__/extension.spec.ts index 446a91f77c..a13e78c4bd 100644 --- a/src/__tests__/extension.spec.ts +++ b/src/__tests__/extension.spec.ts @@ -51,8 +51,6 @@ vi.mock("fs", () => ({ existsSync: vi.fn().mockReturnValue(false), })) -const mockBridgeOrchestratorDisconnect = vi.fn().mockResolvedValue(undefined) - const mockCloudServiceInstance = { off: vi.fn(), on: vi.fn(), @@ -71,9 +69,6 @@ vi.mock("@roo-code/cloud", () => ({ return mockCloudServiceInstance }, }, - BridgeOrchestrator: { - disconnect: mockBridgeOrchestratorDisconnect, - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) @@ -181,20 +176,14 @@ vi.mock("../i18n", () => ({ t: vi.fn((key) => key), })) -// Mock ClineProvider - remoteControlEnabled must call BridgeOrchestrator.disconnect for the test +// Mock ClineProvider vi.mock("../core/webview/ClineProvider", async () => { - const { BridgeOrchestrator } = await import("@roo-code/cloud") const mockInstance = { resolveWebviewView: vi.fn(), postMessageToWebview: vi.fn(), postStateToWebview: vi.fn(), postStateToWebviewWithoutClineMessages: vi.fn(), getState: vi.fn().mockResolvedValue({}), - remoteControlEnabled: vi.fn().mockImplementation(async (enabled: boolean) => { - if (!enabled) { - await BridgeOrchestrator.disconnect() - } - }), initializeCloudProfileSyncWhenReady: vi.fn().mockResolvedValue(undefined), providerSettingsManager: {}, contextProxy: { getGlobalState: vi.fn() }, @@ -230,7 +219,6 @@ describe("extension.ts", () => { beforeEach(() => { vi.clearAllMocks() - mockBridgeOrchestratorDisconnect.mockClear() mockContext = { extensionPath: "/test/path", @@ -274,73 +262,6 @@ describe("extension.ts", () => { expect(dotenvx.config).toHaveBeenCalledTimes(1) }) - test("authStateChangedHandler calls BridgeOrchestrator.disconnect when logged-out event fires", async () => { - const { CloudService, BridgeOrchestrator } = await import("@roo-code/cloud") - - // Capture the auth state changed handler. - vi.mocked(CloudService.createInstance).mockImplementation(async (_context, _logger, handlers) => { - if (handlers?.["auth-state-changed"]) { - authStateChangedHandler = handlers["auth-state-changed"] - } - - return { - off: vi.fn(), - on: vi.fn(), - telemetryClient: null, - hasActiveSession: vi.fn().mockReturnValue(false), - authService: null, - } as any - }) - - // Activate the extension. - const { activate } = await import("../extension") - await activate(mockContext) - - // Verify handler was registered. - expect(authStateChangedHandler).toBeDefined() - - // Trigger logout. - await authStateChangedHandler!({ - state: "logged-out" as AuthState, - previousState: "logged-in" as AuthState, - }) - - // Verify BridgeOrchestrator.disconnect was called - expect(mockBridgeOrchestratorDisconnect).toHaveBeenCalled() - }) - - test("authStateChangedHandler does not call BridgeOrchestrator.disconnect for other states", async () => { - const { CloudService } = await import("@roo-code/cloud") - - // Capture the auth state changed handler. - vi.mocked(CloudService.createInstance).mockImplementation(async (_context, _logger, handlers) => { - if (handlers?.["auth-state-changed"]) { - authStateChangedHandler = handlers["auth-state-changed"] - } - - return { - off: vi.fn(), - on: vi.fn(), - telemetryClient: null, - hasActiveSession: vi.fn().mockReturnValue(false), - authService: null, - } as any - }) - - // Activate the extension. - const { activate } = await import("../extension") - await activate(mockContext) - - // Trigger login. - await authStateChangedHandler!({ - state: "logged-in" as AuthState, - previousState: "logged-out" as AuthState, - }) - - // Verify BridgeOrchestrator.disconnect was NOT called. - expect(mockBridgeOrchestratorDisconnect).not.toHaveBeenCalled() - }) - describe("Roo model cache refresh on auth state change (ROO-202)", () => { beforeEach(() => { vi.resetModules() diff --git a/src/__tests__/single-open-invariant.spec.ts b/src/__tests__/single-open-invariant.spec.ts index 7fac886030..b7e1b99d7c 100644 --- a/src/__tests__/single-open-invariant.spec.ts +++ b/src/__tests__/single-open-invariant.spec.ts @@ -13,7 +13,6 @@ vi.mock("../core/task/Task", () => { public parentTask?: any public apiConfiguration: any public rootTask?: any - public enableBridge?: boolean constructor(opts: any) { this.taskId = opts.historyItem?.id ?? `task-${Math.random().toString(36).slice(2, 8)}` this.parentTask = opts.parentTask @@ -49,7 +48,6 @@ describe("Single-open-task invariant", () => { enableCheckpoints: true, checkpointTimeout: 60, cloudUserInfo: null, - remoteControlEnabled: false, }), removeClineFromStack, addClineToStack, diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index e934342546..9d19248057 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -55,7 +55,7 @@ import { countEnabledMcpTools, } from "@roo-code/types" import { TelemetryService } from "@roo-code/telemetry" -import { CloudService, BridgeOrchestrator } from "@roo-code/cloud" +import { CloudService } from "@roo-code/cloud" // api import { ApiHandler, ApiHandlerCreateMessageMetadata, buildApiHandler } from "../../api" @@ -143,7 +143,6 @@ export interface TaskOptions extends CreateTaskOptions { apiConfiguration: ProviderSettings enableCheckpoints?: boolean checkpointTimeout?: number - enableBridge?: boolean consecutiveMistakeLimit?: number task?: string images?: string[] @@ -332,9 +331,6 @@ export class Task extends EventEmitter implements TaskLike { checkpointService?: RepoPerTaskCheckpointService checkpointServiceInitializing = false - // Task Bridge - enableBridge: boolean - // Message Queue Service public readonly messageQueueService: MessageQueueService private messageQueueStateChangedHandler: (() => void) | undefined @@ -426,7 +422,6 @@ export class Task extends EventEmitter implements TaskLike { apiConfiguration, enableCheckpoints = true, checkpointTimeout = DEFAULT_CHECKPOINT_TIMEOUT_SECONDS, - enableBridge = false, consecutiveMistakeLimit = DEFAULT_CONSECUTIVE_MISTAKE_LIMIT, task, images, @@ -497,7 +492,6 @@ export class Task extends EventEmitter implements TaskLike { this.diffViewProvider = new DiffViewProvider(this.cwd, this) this.enableCheckpoints = enableCheckpoints this.checkpointTimeout = checkpointTimeout - this.enableBridge = enableBridge this.parentTask = parentTask this.taskNumber = taskNumber @@ -1938,16 +1932,6 @@ export class Task extends EventEmitter implements TaskLike { private async startTask(task?: string, images?: string[]): Promise { try { - if (this.enableBridge) { - try { - await BridgeOrchestrator.subscribeToTask(this) - } catch (error) { - console.error( - `[Task#startTask] BridgeOrchestrator.subscribeToTask() failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - } - // `conversationHistory` (for API) and `clineMessages` (for webview) // need to be in sync. // If the extension process were killed, then on restart the @@ -2012,16 +1996,6 @@ export class Task extends EventEmitter implements TaskLike { private async resumeTaskFromHistory() { try { - if (this.enableBridge) { - try { - await BridgeOrchestrator.subscribeToTask(this) - } catch (error) { - console.error( - `[Task#resumeTaskFromHistory] BridgeOrchestrator.subscribeToTask() failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - } - const modifiedClineMessages = await this.getSavedClineMessages() // Remove any resume messages that may have been added before. @@ -2352,16 +2326,6 @@ export class Task extends EventEmitter implements TaskLike { console.error("Error removing event listeners:", error) } - if (this.enableBridge) { - BridgeOrchestrator.getInstance() - ?.unsubscribeFromTask(this.taskId) - .catch((error) => - console.error( - `[Task#dispose] BridgeOrchestrator#unsubscribeFromTask() failed: ${error instanceof Error ? error.message : String(error)}`, - ), - ) - } - // Release any terminals associated with this task. try { // Release any terminals associated with this task. diff --git a/src/core/task/__tests__/grounding-sources.test.ts b/src/core/task/__tests__/grounding-sources.test.ts index f6874a581e..fd82ef8baf 100644 --- a/src/core/task/__tests__/grounding-sources.test.ts +++ b/src/core/task/__tests__/grounding-sources.test.ts @@ -75,14 +75,10 @@ vi.mock("@roo-code/telemetry", () => ({ }, })) -// Mock @roo-code/cloud to prevent socket.io-client initialization issues vi.mock("@roo-code/cloud", () => ({ CloudService: { isEnabled: () => false, }, - BridgeOrchestrator: { - subscribeToTask: vi.fn(), - }, })) // Mock delay to prevent actual delays diff --git a/src/core/task/__tests__/reasoning-preservation.test.ts b/src/core/task/__tests__/reasoning-preservation.test.ts index 3bf2dec298..ea70a26bd3 100644 --- a/src/core/task/__tests__/reasoning-preservation.test.ts +++ b/src/core/task/__tests__/reasoning-preservation.test.ts @@ -75,14 +75,10 @@ vi.mock("@roo-code/telemetry", () => ({ }, })) -// Mock @roo-code/cloud to prevent socket.io-client initialization issues vi.mock("@roo-code/cloud", () => ({ CloudService: { isEnabled: () => false, }, - BridgeOrchestrator: { - subscribeToTask: vi.fn(), - }, })) // Mock delay to prevent actual delays diff --git a/src/core/tools/__tests__/useMcpToolTool.spec.ts b/src/core/tools/__tests__/useMcpToolTool.spec.ts index 27a991456a..5ee826774f 100644 --- a/src/core/tools/__tests__/useMcpToolTool.spec.ts +++ b/src/core/tools/__tests__/useMcpToolTool.spec.ts @@ -676,14 +676,12 @@ describe("useMcpToolTool", () => { mockProviderRef.deref.mockReturnValue({ getMcpHub: () => ({ callTool: vi.fn().mockResolvedValue(mockToolResult), - getAllServers: vi - .fn() - .mockReturnValue([ - { - name: "figma-server", - tools: [{ name: "get_screenshot", description: "Get screenshot" }], - }, - ]), + getAllServers: vi.fn().mockReturnValue([ + { + name: "figma-server", + tools: [{ name: "get_screenshot", description: "Get screenshot" }], + }, + ]), }), postMessageToWebview: vi.fn(), }) @@ -790,14 +788,12 @@ describe("useMcpToolTool", () => { mockProviderRef.deref.mockReturnValue({ getMcpHub: () => ({ callTool: vi.fn().mockResolvedValue(mockToolResult), - getAllServers: vi - .fn() - .mockReturnValue([ - { - name: "figma-server", - tools: [{ name: "get_screenshot", description: "Get screenshot" }], - }, - ]), + getAllServers: vi.fn().mockReturnValue([ + { + name: "figma-server", + tools: [{ name: "get_screenshot", description: "Get screenshot" }], + }, + ]), }), postMessageToWebview: vi.fn(), }) @@ -852,14 +848,12 @@ describe("useMcpToolTool", () => { mockProviderRef.deref.mockReturnValue({ getMcpHub: () => ({ callTool: vi.fn().mockResolvedValue(mockToolResult), - getAllServers: vi - .fn() - .mockReturnValue([ - { - name: "figma-server", - tools: [{ name: "get_screenshots", description: "Get screenshots" }], - }, - ]), + getAllServers: vi.fn().mockReturnValue([ + { + name: "figma-server", + tools: [{ name: "get_screenshots", description: "Get screenshots" }], + }, + ]), }), postMessageToWebview: vi.fn(), }) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index f3fddf22ae..b9da4b4c60 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -49,7 +49,7 @@ import { } from "@roo-code/types" import { aggregateTaskCostsRecursive, type AggregatedCosts } from "./aggregateTaskCosts" import { TelemetryService } from "@roo-code/telemetry" -import { CloudService, BridgeOrchestrator, getRooCodeApiUrl } from "@roo-code/cloud" +import { CloudService, getRooCodeApiUrl } from "@roo-code/cloud" import { Package } from "../../shared/package" import { findLast } from "../../shared/array" @@ -1078,7 +1078,6 @@ export class ClineProvider workspacePath: historyItem.workspace, onCreated: this.taskCreationCallback, startTask: options?.startTask ?? true, - enableBridge: BridgeOrchestrator.isEnabled(cloudUserInfo, taskSyncEnabled), // Preserve the status from the history item to avoid overwriting it when the task saves messages initialStatus: historyItem.status, }) @@ -2194,11 +2193,9 @@ export class ClineProvider includeCurrentCost, maxGitStatusFiles, taskSyncEnabled, - remoteControlEnabled, imageGenerationProvider, openRouterImageApiKey, openRouterImageGenerationSelectedModel, - featureRoomoteControlEnabled, lockApiConfigAcrossModes, } = await this.getState() @@ -2343,11 +2340,9 @@ export class ClineProvider includeCurrentCost: includeCurrentCost ?? true, maxGitStatusFiles: maxGitStatusFiles ?? 0, taskSyncEnabled, - remoteControlEnabled, imageGenerationProvider, openRouterImageApiKey, openRouterImageGenerationSelectedModel, - featureRoomoteControlEnabled, openAiCodexIsAuthenticated: await (async () => { try { const { openAiCodexOAuthManager } = await import("../../integrations/openai-codex/oauth") @@ -2564,32 +2559,9 @@ export class ClineProvider includeCurrentCost: stateValues.includeCurrentCost ?? true, maxGitStatusFiles: stateValues.maxGitStatusFiles ?? 0, taskSyncEnabled, - remoteControlEnabled: (() => { - try { - const cloudSettings = CloudService.instance.getUserSettings() - return cloudSettings?.settings?.extensionBridgeEnabled ?? false - } catch (error) { - console.error( - `[getState] failed to get remote control setting from cloud: ${error instanceof Error ? error.message : String(error)}`, - ) - return false - } - })(), imageGenerationProvider: stateValues.imageGenerationProvider, openRouterImageApiKey: stateValues.openRouterImageApiKey, openRouterImageGenerationSelectedModel: stateValues.openRouterImageGenerationSelectedModel, - featureRoomoteControlEnabled: (() => { - try { - const userSettings = CloudService.instance.getUserSettings() - const hasOrganization = cloudUserInfo?.organizationId != null - return hasOrganization || (userSettings?.features?.roomoteControlEnabled ?? false) - } catch (error) { - console.error( - `[getState] failed to get featureRoomoteControlEnabled: ${error instanceof Error ? error.message : String(error)}`, - ) - return false - } - })(), } } @@ -2786,64 +2758,6 @@ export class ClineProvider return true } - public async remoteControlEnabled(enabled: boolean) { - if (!enabled) { - await BridgeOrchestrator.disconnect() - return - } - - const userInfo = CloudService.instance.getUserInfo() - - if (!userInfo) { - this.log("[ClineProvider#remoteControlEnabled] Failed to get user info, disconnecting") - await BridgeOrchestrator.disconnect() - return - } - - const config = await CloudService.instance.cloudAPI?.bridgeConfig().catch(() => undefined) - - if (!config) { - this.log("[ClineProvider#remoteControlEnabled] Failed to get bridge config") - return - } - - await BridgeOrchestrator.connectOrDisconnect(userInfo, enabled, { - ...config, - provider: this, - sessionId: vscode.env.sessionId, - isCloudAgent: CloudService.instance.isCloudAgent, - }) - - const bridge = BridgeOrchestrator.getInstance() - - if (bridge) { - const currentTask = this.getCurrentTask() - - if (currentTask && !currentTask.enableBridge) { - try { - currentTask.enableBridge = true - await BridgeOrchestrator.subscribeToTask(currentTask) - } catch (error) { - const message = `[ClineProvider#remoteControlEnabled] BridgeOrchestrator.subscribeToTask() failed: ${error instanceof Error ? error.message : String(error)}` - this.log(message) - console.error(message) - } - } - } else { - for (const task of this.clineStack) { - if (task.enableBridge) { - try { - await BridgeOrchestrator.getInstance()?.unsubscribeFromTask(task.taskId) - } catch (error) { - const message = `[ClineProvider#remoteControlEnabled] BridgeOrchestrator#unsubscribeFromTask() failed: ${error instanceof Error ? error.message : String(error)}` - this.log(message) - console.error(message) - } - } - } - } - } - /** * Gets the CodeIndexManager for the current active workspace * @returns CodeIndexManager instance for the current workspace or the default one @@ -2999,15 +2913,8 @@ export class ClineProvider } } - const { - apiConfiguration, - organizationAllowList, - enableCheckpoints, - checkpointTimeout, - experiments, - cloudUserInfo, - remoteControlEnabled, - } = await this.getState() + const { apiConfiguration, organizationAllowList, enableCheckpoints, checkpointTimeout, experiments } = + await this.getState() // Single-open-task invariant: always enforce for user-initiated top-level tasks if (!parentTask) { @@ -3035,7 +2942,6 @@ export class ClineProvider parentTask, taskNumber: this.clineStack.length + 1, onCreated: this.taskCreationCallback, - enableBridge: BridgeOrchestrator.isEnabled(cloudUserInfo, remoteControlEnabled), initialTodos: options.initialTodos, ...options, }) diff --git a/src/core/webview/__tests__/ClineProvider.apiHandlerRebuild.spec.ts b/src/core/webview/__tests__/ClineProvider.apiHandlerRebuild.spec.ts index 9e57ae94b8..87c6ea968c 100644 --- a/src/core/webview/__tests__/ClineProvider.apiHandlerRebuild.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.apiHandlerRebuild.spec.ts @@ -129,9 +129,6 @@ vi.mock("@roo-code/cloud", () => ({ } }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) diff --git a/src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts b/src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts index 8533865031..4bb01347a3 100644 --- a/src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.flicker-free-cancel.spec.ts @@ -78,9 +78,6 @@ vi.mock("@roo-code/cloud", () => ({ isAuthenticated: vi.fn().mockReturnValue(false), }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://api.roo-code.com"), })) diff --git a/src/core/webview/__tests__/ClineProvider.lockApiConfig.spec.ts b/src/core/webview/__tests__/ClineProvider.lockApiConfig.spec.ts index 1a4993b186..2cf9d4cae8 100644 --- a/src/core/webview/__tests__/ClineProvider.lockApiConfig.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.lockApiConfig.spec.ts @@ -110,9 +110,6 @@ vi.mock("@roo-code/cloud", () => ({ } }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) diff --git a/src/core/webview/__tests__/ClineProvider.spec.ts b/src/core/webview/__tests__/ClineProvider.spec.ts index 9400ee34aa..1e26cd45be 100644 --- a/src/core/webview/__tests__/ClineProvider.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.spec.ts @@ -301,9 +301,6 @@ vi.mock("@roo-code/cloud", () => ({ } }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) @@ -554,9 +551,7 @@ describe("ClineProvider", () => { diagnosticsEnabled: true, openRouterImageApiKey: undefined, openRouterImageGenerationSelectedModel: undefined, - remoteControlEnabled: false, taskSyncEnabled: false, - featureRoomoteControlEnabled: false, checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS, } diff --git a/src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts b/src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts index f24cee0786..abef31af89 100644 --- a/src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts @@ -112,9 +112,6 @@ vi.mock("@roo-code/cloud", () => ({ } }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) diff --git a/src/core/webview/__tests__/ClineProvider.sticky-profile.spec.ts b/src/core/webview/__tests__/ClineProvider.sticky-profile.spec.ts index 0bea9b1c36..da2734de87 100644 --- a/src/core/webview/__tests__/ClineProvider.sticky-profile.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.sticky-profile.spec.ts @@ -114,9 +114,6 @@ vi.mock("@roo-code/cloud", () => ({ } }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) diff --git a/src/core/webview/__tests__/ClineProvider.taskHistory.spec.ts b/src/core/webview/__tests__/ClineProvider.taskHistory.spec.ts index b1f29008c4..d1bbd9bca6 100644 --- a/src/core/webview/__tests__/ClineProvider.taskHistory.spec.ts +++ b/src/core/webview/__tests__/ClineProvider.taskHistory.spec.ts @@ -229,9 +229,6 @@ vi.mock("@roo-code/cloud", () => ({ } }, }, - BridgeOrchestrator: { - isEnabled: vi.fn().mockReturnValue(false), - }, getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"), })) diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 4f8d431724..6d17517164 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1352,25 +1352,10 @@ export const webviewMessageHandler = async ( } break } - case "remoteControlEnabled": - try { - await CloudService.instance.updateUserSettings({ extensionBridgeEnabled: message.bool ?? false }) - } catch (error) { - provider.log( - `CloudService#updateUserSettings failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - break - case "taskSyncEnabled": const enabled = message.bool ?? false const updatedSettings: Partial = { taskSyncEnabled: enabled } - // If disabling task sync, also disable remote control. - if (!enabled) { - updatedSettings.extensionBridgeEnabled = false - } - try { await CloudService.instance.updateUserSettings(updatedSettings) } catch (error) { diff --git a/src/extension.ts b/src/extension.ts index 75fff6328f..19c0d70585 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,7 +18,7 @@ if (fs.existsSync(envPath)) { } import type { CloudUserInfo, AuthState } from "@roo-code/types" -import { CloudService, BridgeOrchestrator } from "@roo-code/cloud" +import { CloudService } from "@roo-code/cloud" import { TelemetryService, PostHogTelemetryClient } from "@roo-code/telemetry" import { customToolRegistry } from "@roo-code/core" @@ -200,16 +200,6 @@ export async function activate(context: vscode.ExtensionContext) { authStateChangedHandler = async (data: { state: AuthState; previousState: AuthState }) => { postStateListener() - if (data.state === "logged-out") { - try { - await provider.remoteControlEnabled(false) - } catch (error) { - cloudLogger( - `[authStateChangedHandler] remoteControlEnabled(false) failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - } - // Handle Roo models cache based on auth state (ROO-202) const handleRooModelsCache = async () => { try { @@ -265,36 +255,11 @@ export async function activate(context: vscode.ExtensionContext) { } settingsUpdatedHandler = async () => { - const userInfo = CloudService.instance.getUserInfo() - - if (userInfo && CloudService.instance.cloudAPI) { - try { - provider.remoteControlEnabled(CloudService.instance.isTaskSyncEnabled()) - } catch (error) { - cloudLogger( - `[settingsUpdatedHandler] remoteControlEnabled failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } - } - postStateListener() } userInfoHandler = async ({ userInfo }: { userInfo: CloudUserInfo }) => { postStateListener() - - if (!CloudService.instance.cloudAPI) { - cloudLogger("[userInfoHandler] CloudAPI is not initialized") - return - } - - try { - provider.remoteControlEnabled(CloudService.instance.isTaskSyncEnabled()) - } catch (error) { - cloudLogger( - `[userInfoHandler] remoteControlEnabled failed: ${error instanceof Error ? error.message : String(error)}`, - ) - } } cloudService = await CloudService.createInstance(context, cloudLogger, { @@ -481,12 +446,6 @@ export async function deactivate() { } } - const bridge = BridgeOrchestrator.getInstance() - - if (bridge) { - await bridge.disconnect() - } - await McpServerManager.cleanup(extensionContext) TelemetryService.instance.shutdown() TerminalRegistry.cleanup() diff --git a/src/package.json b/src/package.json index a41b6682e5..3b7b28ebf0 100644 --- a/src/package.json +++ b/src/package.json @@ -521,7 +521,6 @@ "serialize-error": "^12.0.0", "shell-quote": "^1.8.2", "simple-git": "^3.27.0", - "socket.io-client": "^4.8.1", "sound-play": "^1.1.0", "stream-json": "^1.8.0", "string-similarity": "^4.0.4", diff --git a/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts b/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts index f2d9d12dd0..92bf1f8e7d 100644 --- a/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts +++ b/src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts @@ -942,9 +942,7 @@ describe("worktree path comparison", () => { // Second init with stubbed worktree returning a trailing newline const service2 = new RepoPerTaskCheckpointService("trim-test-2", shadowDir, workspaceDir, () => {}) - vitest - .spyOn(service2 as any, "getShadowGitConfigWorktree") - .mockResolvedValue(workspaceDir + "\n") + vitest.spyOn(service2 as any, "getShadowGitConfigWorktree").mockResolvedValue(workspaceDir + "\n") await service2.initShadowGit() } finally { @@ -983,9 +981,7 @@ describe("worktree path comparison", () => { // Second init should throw because core.worktree is missing const service2 = new RepoPerTaskCheckpointService("missing-test-2", shadowDir, workspaceDir, () => {}) - await expect(service2.initShadowGit()).rejects.toThrowError( - /core\.worktree to be set/, - ) + await expect(service2.initShadowGit()).rejects.toThrowError(/core\.worktree to be set/) } finally { vitest.restoreAllMocks() await fs.rm(shadowDir, { recursive: true, force: true }) diff --git a/webview-ui/package.json b/webview-ui/package.json index d72c6a1a2c..7722f4119f 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -33,7 +33,6 @@ "@roo-code/types": "workspace:^", "@tailwindcss/vite": "^4.0.0", "@tanstack/react-query": "^5.68.0", - "@types/qrcode": "^1.5.5", "@vscode/codicons": "^0.0.36", "@vscode/webview-ui-toolkit": "^1.4.0", "axios": "^1.12.0", @@ -55,7 +54,6 @@ "mermaid": "^11.4.1", "posthog-js": "^1.227.2", "pretty-bytes": "^7.0.0", - "qrcode": "^1.5.4", "react": "^18.3.1", "react-dom": "^18.3.1", "react-compiler-runtime": "^1.0.0", diff --git a/webview-ui/src/components/chat/CloudTaskButton.tsx b/webview-ui/src/components/chat/CloudTaskButton.tsx deleted file mode 100644 index 672bf020bb..0000000000 --- a/webview-ui/src/components/chat/CloudTaskButton.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { useState, useEffect, useCallback } from "react" -import { useTranslation } from "react-i18next" -import { Copy, Check, CloudUploadIcon } from "lucide-react" -import QRCode from "qrcode" - -import type { HistoryItem } from "@roo-code/types" - -import { useExtensionState } from "@/context/ExtensionStateContext" -import { useCopyToClipboard } from "@/utils/clipboard" -import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, Input } from "@/components/ui" -import { vscode } from "@/utils/vscode" -import { LucideIconButton } from "./LucideIconButton" - -interface CloudTaskButtonProps { - item?: HistoryItem - disabled?: boolean -} - -export const CloudTaskButton = ({ item, disabled = false }: CloudTaskButtonProps) => { - const [dialogOpen, setDialogOpen] = useState(false) - const { t } = useTranslation() - const { cloudUserInfo, cloudApiUrl } = useExtensionState() - const { copyWithFeedback, showCopyFeedback } = useCopyToClipboard() - const [canvasElement, setCanvasElement] = useState(null) - - // Generate the cloud URL for the task - const cloudTaskUrl = item?.id ? `${cloudApiUrl}/task/${item.id}` : "" - - const generateQRCode = useCallback( - (canvas: HTMLCanvasElement, context: string) => { - if (!cloudTaskUrl) { - // This will run again later when ready - return - } - - QRCode.toCanvas( - canvas, - cloudTaskUrl, - { - width: 140, - margin: 0, - color: { - dark: "#000000", - light: "#FFFFFF", - }, - }, - (error: Error | null | undefined) => { - if (error) { - console.error(`Error generating QR code (${context}):`, error) - } - }, - ) - }, - [cloudTaskUrl], - ) - - // Callback ref to capture canvas element when it mounts - const canvasRef = useCallback( - (node: HTMLCanvasElement | null) => { - if (node) { - setCanvasElement(node) - - // Try to generate QR code immediately when canvas is available - if (dialogOpen) { - generateQRCode(node, "on mount") - } - } else { - setCanvasElement(null) - } - }, - [dialogOpen, generateQRCode], - ) - - // Also generate QR code when dialog opens after canvas is available - useEffect(() => { - if (dialogOpen && canvasElement) { - generateQRCode(canvasElement, "in useEffect") - } - }, [dialogOpen, canvasElement, generateQRCode]) - - if (!cloudUserInfo?.extensionBridgeEnabled || !item?.id) { - return null - } - - return ( - <> - setDialogOpen(true)}> - - - - - {t("chat:task.openInCloud")} - - -
-

{t("chat:task.openInCloudIntro")}

-
-
vscode.postMessage({ type: "openExternal", url: cloudTaskUrl })} - title={t("chat:task.openInCloud")}> - -
-
- -
- - -
-
-
-
- - ) -} diff --git a/webview-ui/src/components/chat/TaskActions.tsx b/webview-ui/src/components/chat/TaskActions.tsx index 74575ddc28..c7401425f6 100644 --- a/webview-ui/src/components/chat/TaskActions.tsx +++ b/webview-ui/src/components/chat/TaskActions.tsx @@ -9,7 +9,6 @@ import { useExtensionState } from "@/context/ExtensionStateContext" import { DeleteTaskDialog } from "../history/DeleteTaskDialog" import { ShareButton } from "./ShareButton" -import { CloudTaskButton } from "./CloudTaskButton" import { CopyIcon, DownloadIcon, Trash2Icon, FileJsonIcon, MessageSquareCodeIcon } from "lucide-react" import { LucideIconButton } from "./LucideIconButton" @@ -64,7 +63,6 @@ export const TaskActions = ({ item, buttonsDisabled }: TaskActionsProps) => { )} - {debug && item?.id && ( <> ({ - default: { - toCanvas: vi.fn((_canvas, _text, _options, callback) => { - // Simulate successful QR code generation - if (callback) { - callback(null) - } - }), - }, -})) - -// Mock react-i18next -vi.mock("react-i18next") - -// Mock the cloud config -vi.mock("@roo-code/cloud/src/config", () => ({ - getRooCodeApiUrl: vi.fn(() => "https://app.roocode.com"), -})) - -// Mock the extension state context -vi.mock("@/context/ExtensionStateContext", () => ({ - ExtensionStateContextProvider: ({ children }: { children: React.ReactNode }) => children, - useExtensionState: vi.fn(), -})) - -// Mock clipboard utility -vi.mock("@/utils/clipboard", () => ({ - useCopyToClipboard: () => ({ - copyWithFeedback: vi.fn(), - showCopyFeedback: false, - }), -})) - -const mockUseTranslation = vi.mocked(useTranslation) -const { useExtensionState } = await import("@/context/ExtensionStateContext") -const mockUseExtensionState = vi.mocked(useExtensionState) - -describe("CloudTaskButton", () => { - const mockT = vi.fn((key: string) => key) - const mockItem = { - id: "test-task-id", - number: 1, - ts: Date.now(), - task: "Test Task", - tokensIn: 100, - tokensOut: 50, - totalCost: 0.01, - } - - beforeEach(() => { - vi.clearAllMocks() - - mockUseTranslation.mockReturnValue({ - t: mockT, - i18n: {} as any, - ready: true, - } as any) - - // Default extension state with bridge enabled - mockUseExtensionState.mockReturnValue({ - cloudUserInfo: { - id: "test-user", - email: "test@example.com", - extensionBridgeEnabled: true, - }, - cloudApiUrl: "https://app.roocode.com", - } as any) - }) - - test("renders cloud task button when extension bridge is enabled", () => { - render() - - const button = screen.getByTestId("cloud-task-button") - expect(button).toBeInTheDocument() - expect(button).toHaveAttribute("aria-label", "chat:task.openInCloud") - }) - - test("does not render when extension bridge is disabled", () => { - mockUseExtensionState.mockReturnValue({ - cloudUserInfo: { - id: "test-user", - email: "test@example.com", - extensionBridgeEnabled: false, - }, - cloudApiUrl: "https://app.roocode.com", - } as any) - - render() - - expect(screen.queryByTestId("cloud-task-button")).not.toBeInTheDocument() - }) - - test("does not render when cloudUserInfo is null", () => { - mockUseExtensionState.mockReturnValue({ - cloudUserInfo: null, - cloudApiUrl: "https://app.roocode.com", - } as any) - - render() - - expect(screen.queryByTestId("cloud-task-button")).not.toBeInTheDocument() - }) - - test("does not render when item has no id", () => { - const itemWithoutId = { ...mockItem, id: undefined } - render() - - expect(screen.queryByTestId("cloud-task-button")).not.toBeInTheDocument() - }) - - test("opens dialog when button is clicked", async () => { - render() - - const button = screen.getByTestId("cloud-task-button") - fireEvent.click(button) - - await waitFor(() => { - expect(screen.getByText("chat:task.openInCloud")).toBeInTheDocument() - }) - }) - - test("displays correct cloud URL in dialog", async () => { - render() - - const button = screen.getByTestId("cloud-task-button") - fireEvent.click(button) - - await waitFor(() => { - const input = screen.getByDisplayValue("https://app.roocode.com/task/test-task-id") - expect(input).toBeInTheDocument() - expect(input).toBeDisabled() - }) - }) - - test("displays intro text in dialog", async () => { - render() - - const button = screen.getByTestId("cloud-task-button") - fireEvent.click(button) - - await waitFor(() => { - expect(screen.getByText("chat:task.openInCloudIntro")).toBeInTheDocument() - }) - }) - - // Note: QR code generation is tested implicitly through the canvas rendering test below - - test("QR code canvas is rendered", async () => { - render() - - const button = screen.getByTestId("cloud-task-button") - fireEvent.click(button) - - await waitFor(() => { - // Canvas element doesn't have a specific aria label, find it directly - const canvas = document.querySelector("canvas") - expect(canvas).toBeInTheDocument() - expect(canvas?.tagName).toBe("CANVAS") - }) - }) - - // Note: Error handling for QR code generation is non-critical as per PR feedback - - test("button is disabled when disabled prop is true", () => { - render() - - const button = screen.getByTestId("cloud-task-button") - expect(button).toBeDisabled() - }) - - test("button is enabled when disabled prop is false", () => { - render() - - const button = screen.getByTestId("cloud-task-button") - expect(button).not.toBeDisabled() - }) - - test("dialog can be closed", async () => { - render() - - // Open dialog - const button = screen.getByTestId("cloud-task-button") - fireEvent.click(button) - - await waitFor(() => { - expect(screen.getByText("chat:task.openInCloud")).toBeInTheDocument() - }) - - // Close dialog by clicking the X button (assuming it exists in Dialog component) - const closeButton = screen.getByRole("button", { name: /close/i }) - fireEvent.click(closeButton) - - await waitFor(() => { - expect(screen.queryByText("chat:task.openInCloud")).not.toBeInTheDocument() - }) - }) - - test("copy button exists in dialog", async () => { - render() - - const button = screen.getByTestId("cloud-task-button") - fireEvent.click(button) - - await waitFor(() => { - // Look for the copy button (it should have a Copy icon) - const copyButtons = screen.getAllByRole("button") - const copyButton = copyButtons.find( - (btn) => btn.querySelector('[class*="lucide"]') || btn.textContent?.includes("Copy"), - ) - expect(copyButton).toBeInTheDocument() - }) - }) - - test("uses correct URL from getRooCodeApiUrl", async () => { - // Mock getRooCodeApiUrl to return a custom URL - vi.doMock("@roo-code/cloud/src/config", () => ({ - getRooCodeApiUrl: vi.fn(() => "https://custom.roocode.com"), - })) - - // Clear module cache and re-import to get the mocked version - vi.resetModules() - - // Since we can't easily test the dynamic import, let's skip this specific test - // The functionality is already covered by the main component using getRooCodeApiUrl - expect(true).toBe(true) - }) -}) diff --git a/webview-ui/src/components/cloud/CloudView.tsx b/webview-ui/src/components/cloud/CloudView.tsx index e8ed9e163c..997997ccd0 100644 --- a/webview-ui/src/components/cloud/CloudView.tsx +++ b/webview-ui/src/components/cloud/CloudView.tsx @@ -9,7 +9,7 @@ import { vscode } from "@src/utils/vscode" import { telemetryClient } from "@src/utils/TelemetryClient" import { ToggleSwitch } from "@/components/ui/toggle-switch" import { renderCloudBenefitsContent } from "./CloudUpsellDialog" -import { ArrowRight, CircleAlert, Info, Lock, TriangleAlert } from "lucide-react" +import { ArrowRight, Info, Lock, TriangleAlert } from "lucide-react" import { cn } from "@/lib/utils" import { Tab, TabContent } from "../common/Tab" import { Button } from "@/components/ui/button" @@ -28,13 +28,7 @@ type CloudViewProps = { export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, organizations = [] }: CloudViewProps) => { const { t } = useAppTranslation() - const { - remoteControlEnabled, - setRemoteControlEnabled, - taskSyncEnabled, - setTaskSyncEnabled, - featureRoomoteControlEnabled, - } = useExtensionState() + const { taskSyncEnabled, setTaskSyncEnabled } = useExtensionState() const wasAuthenticatedRef = useRef(false) const timeoutRef = useRef(null) const manualUrlInputRef = useRef(null) @@ -144,12 +138,6 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, organization } } - const handleRemoteControlToggle = () => { - const newValue = !remoteControlEnabled - setRemoteControlEnabled(newValue) - vscode.postMessage({ type: "remoteControlEnabled", bool: newValue }) - } - const handleTaskSyncToggle = () => { const newValue = !taskSyncEnabled setTaskSyncEnabled(newValue) @@ -219,34 +207,6 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, organization
{t("cloud:taskSyncDescription")}
- - {/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */} - {userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && ( - <> -
- - - {t("cloud:remoteControl")} - -
-
- {t("cloud:remoteControlDescription")} - {!taskSyncEnabled && ( -
- - {t("cloud:remoteControlRequiresTaskSync")} -
- )} -
- - )}
diff --git a/webview-ui/src/components/cloud/__tests__/CloudView.spec.tsx b/webview-ui/src/components/cloud/__tests__/CloudView.spec.tsx index 87f5da9c65..120579e732 100644 --- a/webview-ui/src/components/cloud/__tests__/CloudView.spec.tsx +++ b/webview-ui/src/components/cloud/__tests__/CloudView.spec.tsx @@ -23,10 +23,6 @@ vi.mock("@src/i18n/TranslationContext", () => ({ "cloud:taskSync": "Task sync", "cloud:taskSyncDescription": "Sync your tasks for viewing and sharing on Roo Code Cloud", "cloud:taskSyncManagedByOrganization": "Task sync is managed by your organization", - "cloud:remoteControl": "Roomote Control", - "cloud:remoteControlDescription": - "Enable following and interacting with tasks in this workspace with Roo Code Cloud", - "cloud:remoteControlRequiresTaskSync": "Task sync must be enabled to use Roomote Control", "cloud:usageMetricsAlwaysReported": "Model usage info is always reported when logged in", "cloud:profilePicture": "Profile picture", "cloud:cloudUrlPillLabel": "Roo Code Cloud URL: ", @@ -52,12 +48,8 @@ vi.mock("@src/utils/TelemetryClient", () => ({ // Mock the extension state context const mockExtensionState = { - remoteControlEnabled: false, - setRemoteControlEnabled: vi.fn(), taskSyncEnabled: true, setTaskSyncEnabled: vi.fn(), - featureRoomoteControlEnabled: true, // Default to true for tests - setFeatureRoomoteControlEnabled: vi.fn(), } vi.mock("@src/context/ExtensionStateContext", () => ({ @@ -116,82 +108,6 @@ describe("CloudView", () => { expect(screen.getByText("test@example.com")).toBeInTheDocument() }) - it("should display remote control toggle when user has extension bridge enabled and roomote control enabled", () => { - const mockUserInfo = { - name: "Test User", - email: "test@example.com", - extensionBridgeEnabled: true, - } - - render() - - // Check that the remote control toggle is displayed - expect(screen.getByTestId("remote-control-toggle")).toBeInTheDocument() - expect(screen.getByText("Roomote Control")).toBeInTheDocument() - expect( - screen.getByText("Enable following and interacting with tasks in this workspace with Roo Code Cloud"), - ).toBeInTheDocument() - }) - - it("should not display remote control toggle when user does not have extension bridge enabled", () => { - const mockUserInfo = { - name: "Test User", - email: "test@example.com", - extensionBridgeEnabled: false, - } - - render() - - // Check that the remote control toggle is NOT displayed - expect(screen.queryByTestId("remote-control-toggle")).not.toBeInTheDocument() - expect(screen.queryByText("Roomote Control")).not.toBeInTheDocument() - }) - - it("should not display remote control toggle when roomote control is disabled", () => { - // Temporarily override the mock for this specific test - const originalFeatureRoomoteControlEnabled = mockExtensionState.featureRoomoteControlEnabled - mockExtensionState.featureRoomoteControlEnabled = false - - const mockUserInfo = { - name: "Test User", - email: "test@example.com", - extensionBridgeEnabled: true, // Bridge enabled but roomote control disabled - } - - render() - - // Check that the remote control toggle is NOT displayed - expect(screen.queryByTestId("remote-control-toggle")).not.toBeInTheDocument() - expect(screen.queryByText("Roomote Control")).not.toBeInTheDocument() - - // Restore the original value - mockExtensionState.featureRoomoteControlEnabled = originalFeatureRoomoteControlEnabled - }) - - it("should display remote control toggle for organization users (simulating backend logic)", () => { - // This test simulates what the ClineProvider would do: - // Organization users are treated as having featureRoomoteControlEnabled true - const originalFeatureRoomoteControlEnabled = mockExtensionState.featureRoomoteControlEnabled - mockExtensionState.featureRoomoteControlEnabled = true // Simulating ClineProvider logic for org users - - const mockUserInfo = { - name: "Test User", - email: "test@example.com", - organizationId: "org-123", // User is in an organization - extensionBridgeEnabled: true, - } - - render() - - // Check that the remote control toggle IS displayed for organization users - // (The ClineProvider would set featureRoomoteControlEnabled to true for org users) - expect(screen.getByTestId("remote-control-toggle")).toBeInTheDocument() - expect(screen.getByText("Roomote Control")).toBeInTheDocument() - - // Restore the original value - mockExtensionState.featureRoomoteControlEnabled = originalFeatureRoomoteControlEnabled - }) - it("should not display cloud URL pill when pointing to production", () => { const mockUserInfo = { name: "Test User", diff --git a/webview-ui/src/components/marketplace/MarketplaceView.tsx b/webview-ui/src/components/marketplace/MarketplaceView.tsx index 94c50b80ab..0ab5430eec 100644 --- a/webview-ui/src/components/marketplace/MarketplaceView.tsx +++ b/webview-ui/src/components/marketplace/MarketplaceView.tsx @@ -108,7 +108,7 @@ export function MarketplaceView({ stateManager, onDone, targetTab }: Marketplace onClick={() => onDone?.()} aria-label={t("settings:back")}> - {t("settings:back")} + {t("settings:back")}

{t("marketplace:title")}

diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index ac0b25d8c3..ce7a607d9a 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -94,12 +94,8 @@ export interface ExtensionStateContextType extends ExtensionState { setTerminalOutputPreviewSize: (value: "small" | "medium" | "large") => void mcpEnabled: boolean setMcpEnabled: (value: boolean) => void - remoteControlEnabled: boolean - setRemoteControlEnabled: (value: boolean) => void taskSyncEnabled: boolean setTaskSyncEnabled: (value: boolean) => void - featureRoomoteControlEnabled: boolean - setFeatureRoomoteControlEnabled: (value: boolean) => void setCurrentApiConfigName: (value: string) => void setListApiConfigMeta: (value: ProviderSettingsEntry[]) => void mode: Mode @@ -212,9 +208,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode writeDelayMs: 1000, terminalShellIntegrationTimeout: 4000, mcpEnabled: true, - remoteControlEnabled: false, taskSyncEnabled: false, - featureRoomoteControlEnabled: false, currentApiConfigName: "default", listApiConfigMeta: [], mode: defaultModeSlug, @@ -514,9 +508,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode profileThresholds: state.profileThresholds ?? {}, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs, - remoteControlEnabled: state.remoteControlEnabled ?? false, taskSyncEnabled: state.taskSyncEnabled, - featureRoomoteControlEnabled: state.featureRoomoteControlEnabled ?? false, setExperimentEnabled: (id, enabled) => setState((prevState) => ({ ...prevState, experiments: { ...prevState.experiments, [id]: enabled } })), setApiConfiguration, @@ -554,10 +546,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setState((prevState) => ({ ...prevState, terminalShellIntegrationDisabled: value })), setTerminalZdotdir: (value) => setState((prevState) => ({ ...prevState, terminalZdotdir: value })), setMcpEnabled: (value) => setState((prevState) => ({ ...prevState, mcpEnabled: value })), - setRemoteControlEnabled: (value) => setState((prevState) => ({ ...prevState, remoteControlEnabled: value })), setTaskSyncEnabled: (value) => setState((prevState) => ({ ...prevState, taskSyncEnabled: value }) as any), - setFeatureRoomoteControlEnabled: (value) => - setState((prevState) => ({ ...prevState, featureRoomoteControlEnabled: value })), setCurrentApiConfigName: (value) => setState((prevState) => ({ ...prevState, currentApiConfigName: value })), setListApiConfigMeta, setMode: (value: Mode) => setState((prevState) => ({ ...prevState, mode: value })), diff --git a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx index f55d07e070..2a5e74c40d 100644 --- a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx +++ b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx @@ -214,9 +214,7 @@ describe("mergeExtensionState", () => { hasOpenedModeSelector: false, // Add the new required property maxImageFileSize: 5, maxTotalImageSize: 20, - remoteControlEnabled: false, taskSyncEnabled: false, - featureRoomoteControlEnabled: false, checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS, // Add the checkpoint timeout property maxReadFileLine: -1, } @@ -285,9 +283,7 @@ describe("mergeExtensionState", () => { hasOpenedModeSelector: false, maxImageFileSize: 5, maxTotalImageSize: 20, - remoteControlEnabled: false, taskSyncEnabled: false, - featureRoomoteControlEnabled: false, checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS, maxReadFileLine: -1, } diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index c5e42cf3d8..f029391a37 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Compartició deshabilitada per l'organització", "shareSuccessOrganization": "Enllaç d'organització copiat al porta-retalls", "shareSuccessPublic": "Enllaç públic copiat al porta-retalls", - "openInCloud": "Obrir tasca a Roo Code Cloud", - "openInCloudIntro": "Continua monitoritzant o interactuant amb Roo des de qualsevol lloc. Escaneja, fes clic o copia per obrir.", "openApiHistory": "Obrir historial d'API", "openUiHistory": "Obrir historial d'UI", "backToParentTask": "Tasca principal" diff --git a/webview-ui/src/i18n/locales/ca/cloud.json b/webview-ui/src/i18n/locales/ca/cloud.json index 077cdf42fa..7c0eeff82b 100644 --- a/webview-ui/src/i18n/locales/ca/cloud.json +++ b/webview-ui/src/i18n/locales/ca/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Visita Roo Code Cloud", "taskSync": "Sincronització de tasques", "taskSyncDescription": "Sincronitza les teves tasques per veure-les i compartir-les a Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Permet controlar tasques des de Roo Code Cloud", - "remoteControlRequiresTaskSync": "La sincronització de tasques ha d'estar habilitada per utilitzar Roomote Control", "taskSyncManagedByOrganization": "La sincronització de tasques la gestiona la teva organització", "usageMetricsAlwaysReported": "La informació d'ús del model sempre es reporta quan s'ha iniciat sessió", "cloudUrlPillLabel": "URL de Roo Code Cloud", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 8d5de267f5..2301f966b1 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Freigabe von der Organisation deaktiviert", "shareSuccessOrganization": "Organisationslink in die Zwischenablage kopiert", "shareSuccessPublic": "Öffentlicher Link in die Zwischenablage kopiert", - "openInCloud": "Aufgabe in Roo Code Cloud öffnen", - "openInCloudIntro": "Überwache oder interagiere mit Roo von überall aus. Scanne, klicke oder kopiere zum Öffnen.", "openApiHistory": "API-Verlauf öffnen", "openUiHistory": "UI-Verlauf öffnen", "backToParentTask": "Übergeordnete Aufgabe" diff --git a/webview-ui/src/i18n/locales/de/cloud.json b/webview-ui/src/i18n/locales/de/cloud.json index 70e480cbc4..7ac165b497 100644 --- a/webview-ui/src/i18n/locales/de/cloud.json +++ b/webview-ui/src/i18n/locales/de/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Roo Code Cloud besuchen", "taskSync": "Aufgabensynchronisierung", "taskSyncDescription": "Synchronisiere deine Aufgaben zum Anzeigen und Teilen in Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Ermöglicht die Steuerung von Aufgaben über Roo Code Cloud", - "remoteControlRequiresTaskSync": "Die Aufgabensynchronisierung muss aktiviert sein, um Roomote Control zu verwenden", "taskSyncManagedByOrganization": "Die Aufgabensynchronisierung wird von deiner Organisation verwaltet", "usageMetricsAlwaysReported": "Modellnutzungsinformationen werden bei Anmeldung immer gemeldet", "authWaiting": "Warte auf Abschluss der Authentifizierung...", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index fa23c7e466..4899859e3a 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Sharing disabled by organization", "shareSuccessOrganization": "Organization link copied to clipboard", "shareSuccessPublic": "Public link copied to clipboard", - "openInCloud": "Open task in Roo Code Cloud", - "openInCloudIntro": "Keep monitoring or interacting with Roo from anywhere. Scan, click or copy to open.", "openApiHistory": "Open API History", "openUiHistory": "Open UI History", "backToParentTask": "Parent task" diff --git a/webview-ui/src/i18n/locales/en/cloud.json b/webview-ui/src/i18n/locales/en/cloud.json index 4ba0d5f62d..5f52afdc6a 100644 --- a/webview-ui/src/i18n/locales/en/cloud.json +++ b/webview-ui/src/i18n/locales/en/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Visit Roo Code Cloud", "taskSync": "Task sync", "taskSyncDescription": "Sync your tasks for viewing and sharing on Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Allow controlling tasks from Roo Code Cloud", - "remoteControlRequiresTaskSync": "Task sync must be enabled to use Roomote Control", "taskSyncManagedByOrganization": "Task sync is managed by your organization", "usageMetricsAlwaysReported": "Model usage info is always reported when logged in", "cloudUrlPillLabel": "Roo Code Cloud URL", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 13b61d9585..1b2bd24a55 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Compartir deshabilitado por la organización", "shareSuccessOrganization": "Enlace de organización copiado al portapapeles", "shareSuccessPublic": "Enlace público copiado al portapapeles", - "openInCloud": "Abrir tarea en Roo Code Cloud", - "openInCloudIntro": "Continúa monitoreando o interactuando con Roo desde cualquier lugar. Escanea, haz clic o copia para abrir.", "openApiHistory": "Abrir historial de API", "openUiHistory": "Abrir historial de UI", "backToParentTask": "Tarea principal" diff --git a/webview-ui/src/i18n/locales/es/cloud.json b/webview-ui/src/i18n/locales/es/cloud.json index 1281cccb41..eb0cddc8b9 100644 --- a/webview-ui/src/i18n/locales/es/cloud.json +++ b/webview-ui/src/i18n/locales/es/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Visitar Roo Code Cloud", "taskSync": "Sincronización de tareas", "taskSyncDescription": "Sincroniza tus tareas para verlas y compartirlas en Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Permite controlar tareas desde Roo Code Cloud", - "remoteControlRequiresTaskSync": "La sincronización de tareas debe estar habilitada para usar Roomote Control", "taskSyncManagedByOrganization": "La sincronización de tareas es gestionada por tu organización", "usageMetricsAlwaysReported": "La información de uso del modelo siempre se reporta cuando se ha iniciado sesión", "authWaiting": "Esperando que se complete la autenticación...", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index bf9c524cc2..adb77f40b9 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Partage désactivé par l'organisation", "shareSuccessOrganization": "Lien d'organisation copié dans le presse-papiers", "shareSuccessPublic": "Lien public copié dans le presse-papiers", - "openInCloud": "Ouvrir la tâche dans Roo Code Cloud", - "openInCloudIntro": "Continue à surveiller ou interagir avec Roo depuis n'importe où. Scanne, clique ou copie pour ouvrir.", "openApiHistory": "Ouvrir l'historique de l'API", "openUiHistory": "Ouvrir l'historique de l'UI", "backToParentTask": "Tâche parente" diff --git a/webview-ui/src/i18n/locales/fr/cloud.json b/webview-ui/src/i18n/locales/fr/cloud.json index 8e031aaad8..ac8a8d1537 100644 --- a/webview-ui/src/i18n/locales/fr/cloud.json +++ b/webview-ui/src/i18n/locales/fr/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Visiter Roo Code Cloud", "taskSync": "Synchronisation des tâches", "taskSyncDescription": "Synchronisez vos tâches pour les visualiser et les partager sur Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Permet de contrôler les tâches depuis Roo Code Cloud", - "remoteControlRequiresTaskSync": "La synchronisation des tâches doit être activée pour utiliser Roomote Control", "taskSyncManagedByOrganization": "La synchronisation des tâches est gérée par votre organisation", "usageMetricsAlwaysReported": "Les informations d'utilisation du modèle sont toujours signalées lors de la connexion", "authWaiting": "En attente de la fin de l'authentification...", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 71c70c4201..b58481f910 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "संगठन द्वारा साझाकरण अक्षम किया गया", "shareSuccessOrganization": "संगठन लिंक क्लिपबोर्ड में कॉपी किया गया", "shareSuccessPublic": "सार्वजनिक लिंक क्लिपबोर्ड में कॉपी किया गया", - "openInCloud": "Roo Code Cloud में कार्य खोलें", - "openInCloudIntro": "कहीं से भी Roo की निगरानी या इंटरैक्ट करना जारी रखें। खोलने के लिए स्कैन करें, क्लिक करें या कॉपी करें।", "openApiHistory": "API इतिहास खोलें", "openUiHistory": "UI इतिहास खोलें", "backToParentTask": "मूल कार्य" diff --git a/webview-ui/src/i18n/locales/hi/cloud.json b/webview-ui/src/i18n/locales/hi/cloud.json index ecf6e1f101..c573284e1d 100644 --- a/webview-ui/src/i18n/locales/hi/cloud.json +++ b/webview-ui/src/i18n/locales/hi/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Roo Code Cloud पर जाएं", "taskSync": "कार्य सिंक", "taskSyncDescription": "Roo Code Cloud पर देखने और साझा करने के लिए अपने कार्यों को सिंक करें", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Roo Code Cloud से कार्यों को नियंत्रित करने की अनुमति दें", - "remoteControlRequiresTaskSync": "Roomote Control का उपयोग करने के लिए कार्य सिंक सक्षम होना चाहिए", "taskSyncManagedByOrganization": "कार्य सिंक आपके संगठन द्वारा प्रबंधित किया जाता है", "usageMetricsAlwaysReported": "लॉग इन होने पर मॉडल उपयोग जानकारी हमेशा रिपोर्ट की जाती है", "authWaiting": "प्रमाणीकरण पूरा होने की प्रतीक्षा कर रहे हैं...", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index f442d6fe10..98b08d4877 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Berbagi dinonaktifkan oleh organisasi", "shareSuccessOrganization": "Tautan organisasi disalin ke clipboard", "shareSuccessPublic": "Tautan publik disalin ke clipboard", - "openInCloud": "Buka tugas di Roo Code Cloud", - "openInCloudIntro": "Terus pantau atau berinteraksi dengan Roo dari mana saja. Pindai, klik atau salin untuk membuka.", "openApiHistory": "Buka Riwayat API", "openUiHistory": "Buka Riwayat UI", "backToParentTask": "Tugas Induk" diff --git a/webview-ui/src/i18n/locales/id/cloud.json b/webview-ui/src/i18n/locales/id/cloud.json index 3e3e293f97..5e8000c7b8 100644 --- a/webview-ui/src/i18n/locales/id/cloud.json +++ b/webview-ui/src/i18n/locales/id/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Kunjungi Roo Code Cloud", "taskSync": "Sinkronisasi tugas", "taskSyncDescription": "Sinkronkan tugas Anda untuk melihat dan berbagi di Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Izinkan mengontrol tugas dari Roo Code Cloud", - "remoteControlRequiresTaskSync": "Sinkronisasi tugas harus diaktifkan untuk menggunakan Roomote Control", "taskSyncManagedByOrganization": "Sinkronisasi tugas dikelola oleh organisasi Anda", "usageMetricsAlwaysReported": "Informasi penggunaan model selalu dilaporkan saat masuk", "authWaiting": "Menunggu autentikasi selesai...", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 28f8eba54d..b2b9adf685 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Condivisione disabilitata dall'organizzazione", "shareSuccessOrganization": "Link organizzazione copiato negli appunti", "shareSuccessPublic": "Link pubblico copiato negli appunti", - "openInCloud": "Apri attività in Roo Code Cloud", - "openInCloudIntro": "Continua a monitorare o interagire con Roo da qualsiasi luogo. Scansiona, clicca o copia per aprire.", "openApiHistory": "Apri cronologia API", "openUiHistory": "Apri cronologia UI", "backToParentTask": "Attività principale" diff --git a/webview-ui/src/i18n/locales/it/cloud.json b/webview-ui/src/i18n/locales/it/cloud.json index cd575786d5..b0c0dceec2 100644 --- a/webview-ui/src/i18n/locales/it/cloud.json +++ b/webview-ui/src/i18n/locales/it/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Visita Roo Code Cloud", "taskSync": "Sincronizzazione attività", "taskSyncDescription": "Sincronizza le tue attività per visualizzarle e condividerle su Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Consenti il controllo delle attività da Roo Code Cloud", - "remoteControlRequiresTaskSync": "La sincronizzazione delle attività deve essere abilitata per utilizzare Roomote Control", "taskSyncManagedByOrganization": "La sincronizzazione delle attività è gestita dalla tua organizzazione", "usageMetricsAlwaysReported": "Le informazioni sull'utilizzo del modello vengono sempre segnalate quando si è connessi", "authWaiting": "In attesa del completamento dell'autenticazione...", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 6d581dbea4..e0e8ff2460 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "組織により共有が無効化されています", "shareSuccessOrganization": "組織リンクをクリップボードにコピーしました", "shareSuccessPublic": "公開リンクをクリップボードにコピーしました", - "openInCloud": "Roo Code Cloudでタスクを開く", - "openInCloudIntro": "どこからでもRooの監視や操作を続けられます。スキャン、クリック、またはコピーして開いてください。", "openApiHistory": "API履歴を開く", "openUiHistory": "UI履歴を開く", "backToParentTask": "親タスク" diff --git a/webview-ui/src/i18n/locales/ja/cloud.json b/webview-ui/src/i18n/locales/ja/cloud.json index d25f61b78c..6474bd8fe0 100644 --- a/webview-ui/src/i18n/locales/ja/cloud.json +++ b/webview-ui/src/i18n/locales/ja/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Roo Code Cloudを訪問", "taskSync": "タスク同期", "taskSyncDescription": "Roo Code Cloudでタスクを表示・共有するために同期", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Roo Code Cloudからタスクを制御できるようにする", - "remoteControlRequiresTaskSync": "Roomote Controlを使用するにはタスク同期を有効にする必要があります", "taskSyncManagedByOrganization": "タスク同期は組織によって管理されます", "usageMetricsAlwaysReported": "ログイン時にはモデル使用情報が常に報告されます", "authWaiting": "認証完了をお待ちください...", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 415481f804..ff3e419975 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "조직에서 공유가 비활성화됨", "shareSuccessOrganization": "조직 링크가 클립보드에 복사되었습니다", "shareSuccessPublic": "공개 링크가 클립보드에 복사되었습니다", - "openInCloud": "Roo Code Cloud에서 작업 열기", - "openInCloudIntro": "어디서나 Roo를 계속 모니터링하거나 상호작용할 수 있습니다. 스캔, 클릭 또는 복사하여 열기.", "openApiHistory": "API 기록 열기", "openUiHistory": "UI 기록 열기", "backToParentTask": "상위 작업" diff --git a/webview-ui/src/i18n/locales/ko/cloud.json b/webview-ui/src/i18n/locales/ko/cloud.json index 6aba5f58ba..c0731e3bf4 100644 --- a/webview-ui/src/i18n/locales/ko/cloud.json +++ b/webview-ui/src/i18n/locales/ko/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Roo Code Cloud 방문", "taskSync": "작업 동기화", "taskSyncDescription": "Roo Code Cloud에서 보고 공유할 수 있도록 작업을 동기화", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Roo Code Cloud에서 작업을 제어할 수 있도록 허용", - "remoteControlRequiresTaskSync": "Roomote Control을 사용하려면 작업 동기화가 활성화되어야 합니다", "taskSyncManagedByOrganization": "작업 동기화는 조직에서 관리합니다", "usageMetricsAlwaysReported": "로그인 시 모델 사용 정보가 항상 보고됩니다", "authWaiting": "인증 완료를 기다리는 중...", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 1095670a35..d79c95d9e9 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Delen uitgeschakeld door organisatie", "shareSuccessOrganization": "Organisatielink gekopieerd naar klembord", "shareSuccessPublic": "Openbare link gekopieerd naar klembord", - "openInCloud": "Taak openen in Roo Code Cloud", - "openInCloudIntro": "Blijf Roo vanaf elke locatie monitoren of ermee interacteren. Scan, klik of kopieer om te openen.", "openApiHistory": "API-geschiedenis openen", "openUiHistory": "UI-geschiedenis openen", "backToParentTask": "Bovenliggende taak" diff --git a/webview-ui/src/i18n/locales/nl/cloud.json b/webview-ui/src/i18n/locales/nl/cloud.json index dad073fdc2..5a4a5c4db2 100644 --- a/webview-ui/src/i18n/locales/nl/cloud.json +++ b/webview-ui/src/i18n/locales/nl/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Bezoek Roo Code Cloud", "taskSync": "Taaksynchronisatie", "taskSyncDescription": "Synchroniseer je taken om ze te bekijken en delen op Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Sta toe taken te besturen vanuit Roo Code Cloud", - "remoteControlRequiresTaskSync": "Taaksynchronisatie moet ingeschakeld zijn om Roomote Control te gebruiken", "taskSyncManagedByOrganization": "Taaksynchronisatie wordt beheerd door uw organisatie", "usageMetricsAlwaysReported": "Modelgebruiksinformatie wordt altijd gerapporteerd wanneer ingelogd", "authWaiting": "Wachten tot authenticatie voltooid is...", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 37998d0d16..ddf225bae0 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Udostępnianie wyłączone przez organizację", "shareSuccessOrganization": "Link organizacji skopiowany do schowka", "shareSuccessPublic": "Link publiczny skopiowany do schowka", - "openInCloud": "Otwórz zadanie w Roo Code Cloud", - "openInCloudIntro": "Kontynuuj monitorowanie lub interakcję z Roo z dowolnego miejsca. Zeskanuj, kliknij lub skopiuj, aby otworzyć.", "openApiHistory": "Otwórz historię API", "openUiHistory": "Otwórz historię UI", "backToParentTask": "Zadanie nadrzędne" diff --git a/webview-ui/src/i18n/locales/pl/cloud.json b/webview-ui/src/i18n/locales/pl/cloud.json index 827eaa70ef..3a7eac8cdb 100644 --- a/webview-ui/src/i18n/locales/pl/cloud.json +++ b/webview-ui/src/i18n/locales/pl/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Odwiedź Roo Code Cloud", "taskSync": "Synchronizacja zadań", "taskSyncDescription": "Synchronizuj swoje zadania, aby przeglądać i udostępniać je w Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Pozwól kontrolować zadania z Roo Code Cloud", - "remoteControlRequiresTaskSync": "Synchronizacja zadań musi być włączona, aby używać Roomote Control", "taskSyncManagedByOrganization": "Synchronizacja zadań jest zarządzana przez Twoją organizację", "usageMetricsAlwaysReported": "Informacje o użyciu modelu są zawsze raportowane po zalogowaniu", "authWaiting": "Oczekiwanie na zakończenie uwierzytelniania...", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index afda26c2e6..b0ad26bfbd 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Compartilhamento desabilitado pela organização", "shareSuccessOrganization": "Link da organização copiado para a área de transferência", "shareSuccessPublic": "Link público copiado para a área de transferência", - "openInCloud": "Abrir tarefa no Roo Code Cloud", - "openInCloudIntro": "Continue monitorando ou interagindo com Roo de qualquer lugar. Escaneie, clique ou copie para abrir.", "openApiHistory": "Abrir histórico da API", "openUiHistory": "Abrir histórico da UI", "backToParentTask": "Tarefa pai" diff --git a/webview-ui/src/i18n/locales/pt-BR/cloud.json b/webview-ui/src/i18n/locales/pt-BR/cloud.json index 1876f1a666..08ee2f205f 100644 --- a/webview-ui/src/i18n/locales/pt-BR/cloud.json +++ b/webview-ui/src/i18n/locales/pt-BR/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Visitar Roo Code Cloud", "taskSync": "Sincronização de tarefas", "taskSyncDescription": "Sincronize suas tarefas para visualizar e compartilhar no Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Permite controlar tarefas a partir do Roo Code Cloud", - "remoteControlRequiresTaskSync": "A sincronização de tarefas deve estar habilitada para usar o Roomote Control", "taskSyncManagedByOrganization": "A sincronização de tarefas é gerenciada pela sua organização", "usageMetricsAlwaysReported": "As informações de uso do modelo são sempre reportadas quando conectado", "authWaiting": "Aguardando conclusão da autenticação...", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index b66e9c40a2..3681d3d648 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Обмен отключен организацией", "shareSuccessOrganization": "Ссылка организации скопирована в буфер обмена", "shareSuccessPublic": "Публичная ссылка скопирована в буфер обмена", - "openInCloud": "Открыть задачу в Roo Code Cloud", - "openInCloudIntro": "Продолжай отслеживать или взаимодействовать с Roo откуда угодно. Отсканируй, нажми или скопируй для открытия.", "openApiHistory": "Открыть историю API", "openUiHistory": "Открыть историю UI", "backToParentTask": "Родительская задача" diff --git a/webview-ui/src/i18n/locales/ru/cloud.json b/webview-ui/src/i18n/locales/ru/cloud.json index 438a1a90fd..20aa6d4506 100644 --- a/webview-ui/src/i18n/locales/ru/cloud.json +++ b/webview-ui/src/i18n/locales/ru/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Посетить Roo Code Cloud", "taskSync": "Синхронизация задач", "taskSyncDescription": "Синхронизируйте свои задачи для просмотра и обмена в Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Разрешить управление задачами из Roo Code Cloud", - "remoteControlRequiresTaskSync": "Для использования Roomote Control должна быть включена синхронизация задач", "taskSyncManagedByOrganization": "Синхронизация задач управляется вашей организацией", "usageMetricsAlwaysReported": "Информация об использовании модели всегда сообщается при входе в систему", "authWaiting": "Ожидание завершения аутентификации...", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 647f57bf17..216d8e0797 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Paylaşım kuruluş tarafından devre dışı bırakıldı", "shareSuccessOrganization": "Organizasyon bağlantısı panoya kopyalandı", "shareSuccessPublic": "Genel bağlantı panoya kopyalandı", - "openInCloud": "Görevi Roo Code Cloud'da aç", - "openInCloudIntro": "Roo'yu her yerden izlemeye veya etkileşime devam et. Açmak için tara, tıkla veya kopyala.", "openApiHistory": "API Geçmişini Aç", "openUiHistory": "UI Geçmişini Aç", "backToParentTask": "Üst görev" diff --git a/webview-ui/src/i18n/locales/tr/cloud.json b/webview-ui/src/i18n/locales/tr/cloud.json index 24e767a6c3..8c14c744a7 100644 --- a/webview-ui/src/i18n/locales/tr/cloud.json +++ b/webview-ui/src/i18n/locales/tr/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Roo Code Cloud'u ziyaret et", "taskSync": "Görev senkronizasyonu", "taskSyncDescription": "Görevlerinizi Roo Code Cloud'da görüntülemek ve paylaşmak için senkronize edin", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Roo Code Cloud'dan görevleri kontrol etmeye izin ver", - "remoteControlRequiresTaskSync": "Roomote Control'ü kullanmak için görev senkronizasyonu etkinleştirilmelidir", "taskSyncManagedByOrganization": "Görev senkronizasyonu kuruluşunuz tarafından yönetilir", "usageMetricsAlwaysReported": "Oturum açıldığında model kullanım bilgileri her zaman raporlanır", "authWaiting": "Kimlik doğrulama tamamlanması bekleniyor...", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 9d56f1885e..83cb5a03f7 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "Chia sẻ bị tổ chức vô hiệu hóa", "shareSuccessOrganization": "Liên kết tổ chức đã được sao chép vào clipboard", "shareSuccessPublic": "Liên kết công khai đã được sao chép vào clipboard", - "openInCloud": "Mở tác vụ trong Roo Code Cloud", - "openInCloudIntro": "Tiếp tục theo dõi hoặc tương tác với Roo từ bất cứ đâu. Quét, nhấp hoặc sao chép để mở.", "openApiHistory": "Mở lịch sử API", "openUiHistory": "Mở lịch sử UI", "backToParentTask": "Nhiệm vụ cha" diff --git a/webview-ui/src/i18n/locales/vi/cloud.json b/webview-ui/src/i18n/locales/vi/cloud.json index e9c4dee720..45dd092b75 100644 --- a/webview-ui/src/i18n/locales/vi/cloud.json +++ b/webview-ui/src/i18n/locales/vi/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "Truy cập Roo Code Cloud", "taskSync": "Đồng bộ tác vụ", "taskSyncDescription": "Đồng bộ tác vụ của bạn để xem và chia sẻ trên Roo Code Cloud", - "remoteControl": "Roomote Control", - "remoteControlDescription": "Cho phép điều khiển tác vụ từ Roo Code Cloud", - "remoteControlRequiresTaskSync": "Đồng bộ tác vụ phải được bật để sử dụng Roomote Control", "taskSyncManagedByOrganization": "Việc đồng bộ hóa công việc được quản lý bởi tổ chức của bạn", "usageMetricsAlwaysReported": "Thông tin sử dụng mô hình luôn được báo cáo khi đăng nhập", "authWaiting": "Đang chờ hoàn tất xác thực...", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 22994cbb07..049a06a7ce 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "组织已禁用分享功能", "shareSuccessOrganization": "组织链接已复制到剪贴板", "shareSuccessPublic": "公开链接已复制到剪贴板", - "openInCloud": "在 Roo Code Cloud 中打开任务", - "openInCloudIntro": "从任何地方继续监控或与 Roo 交互。扫描、点击或复制以打开。", "openApiHistory": "打开 API 历史", "openUiHistory": "打开 UI 历史", "backToParentTask": "父任务" diff --git a/webview-ui/src/i18n/locales/zh-CN/cloud.json b/webview-ui/src/i18n/locales/zh-CN/cloud.json index 29b4f98e4c..560218c56f 100644 --- a/webview-ui/src/i18n/locales/zh-CN/cloud.json +++ b/webview-ui/src/i18n/locales/zh-CN/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "访问 Roo Code Cloud", "taskSync": "任务同步", "taskSyncDescription": "同步您的任务以在 Roo Code Cloud 上查看和共享", - "remoteControl": "Roomote Control", - "remoteControlDescription": "允许从 Roo Code Cloud 控制任务", - "remoteControlRequiresTaskSync": "必须启用任务同步才能使用 Roomote Control", "taskSyncManagedByOrganization": "任务同步由您的组织管理", "usageMetricsAlwaysReported": "登录时始终报告模型使用信息", "authWaiting": "等待身份验证完成...", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 00f57d369d..e01b86f52b 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -25,8 +25,6 @@ "sharingDisabledByOrganization": "組織已停用分享功能", "shareSuccessOrganization": "組織連結已複製到剪貼簿", "shareSuccessPublic": "公開連結已複製到剪貼簿", - "openInCloud": "在 Roo Code Cloud 中開啟工作", - "openInCloudIntro": "從任何地方繼續監控或與 Roo 互動。掃描、點選或複製即可開啟。", "openApiHistory": "開啟 API 歷史紀錄", "openUiHistory": "開啟 UI 歷史紀錄", "backToParentTask": "上層工作" diff --git a/webview-ui/src/i18n/locales/zh-TW/cloud.json b/webview-ui/src/i18n/locales/zh-TW/cloud.json index 1ade83d3e3..032c18ed91 100644 --- a/webview-ui/src/i18n/locales/zh-TW/cloud.json +++ b/webview-ui/src/i18n/locales/zh-TW/cloud.json @@ -15,9 +15,6 @@ "visitCloudWebsite": "造訪 Roo Code Cloud", "taskSync": "任務同步", "taskSyncDescription": "同步工作以在 Roo Code Cloud 上檢視和分享", - "remoteControl": "Roomote Control", - "remoteControlDescription": "允許從 Roo Code Cloud 控制工作", - "remoteControlRequiresTaskSync": "必須啟用任務同步才能使用 Roomote Control", "taskSyncManagedByOrganization": "工作同步由您的組織管理", "usageMetricsAlwaysReported": "登入時會一律回報模型使用資訊", "authWaiting": "等待瀏覽器驗證完成...",