diff --git a/README.de.md b/README.de.md index f08127048..a3bcd2f8b 100644 --- a/README.de.md +++ b/README.de.md @@ -64,7 +64,7 @@ Passt sich automatisch an die Fähigkeiten jedes Modells an. Claude erhält voll ### 🔌 MCP-Server -Ein-Klick-Installation in Claude Code, Codex, Gemini, OpenCode, Kiro oder Copilot CLIs. Designen Sie aus Ihrem Terminal — `.op`-Dateien über jeden MCP-kompatiblen Agenten lesen, erstellen und bearbeiten. +Ein-Klick-Installation in Claude Code, Codex, OpenCode, Kiro oder Copilot CLIs. Designen Sie aus Ihrem Terminal — `.op`-Dateien über jeden MCP-kompatiblen Agenten lesen, erstellen und bearbeiten. @@ -125,7 +125,7 @@ Getaggte Rust-Releases veröffentlichen ein einzelnes Web-Host-Image. Die frühe | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust-Web-Host, wasm bundle und CanvasKit-Assets | -Die Web-UI zeigt nur integrierte Agent-Profile; Claude/Codex/OpenCode/Copilot/Gemini-CLI-Tools sind nicht in Docker-Images enthalten. +Die Web-UI zeigt nur integrierte Agent-Profile; Claude/Codex/OpenCode/Copilot-CLI-Tools sind nicht in Docker-Images enthalten. **Ausführen:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | In den Agenteneinstellungen verbinden (`Cmd+,`) | | **OpenCode** | In den Agenteneinstellungen verbinden (`Cmd+,`) | | **GitHub Copilot** | `copilot login` dann in den Agenteneinstellungen verbinden (`Cmd+,`) | -| **Gemini CLI** | In den Agenteneinstellungen verbinden (`Cmd+,`) | **Modell-Fähigkeitsprofile** — passt Prompts, Thinking-Modus und Timeouts automatisch pro Modellstufe an. Modelle der Vollstufe (Claude) erhalten vollständige Prompts; Standardstufe (GPT-4o, Gemini, DeepSeek) deaktiviert Thinking; Basisstufe (MiniMax, Qwen, Llama, Mistral) erhält vereinfachte verschachtelte JSON-Prompts für maximale Zuverlässigkeit. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP-Server** -- Eingebauter MCP-Server (`op-mcp`-Crate) — Ein-Klick-Installation in Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLIs +- Eingebauter MCP-Server (`op-mcp`-Crate) — Ein-Klick-Installation in Claude Code / Codex / OpenCode / Kiro / Copilot CLIs - Kein Node.js erforderlich — stdio-Transport über die Desktop-Binärdatei (`--mcp `), plus ein Live-HTTP-Endpunkt (`127.0.0.1:/mcp`) der laufenden App - Design-Automatisierung vom Terminal aus: `.op`-Dateien über jeden MCP-kompatiblen Agenten lesen, erstellen und bearbeiten - **Mehrstufiger Design-Workflow** — `design_skeleton` → `design_content` → `design_refine` für hochwertigere mehrteilige Designs @@ -229,7 +228,7 @@ Unterstützt Inline-Strings, `@filepath` und stdin (`-`). Funktioniert mit Deskt - Mehrstufiger Workflow — `design_skeleton` → `design_content` → `design_refine` mit fokussierten Prompts pro Phase - Style Guides — 50+ eingebaute Stile (glassmorphism, brutalist, retro usw.) mit tag-basiertem Fuzzy-Matching, eingebunden in Planung und Generierung - Multi-Modell-Fähigkeitsprofile — passt Denkmodus, Aufwand und Promptform automatisch an die Modellstufe an -- Integrierte Agent-Laufzeit (Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini-Anbieter +- Integrierte Agent-Laufzeit (Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot und Google Gemini API - Anthropic-Format-Passthrough für chinesische LLM-Anbieter — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Git-Integration** diff --git a/README.es.md b/README.es.md index c989f5b11..eb0f491da 100644 --- a/README.es.md +++ b/README.es.md @@ -64,7 +64,7 @@ Se adapta automáticamente a las capacidades de cada modelo. Claude recibe promp ### 🔌 Servidor MCP -Instalación con un clic en Claude Code, Codex, Gemini, OpenCode, Kiro o Copilot CLIs. Diseña desde tu terminal — lee, crea y modifica archivos `.op` a través de cualquier agente compatible con MCP. +Instalación con un clic en Claude Code, Codex, OpenCode, Kiro o Copilot CLIs. Diseña desde tu terminal — lee, crea y modifica archivos `.op` a través de cualquier agente compatible con MCP. @@ -125,7 +125,7 @@ Las releases Rust etiquetadas publican una única imagen de web host. Las imáge | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle y recursos de CanvasKit | -La UI web expone solo perfiles de agente integrados; las herramientas Claude/Codex/OpenCode/Copilot/Gemini CLI no se incluyen en las imágenes Docker. +La UI web expone solo perfiles de agente integrados; las herramientas Claude/Codex/OpenCode/Copilot CLI no se incluyen en las imágenes Docker. **Ejecutar:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Conectar en Configuración de Agente (`Cmd+,`) | | **OpenCode** | Conectar en Configuración de Agente (`Cmd+,`) | | **GitHub Copilot** | `copilot login` y luego conectar en Configuración de Agente (`Cmd+,`) | -| **Gemini CLI** | Conectar en Configuración de Agente (`Cmd+,`) | **Perfiles de Capacidad de Modelos** — adapta automáticamente los prompts, el modo de pensamiento y los tiempos de espera según el nivel del modelo. Los modelos de nivel completo (Claude) reciben prompts completos; los de nivel estándar (GPT-4o, Gemini, DeepSeek) desactivan el pensamiento; los de nivel básico (MiniMax, Qwen, Llama, Mistral) reciben prompts simplificados de JSON anidado para máxima fiabilidad. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **Servidor MCP** -- Servidor MCP integrado (crate `op-mcp`) — instalación con un clic en Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLIs +- Servidor MCP integrado (crate `op-mcp`) — instalación con un clic en Claude Code / Codex / OpenCode / Kiro / Copilot CLIs - No requiere Node.js — transporte stdio a través del binario de escritorio (`--mcp `), además de un endpoint HTTP en vivo (`127.0.0.1:/mcp`) desde la app en ejecución - Automatización de diseño desde la terminal: leer, crear y modificar archivos `.op` a través de cualquier agente compatible con MCP - **Flujo de diseño por capas** — `design_skeleton` → `design_content` → `design_refine` para diseños multisección de mayor fidelidad @@ -229,7 +228,7 @@ Admite cadenas inline, `@filepath` y stdin (`-`). Funciona con la app de escrito - Flujo de trabajo por capas — `design_skeleton` → `design_content` → `design_refine` con prompts enfocados por fase - Guías de estilo — más de 50 estilos integrados (glassmorphism, brutalist, retro, etc.) con coincidencia difusa basada en etiquetas, integrada en planificación y generación - Perfiles multi-modelo — adapta automáticamente el modo de pensamiento, el esfuerzo y la forma del prompt por nivel de modelo -- Runtime de agente integrado (Rust) + proveedores Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Runtime de agente integrado (Rust) + proveedores Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot y Google Gemini API - Passthrough en formato Anthropic para proveedores de LLM chinos — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Integración con Git** diff --git a/README.fr.md b/README.fr.md index f476333f7..22c96ab45 100644 --- a/README.fr.md +++ b/README.fr.md @@ -64,7 +64,7 @@ S'adapte automatiquement aux capacités de chaque modèle. Claude obtient des pr ### 🔌 Serveur MCP -Installation en un clic dans les CLI Claude Code, Codex, Gemini, OpenCode, Kiro ou Copilot. Designez depuis votre terminal — lisez, créez et modifiez des fichiers `.op` via tout agent compatible MCP. +Installation en un clic dans les CLI Claude Code, Codex, OpenCode, Kiro ou Copilot. Designez depuis votre terminal — lisez, créez et modifiez des fichiers `.op` via tout agent compatible MCP. @@ -125,7 +125,7 @@ Les releases Rust taguées publient une seule image web host. Les anciennes imag | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle et ressources CanvasKit | -L'interface web expose uniquement les profils d'agents intégrés ; les outils Claude/Codex/OpenCode/Copilot/Gemini CLI ne sont pas inclus dans les images Docker. +L'interface web expose uniquement les profils d'agents intégrés ; les outils Claude/Codex/OpenCode/Copilot CLI ne sont pas inclus dans les images Docker. **Exécuter :** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Connecter dans les Paramètres de l'agent (`Cmd+,`) | | **OpenCode** | Connecter dans les Paramètres de l'agent (`Cmd+,`) | | **GitHub Copilot** | `copilot login` puis connecter dans les Paramètres de l'agent (`Cmd+,`) | -| **Gemini CLI** | Connecter dans les Paramètres de l'agent (`Cmd+,`) | **Profils de capacités des modèles** — adapte automatiquement les prompts, le mode de réflexion et les délais d'attente par niveau de modèle. Les modèles de niveau complet (Claude) reçoivent des prompts complets ; le niveau standard (GPT-4o, Gemini, DeepSeek) désactive la réflexion ; le niveau basique (MiniMax, Qwen, Llama, Mistral) reçoit des prompts JSON imbriqués simplifiés pour une fiabilité maximale. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **Serveur MCP** -- Serveur MCP intégré (crate `op-mcp`) — installation en un clic dans les CLI Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot +- Serveur MCP intégré (crate `op-mcp`) — installation en un clic dans les CLI Claude Code / Codex / OpenCode / Kiro / Copilot - Aucun besoin de Node.js — transport stdio via le binaire de bureau (`--mcp `), plus un point de terminaison HTTP en direct (`127.0.0.1:/mcp`) depuis l'application en cours d'exécution - Automatisation du design depuis le terminal : lire, créer et modifier des fichiers `.op` via tout agent compatible MCP - **Workflow de design en couches** — `design_skeleton` → `design_content` → `design_refine` pour des designs multi-sections de plus haute fidélité @@ -229,7 +228,7 @@ Prend en charge les chaînes en ligne, `@filepath` et stdin (`-`). Fonctionne av - Workflow en couches — `design_skeleton` → `design_content` → `design_refine` avec des prompts ciblés par phase - Guides de style — plus de 50 styles intégrés (glassmorphism, brutalist, retro, etc.) avec appariement flou basé sur les tags, intégrés dans la planification et la génération - Profils de capacités multi-modèles — adapte automatiquement le mode de réflexion, l'effort et la forme du prompt selon le niveau du modèle -- Runtime d'agent intégré (Rust) + fournisseurs Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Runtime d'agent intégré (Rust) + fournisseurs Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot et Google Gemini API - Passthrough au format Anthropic pour les fournisseurs LLM chinois — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Intégration Git** diff --git a/README.hi.md b/README.hi.md index 6541d4b53..7761db318 100644 --- a/README.hi.md +++ b/README.hi.md @@ -64,7 +64,7 @@ ### 🔌 MCP सर्वर -Claude Code, Codex, Gemini, OpenCode, Kiro, या Copilot CLIs में वन-क्लिक इंस्टॉल। अपने टर्मिनल से डिज़ाइन करें — किसी भी MCP-संगत एजेंट के ज़रिए `.op` फ़ाइलें पढ़ें, बनाएँ और संशोधित करें। +Claude Code, Codex, OpenCode, Kiro, या Copilot CLIs में वन-क्लिक इंस्टॉल। अपने टर्मिनल से डिज़ाइन करें — किसी भी MCP-संगत एजेंट के ज़रिए `.op` फ़ाइलें पढ़ें, बनाएँ और संशोधित करें। @@ -125,7 +125,7 @@ cargo run -p op-host-desktop | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle और CanvasKit assets | -Web UI केवल built-in agent profiles दिखाता है; Claude/Codex/OpenCode/Copilot/Gemini CLI tools Docker images में शामिल नहीं हैं। +Web UI केवल built-in agent profiles दिखाता है; Claude/Codex/OpenCode/Copilot CLI tools Docker images में शामिल नहीं हैं। **चलाएँ:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | एजेंट सेटिंग्स में कनेक्ट करें (`Cmd+,`) | | **OpenCode** | एजेंट सेटिंग्स में कनेक्ट करें (`Cmd+,`) | | **GitHub Copilot** | `copilot login` फिर एजेंट सेटिंग्स में कनेक्ट करें (`Cmd+,`) | -| **Gemini CLI** | एजेंट सेटिंग्स में कनेक्ट करें (`Cmd+,`) | **मॉडल क्षमता प्रोफ़ाइल** — प्रत्येक मॉडल टियर के अनुसार प्रॉम्प्ट, थिंकिंग मोड और टाइमआउट को स्वचालित रूप से अनुकूलित करता है। फुल-टियर मॉडल (Claude) को पूर्ण प्रॉम्प्ट मिलते हैं; स्टैंडर्ड-टियर (GPT-4o, Gemini, DeepSeek) में थिंकिंग अक्षम होती है; बेसिक-टियर (MiniMax, Qwen, Llama, Mistral) को अधिकतम विश्वसनीयता के लिए सरलीकृत नेस्टेड-JSON प्रॉम्प्ट मिलते हैं। @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP सर्वर** -- बिल्ट-इन MCP सर्वर (`op-mcp` crate) — Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLIs में वन-क्लिक इंस्टॉल +- बिल्ट-इन MCP सर्वर (`op-mcp` crate) — Claude Code / Codex / OpenCode / Kiro / Copilot CLIs में वन-क्लिक इंस्टॉल - Node.js की कोई आवश्यकता नहीं — डेस्कटॉप बाइनरी (`--mcp `) के ज़रिए stdio ट्रांसपोर्ट, साथ ही चल रहे ऐप से एक लाइव HTTP एंडपॉइंट (`127.0.0.1:/mcp`) - टर्मिनल से डिज़ाइन ऑटोमेशन: किसी भी MCP-संगत एजेंट के ज़रिए `.op` फ़ाइलें पढ़ें, बनाएँ और संपादित करें - **लेयर्ड डिज़ाइन वर्कफ़्लो** — उच्च-फ़िडेलिटी मल्टी-सेक्शन डिज़ाइन के लिए `design_skeleton` → `design_content` → `design_refine` @@ -229,7 +228,7 @@ cat design.dsl | op design - # stdin से पाइप करें - लेयर्ड वर्कफ़्लो — `design_skeleton` → `design_content` → `design_refine`, प्रत्येक चरण के लिए केंद्रित प्रॉम्प्ट - स्टाइल गाइड — 50+ इन-बिल्ट स्टाइल (glassmorphism, brutalist, retro आदि), टैग-आधारित फ़ज़ी मैचिंग, प्लानिंग और जनरेशन में एकीकृत - मल्टी-मॉडल क्षमता प्रोफ़ाइल — मॉडल स्तर के अनुसार थिंकिंग मोड, प्रयास और प्रॉम्प्ट रूप को स्वचालित रूप से अनुकूलित करता है -- बिल्ट-इन एजेंट रनटाइम (Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini प्रदाता +- बिल्ट-इन एजेंट रनटाइम (Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot और Google Gemini API प्रदाता - चीनी LLM प्रदाताओं के लिए Anthropic फ़ॉर्मेट पासथ्रू — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Git इंटीग्रेशन** diff --git a/README.id.md b/README.id.md index 0ae3c415d..c817ebaa3 100644 --- a/README.id.md +++ b/README.id.md @@ -64,7 +64,7 @@ Secara otomatis menyesuaikan dengan kemampuan setiap model. Claude mendapat prom ### 🔌 Server MCP -Instal satu klik ke Claude Code, Codex, Gemini, OpenCode, Kiro, atau Copilot CLI. Desain dari terminal Anda — baca, buat, dan modifikasi file `.op` melalui agen yang kompatibel dengan MCP. +Instal satu klik ke Claude Code, Codex, OpenCode, Kiro, atau Copilot CLI. Desain dari terminal Anda — baca, buat, dan modifikasi file `.op` melalui agen yang kompatibel dengan MCP. @@ -125,7 +125,7 @@ Rilis Rust bertag menerbitkan satu image web host. Image TypeScript lama yang me | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle, dan aset CanvasKit | -Web UI hanya menampilkan built-in agent profiles; alat Claude/Codex/OpenCode/Copilot/Gemini CLI tidak dibundel ke dalam image Docker. +Web UI hanya menampilkan built-in agent profiles; alat Claude/Codex/OpenCode/Copilot CLI tidak dibundel ke dalam image Docker. **Jalankan:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Hubungkan di Pengaturan Agen (`Cmd+,`) | | **OpenCode** | Hubungkan di Pengaturan Agen (`Cmd+,`) | | **GitHub Copilot** | `copilot login` lalu hubungkan di Pengaturan Agen (`Cmd+,`) | -| **Gemini CLI** | Hubungkan di Pengaturan Agen (`Cmd+,`) | **Profil Kemampuan Model** — secara otomatis menyesuaikan prompt, mode thinking, dan timeout per tingkatan model. Model tingkat penuh (Claude) mendapat prompt lengkap; tingkat standar (GPT-4o, Gemini, DeepSeek) menonaktifkan thinking; tingkat dasar (MiniMax, Qwen, Llama, Mistral) mendapat prompt JSON bertingkat yang disederhanakan untuk keandalan maksimum. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **Server MCP** -- Server MCP bawaan (crate `op-mcp`) — instal satu klik ke Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI +- Server MCP bawaan (crate `op-mcp`) — instal satu klik ke Claude Code / Codex / OpenCode / Kiro / Copilot CLI - Tidak memerlukan Node.js — transport stdio melalui binary desktop (`--mcp `), ditambah endpoint HTTP langsung (`127.0.0.1:/mcp`) dari aplikasi yang berjalan - Otomasi desain dari terminal: baca, buat, dan modifikasi file `.op` melalui agen yang kompatibel dengan MCP - **Alur kerja desain berlapis** — `design_skeleton` → `design_content` → `design_refine` untuk desain multi-bagian dengan fidelitas lebih tinggi @@ -229,7 +228,7 @@ Mendukung string inline, `@filepath`, dan stdin (`-`). Bekerja dengan aplikasi d - Alur kerja berlapis — `design_skeleton` → `design_content` → `design_refine` dengan prompt yang terfokus per fase - Panduan Gaya — 50+ gaya bawaan (glassmorphism, brutalist, retro, dll.) dengan pencocokan fuzzy berbasis tag, terintegrasi ke perencanaan dan pembuatan - Profil kemampuan multi-model — secara otomatis menyesuaikan mode berpikir, upaya, dan bentuk prompt berdasarkan tingkat model -- Runtime agen bawaan (Rust) + penyedia Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Runtime agen bawaan (Rust) + penyedia Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, dan Google Gemini API - Passthrough format Anthropic untuk penyedia LLM Tiongkok — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Integrasi Git** diff --git a/README.ja.md b/README.ja.md index 36b080782..059035f29 100644 --- a/README.ja.md +++ b/README.ja.md @@ -64,7 +64,7 @@ ### 🔌 MCP サーバー -Claude Code、Codex、Gemini、OpenCode、Kiro、Copilot CLI にワンクリックでインストール。ターミナルからデザイン — MCP 対応エージェントを通じて `.op` ファイルの読み取り、作成、編集が可能。 +Claude Code、Codex、OpenCode、Kiro、Copilot CLI にワンクリックでインストール。ターミナルからデザイン — MCP 対応エージェントを通じて `.op` ファイルの読み取り、作成、編集が可能。 @@ -125,7 +125,7 @@ cargo run -p op-host-desktop | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host、wasm bundle、CanvasKit assets | -Web UI は built-in agent profiles のみを公開します。Claude/Codex/OpenCode/Copilot/Gemini CLI ツールは Docker イメージに同梱されません。 +Web UI は built-in agent profiles のみを公開します。Claude/Codex/OpenCode/Copilot CLI ツールは Docker イメージに同梱されません。 **実行:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | エージェント設定で接続(`Cmd+,`) | | **OpenCode** | エージェント設定で接続(`Cmd+,`) | | **GitHub Copilot** | `copilot login` 後、エージェント設定で接続(`Cmd+,`) | -| **Gemini CLI** | エージェント設定で接続(`Cmd+,`) | **モデル能力プロファイル** — モデルの階層に応じてプロンプト、シンキングモード、タイムアウトを自動適応。フル階層モデル(Claude)には完全なプロンプト、標準階層(GPT-4o、Gemini、DeepSeek)ではシンキングを無効化、ベーシック階層(MiniMax、Qwen、Llama、Mistral)には最大限の信頼性のために簡略化されたネスト JSON プロンプトを使用。 @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP サーバー** -- 内蔵 MCP サーバー(`op-mcp` crate) — Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI にワンクリックでインストール +- 内蔵 MCP サーバー(`op-mcp` crate) — Claude Code / Codex / OpenCode / Kiro / Copilot CLI にワンクリックでインストール - Node.js は不要 — デスクトップバイナリ経由の stdio トランスポート(`--mcp `)に加え、実行中のアプリからライブ HTTP エンドポイント(`127.0.0.1:/mcp`)を提供 - ターミナルからのデザイン自動化:MCP 対応エージェントを通じて `.op` ファイルの読み取り、作成、編集が可能 - **レイヤードデザインワークフロー** — `design_skeleton` → `design_content` → `design_refine` による高忠実度マルチセクションデザイン @@ -229,7 +228,7 @@ cat design.dsl | op design - # stdin からパイプ入力 - レイヤードワークフロー — `design_skeleton` → `design_content` → `design_refine`、各フェーズごとに焦点を絞ったプロンプト - スタイルガイド — 50+ のビルトインスタイル(glassmorphism、brutalist、retro など)、タグベースのファジーマッチング対応、プランニングと生成に統合 - マルチモデル能力プロファイル — モデル階層に応じてシンキングモード、エフォート、プロンプト形状を自動適応 -- ビルトインエージェントランタイム(Rust)+ Anthropic、Claude Agent SDK、OpenCode、Codex、Copilot、Gemini プロバイダー +- ビルトインエージェントランタイム(Rust)+ Anthropic、Claude Agent SDK、OpenCode、Codex、Copilot、Google Gemini API プロバイダー - 中国系 LLM プロバイダー向け Anthropic フォーマットパススルー — Kimi、Zhipu、GLM、DouBao、Ark、Bailian/DashScope、ModelScope、Coding Plans **Git 統合** diff --git a/README.ko.md b/README.ko.md index d364e2f46..38463da4c 100644 --- a/README.ko.md +++ b/README.ko.md @@ -64,7 +64,7 @@ ### 🔌 MCP 서버 -Claude Code, Codex, Gemini, OpenCode, Kiro 또는 Copilot CLI에 원클릭 설치. 터미널에서 디자인하세요 — MCP 호환 에이전트를 통해 `.op` 파일을 읽고, 생성하고, 편집할 수 있습니다. +Claude Code, Codex, OpenCode, Kiro 또는 Copilot CLI에 원클릭 설치. 터미널에서 디자인하세요 — MCP 호환 에이전트를 통해 `.op` 파일을 읽고, 생성하고, 편집할 수 있습니다. @@ -125,7 +125,7 @@ cargo run -p op-host-desktop | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle, CanvasKit assets | -웹 UI는 내장 agent profiles만 노출합니다. Claude/Codex/OpenCode/Copilot/Gemini CLI 도구는 Docker 이미지에 포함되지 않습니다. +웹 UI는 내장 agent profiles만 노출합니다. Claude/Codex/OpenCode/Copilot CLI 도구는 Docker 이미지에 포함되지 않습니다. **실행:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | 에이전트 설정에서 연결 (`Cmd+,`) | | **OpenCode** | 에이전트 설정에서 연결 (`Cmd+,`) | | **GitHub Copilot** | `copilot login` 후 에이전트 설정에서 연결 (`Cmd+,`) | -| **Gemini CLI** | 에이전트 설정에서 연결 (`Cmd+,`) | **모델 역량 프로파일** — 모델 티어에 따라 프롬프트, 사고 모드, 타임아웃을 자동 조정합니다. 풀 티어 모델(Claude)은 완전한 프롬프트를 받고, 스탠다드 티어(GPT-4o, Gemini, DeepSeek)는 사고 모드를 비활성화하며, 베이직 티어(MiniMax, Qwen, Llama, Mistral)는 최대 안정성을 위해 단순화된 중첩 JSON 프롬프트를 받습니다. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP 서버** -- 내장 MCP 서버 (`op-mcp` 크레이트) — Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI에 원클릭 설치 +- 내장 MCP 서버 (`op-mcp` 크레이트) — Claude Code / Codex / OpenCode / Kiro / Copilot CLI에 원클릭 설치 - Node.js 불필요 — 데스크톱 바이너리(`--mcp `)를 통한 stdio 전송, 그리고 실행 중인 앱이 제공하는 실시간 HTTP 엔드포인트(`127.0.0.1:/mcp`) - 터미널에서 디자인 자동화: MCP 호환 에이전트를 통해 `.op` 파일 읽기, 생성, 편집 - **계층적 디자인 워크플로** — `design_skeleton` → `design_content` → `design_refine`으로 더 높은 충실도의 멀티 섹션 디자인 @@ -229,7 +228,7 @@ cat design.dsl | op design - # stdin에서 파이프 입력 - 계층적 워크플로 — `design_skeleton` → `design_content` → `design_refine`, 각 단계에 집중된 프롬프트 사용 - 스타일 가이드 — 50개 이상의 내장 스타일(glassmorphism, brutalist, retro 등), 태그 기반 퍼지 매칭 지원, 플래닝과 생성에 통합 - 멀티 모델 역량 프로파일 — 모델 등급별로 싱킹 모드, 노력도, 프롬프트 형태를 자동 적응 -- 내장 에이전트 런타임(Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini 제공자 +- 내장 에이전트 런타임(Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Google Gemini API 제공자 - 중국 LLM 제공자를 위한 Anthropic 형식 패스스루 — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Git 통합** diff --git a/README.md b/README.md index 5b82b5246..b594fccdb 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Automatically adapts to each model's capabilities. Claude gets full prompts with ### 🔌 MCP Server -One-click install into Claude Code, Codex, Gemini, OpenCode, Kiro, or Copilot CLIs. Design from your terminal — read, create, and modify `.op` files through any MCP-compatible agent. +One-click install into Claude Code, Codex, OpenCode, Kiro, or Copilot CLIs. Design from your terminal — read, create, and modify `.op` files through any MCP-compatible agent. @@ -243,7 +243,7 @@ Tagged Rust releases publish a single web-host image. The retired TypeScript ima | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle, and CanvasKit assets | -The web UI exposes built-in agent profiles only; Claude/Codex/OpenCode/Copilot/Gemini CLI tooling is not bundled into Docker images. +The web UI exposes built-in agent profiles only; Claude/Codex/OpenCode/Copilot CLI tooling is not bundled into Docker images. **Run:** @@ -282,7 +282,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Connect in Agent Settings (`Cmd+,`) | | **OpenCode** | Connect in Agent Settings (`Cmd+,`) | | **GitHub Copilot** | `copilot login` then connect in Agent Settings (`Cmd+,`) | -| **Gemini CLI** | Connect in Agent Settings (`Cmd+,`) | **Model Capability Profiles** — automatically adapts prompts, thinking mode, and timeouts per model tier. Full-tier models (Claude) get complete prompts; standard-tier (GPT-4o, Gemini, DeepSeek) disable thinking; basic-tier (MiniMax, Qwen, Llama, Mistral) get simplified nested-JSON prompts for maximum reliability. @@ -290,7 +289,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP Server** -- Built-in MCP server (`op-mcp` crate) — one-click install into Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLIs +- Built-in MCP server (`op-mcp` crate) — one-click install into Claude Code / Codex / OpenCode / Kiro / Copilot CLIs - No Node.js required — stdio transport via the desktop binary (`--mcp `), plus a live HTTP endpoint (`127.0.0.1:/mcp`) from the running app - Design automation from terminal: read, create, and modify `.op` files via any MCP-compatible agent - **Layered design workflow** — `design_skeleton` → `design_content` → `design_refine` for higher-fidelity multi-section designs @@ -367,7 +366,7 @@ Supports three input methods: inline string, `@filepath` (read from file), or `- - Layered workflow — `design_skeleton` → `design_content` → `design_refine` with focused prompts per phase - Style Guides — 50+ built-in styles (glassmorphism, brutalist, retro, etc.) with tag-based fuzzy matching, wired into planning and generation - Multi-model capability profiles — auto-adapts thinking mode, effort, and prompt shape per model tier -- Built-in Rust agent runtime + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini providers +- Built-in Rust agent runtime + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Google Gemini API providers - Anthropic-format passthrough for Chinese LLM providers — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Git Integration** diff --git a/README.pt.md b/README.pt.md index 2984cc2e7..018cef780 100644 --- a/README.pt.md +++ b/README.pt.md @@ -64,7 +64,7 @@ Adapta-se automaticamente às capacidades de cada modelo. Claude recebe prompts ### 🔌 Servidor MCP -Instalação com um clique no Claude Code, Codex, Gemini, OpenCode, Kiro ou Copilot CLIs. Faça design pelo seu terminal — leia, crie e modifique arquivos `.op` através de qualquer agente compatível com MCP. +Instalação com um clique no Claude Code, Codex, OpenCode, Kiro ou Copilot CLIs. Faça design pelo seu terminal — leia, crie e modifique arquivos `.op` através de qualquer agente compatível com MCP. @@ -125,7 +125,7 @@ Releases Rust com tag publicam uma única imagem de web host. As imagens TypeScr | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle e assets do CanvasKit | -A UI web expõe apenas perfis de agente integrados; as ferramentas Claude/Codex/OpenCode/Copilot/Gemini CLI não são incluídas nas imagens Docker. +A UI web expõe apenas perfis de agente integrados; as ferramentas Claude/Codex/OpenCode/Copilot CLI não são incluídas nas imagens Docker. **Executar:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Conectar nas Configurações do Agente (`Cmd+,`) | | **OpenCode** | Conectar nas Configurações do Agente (`Cmd+,`) | | **GitHub Copilot** | `copilot login` e depois conectar nas Configurações do Agente (`Cmd+,`) | -| **Gemini CLI** | Conectar nas Configurações do Agente (`Cmd+,`) | **Perfis de Capacidade de Modelo** — adapta automaticamente prompts, modo de thinking e timeouts por nível de modelo. Modelos de nível completo (Claude) recebem prompts completos; nível padrão (GPT-4o, Gemini, DeepSeek) desativam thinking; nível básico (MiniMax, Qwen, Llama, Mistral) recebem prompts simplificados de JSON aninhado para máxima confiabilidade. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **Servidor MCP** -- Servidor MCP integrado (crate `op-mcp`) — instalação com um clique no Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLIs +- Servidor MCP integrado (crate `op-mcp`) — instalação com um clique no Claude Code / Codex / OpenCode / Kiro / Copilot CLIs - Não requer Node.js — transporte stdio via o binário desktop (`--mcp `), além de um endpoint HTTP ativo (`127.0.0.1:/mcp`) a partir do app em execução - Automação de design pelo terminal: leia, crie e modifique arquivos `.op` via qualquer agente compatível com MCP - **Fluxo de design em camadas** — `design_skeleton` → `design_content` → `design_refine` para designs multi-seção de maior fidelidade @@ -229,7 +228,7 @@ Suporta strings inline, `@filepath` e stdin (`-`). Funciona com o app desktop, s - Fluxo em camadas — `design_skeleton` → `design_content` → `design_refine` com prompts focados por fase - Guias de estilo — mais de 50 estilos integrados (glassmorphism, brutalist, retro, etc.) com correspondência fuzzy baseada em tags, integrados ao planejamento e geração - Perfis de capacidade multi-modelo — adapta automaticamente o modo de pensamento, o esforço e a forma do prompt conforme o nível do modelo -- Runtime de agente integrado (Rust) + provedores Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Runtime de agente integrado (Rust) + provedores Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot e Google Gemini API - Passthrough no formato Anthropic para provedores de LLMs chineses — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Integração com Git** diff --git a/README.ru.md b/README.ru.md index cce8b082f..2f71d0cee 100644 --- a/README.ru.md +++ b/README.ru.md @@ -64,7 +64,7 @@ ### 🔌 MCP-сервер -Установка в один клик в Claude Code, Codex, Gemini, OpenCode, Kiro или Copilot CLI. Дизайн из терминала — чтение, создание и изменение файлов `.op` через любой MCP-совместимый агент. +Установка в один клик в Claude Code, Codex, OpenCode, Kiro или Copilot CLI. Дизайн из терминала — чтение, создание и изменение файлов `.op` через любой MCP-совместимый агент. @@ -125,7 +125,7 @@ cargo run -p op-host-desktop | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle и ресурсы CanvasKit | -Веб-интерфейс показывает только встроенные профили агентов; инструменты Claude/Codex/OpenCode/Copilot/Gemini CLI не входят в Docker-образы. +Веб-интерфейс показывает только встроенные профили агентов; инструменты Claude/Codex/OpenCode/Copilot CLI не входят в Docker-образы. **Запуск:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Подключить в настройках агента (`Cmd+,`) | | **OpenCode** | Подключить в настройках агента (`Cmd+,`) | | **GitHub Copilot** | `copilot login`, затем подключить в настройках агента (`Cmd+,`) | -| **Gemini CLI** | Подключить в настройках агента (`Cmd+,`) | **Профили возможностей моделей** — автоматически адаптирует промпты, режим thinking и таймауты для каждого уровня моделей. Модели полного уровня (Claude) получают полные промпты; стандартного уровня (GPT-4o, Gemini, DeepSeek) — с отключённым thinking; базового уровня (MiniMax, Qwen, Llama, Mistral) — упрощённые промпты с вложенным JSON для максимальной надёжности. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP-сервер** -- Встроенный MCP-сервер (крейт `op-mcp`) — установка в один клик в Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI +- Встроенный MCP-сервер (крейт `op-mcp`) — установка в один клик в Claude Code / Codex / OpenCode / Kiro / Copilot CLI - Node.js не требуется — stdio-транспорт через десктопный бинарный файл (`--mcp `), плюс работающий HTTP-эндпоинт (`127.0.0.1:/mcp`) из запущенного приложения - Автоматизация дизайна из терминала: чтение, создание и изменение файлов `.op` через любой MCP-совместимый агент - **Послойный рабочий процесс** — `design_skeleton` → `design_content` → `design_refine` для дизайнов высокого качества с несколькими секциями @@ -229,7 +228,7 @@ cat design.dsl | op design - # Передача через stdin - Послойный рабочий процесс — `design_skeleton` → `design_content` → `design_refine` со сфокусированными промптами на каждой фазе - Руководства по стилю — 50+ встроенных стилей (glassmorphism, brutalist, retro и т. д.) с нечётким сопоставлением по тегам, интегрированным в планирование и генерацию - Профили возможностей мультимодели — автоматически подстраивает режим размышления, уровень усилий и форму промпта в зависимости от уровня модели -- Встроенный рантайм агентов (Rust) + провайдеры Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Встроенный рантайм агентов (Rust) + провайдеры Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot и Google Gemini API - Проброс формата Anthropic для китайских провайдеров LLM — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Интеграция с Git** diff --git a/README.th.md b/README.th.md index 04692e0e8..25be10ff6 100644 --- a/README.th.md +++ b/README.th.md @@ -64,7 +64,7 @@ Orchestrator แบ่งหน้าที่ซับซ้อนออกเ ### 🔌 MCP Server -ติดตั้งได้ด้วยคลิกเดียวใน Claude Code, Codex, Gemini, OpenCode, Kiro หรือ Copilot CLIs ออกแบบจาก terminal ของคุณ — อ่าน สร้าง และแก้ไขไฟล์ `.op` ผ่าน agent ที่รองรับ MCP +ติดตั้งได้ด้วยคลิกเดียวใน Claude Code, Codex, OpenCode, Kiro หรือ Copilot CLIs ออกแบบจาก terminal ของคุณ — อ่าน สร้าง และแก้ไขไฟล์ `.op` ผ่าน agent ที่รองรับ MCP @@ -125,7 +125,7 @@ Rust release ที่มี tag จะเผยแพร่ image แบบ web | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle และ CanvasKit assets | -Web UI แสดงเฉพาะ built-in agent profiles เท่านั้น เครื่องมือ Claude/Codex/OpenCode/Copilot/Gemini CLI จะไม่ถูกบันเดิลใน Docker images +Web UI แสดงเฉพาะ built-in agent profiles เท่านั้น เครื่องมือ Claude/Codex/OpenCode/Copilot CLI จะไม่ถูกบันเดิลใน Docker images **รัน:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | เชื่อมต่อใน Agent Settings (`Cmd+,`) | | **OpenCode** | เชื่อมต่อใน Agent Settings (`Cmd+,`) | | **GitHub Copilot** | `copilot login` จากนั้นเชื่อมต่อใน Agent Settings (`Cmd+,`) | -| **Gemini CLI** | เชื่อมต่อใน Agent Settings (`Cmd+,`) | **โปรไฟล์ความสามารถของโมเดล** — ปรับ prompt, โหมด thinking และ timeout ตามระดับโมเดลโดยอัตโนมัติ โมเดลระดับเต็ม (Claude) ได้ prompt ครบถ้วน; โมเดลระดับมาตรฐาน (GPT-4o, Gemini, DeepSeek) ปิด thinking; โมเดลระดับพื้นฐาน (MiniMax, Qwen, Llama, Mistral) ได้ prompt แบบ nested-JSON ที่ย่อลงเพื่อความเสถียรสูงสุด @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP Server** -- MCP Server ในตัว (`op-mcp` crate) — ติดตั้งได้ด้วยคลิกเดียวใน Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLIs +- MCP Server ในตัว (`op-mcp` crate) — ติดตั้งได้ด้วยคลิกเดียวใน Claude Code / Codex / OpenCode / Kiro / Copilot CLIs - ไม่ต้องใช้ Node.js — stdio transport ผ่าน binary เดสก์ท็อป (`--mcp `) พร้อม live HTTP endpoint (`127.0.0.1:/mcp`) จากแอปที่กำลังทำงาน - การทำ Design automation จาก terminal: อ่าน สร้าง และแก้ไขไฟล์ `.op` ผ่าน agent ที่รองรับ MCP - **Layered design workflow** — `design_skeleton` → `design_content` → `design_refine` สำหรับดีไซน์หลายส่วนที่มีความละเอียดสูงขึ้น @@ -229,7 +228,7 @@ cat design.dsl | op design - # Pipe จาก stdin - Layered workflow — `design_skeleton` → `design_content` → `design_refine` พร้อม prompt ที่เน้นเฉพาะในแต่ละเฟส - Style Guides — สไตล์ในตัวกว่า 50 แบบ (glassmorphism, brutalist, retro ฯลฯ) พร้อม fuzzy matching ตาม tag ใช้ในการวางแผนและการสร้าง - โปรไฟล์ความสามารถหลายโมเดล — ปรับโหมดการคิด ความพยายาม และรูปแบบ prompt อัตโนมัติตามระดับโมเดล -- Agent runtime ในตัว (Rust) + ผู้ให้บริการ Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Agent runtime ในตัว (Rust) + ผู้ให้บริการ Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot และ Google Gemini API - Passthrough รูปแบบ Anthropic สำหรับผู้ให้บริการ LLM จีน — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **การเชื่อมต่อ Git** diff --git a/README.tr.md b/README.tr.md index 4dee4e559..78ae558c3 100644 --- a/README.tr.md +++ b/README.tr.md @@ -64,7 +64,7 @@ Her modelin yeteneklerine otomatik olarak uyum sağlar. Claude tam promptlar ve ### 🔌 MCP Sunucusu -Claude Code, Codex, Gemini, OpenCode, Kiro veya Copilot CLI'larına tek tıkla kurulum. Terminalinizden tasarım yapın — herhangi bir MCP uyumlu ajan aracılığıyla `.op` dosyalarını okuyun, oluşturun ve düzenleyin. +Claude Code, Codex, OpenCode, Kiro veya Copilot CLI'larına tek tıkla kurulum. Terminalinizden tasarım yapın — herhangi bir MCP uyumlu ajan aracılığıyla `.op` dosyalarını okuyun, oluşturun ve düzenleyin. @@ -125,7 +125,7 @@ Etiketli Rust sürümleri tek bir web host görüntüsü yayımlar. AI CLI'ları | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle ve CanvasKit varlıkları | -Web UI yalnızca yerleşik agent profillerini gösterir; Claude/Codex/OpenCode/Copilot/Gemini CLI araçları Docker görüntülerine dahil değildir. +Web UI yalnızca yerleşik agent profillerini gösterir; Claude/Codex/OpenCode/Copilot CLI araçları Docker görüntülerine dahil değildir. **Çalıştır:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Ajan Ayarlarından bağlanın (`Cmd+,`) | | **OpenCode** | Ajan Ayarlarından bağlanın (`Cmd+,`) | | **GitHub Copilot** | `copilot login` ardından Ajan Ayarlarından bağlanın (`Cmd+,`) | -| **Gemini CLI** | Ajan Ayarlarından bağlanın (`Cmd+,`) | **Model Yetenek Profilleri** — promptları, düşünme modunu ve zaman aşımlarını model katmanına göre otomatik olarak uyarlar. Tam katman modeller (Claude) eksiksiz promptlar alır; standart katman (GPT-4o, Gemini, DeepSeek) düşünme modunu devre dışı bırakır; temel katman (MiniMax, Qwen, Llama, Mistral) maksimum güvenilirlik için basitleştirilmiş iç içe JSON promptları alır. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP Sunucusu** -- Yerleşik MCP sunucusu (`op-mcp` crate) — Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI'larına tek tıkla kurulum +- Yerleşik MCP sunucusu (`op-mcp` crate) — Claude Code / Codex / OpenCode / Kiro / Copilot CLI'larına tek tıkla kurulum - Node.js gerekmez — masaüstü ikili dosyası aracılığıyla stdio aktarımı (`--mcp `), ayrıca çalışan uygulamadan canlı bir HTTP uç noktası (`127.0.0.1:/mcp`) - Terminalden tasarım otomasyonu: herhangi bir MCP uyumlu ajan aracılığıyla `.op` dosyalarını okuyun, oluşturun ve düzenleyin - **Katmanlı tasarım iş akışı** — daha yüksek kaliteli çok bölümlü tasarımlar için `design_skeleton` → `design_content` → `design_refine` @@ -229,7 +228,7 @@ Satır içi metni, `@filepath` ve stdin'i (`-`) destekler. Masaüstü uygulama, - Katmanlı iş akışı — `design_skeleton` → `design_content` → `design_refine`, her aşamada odaklı prompt'lar - Stil Rehberleri — 50+ yerleşik stil (glassmorphism, brutalist, retro vb.), etiket tabanlı bulanık eşleştirme ile planlama ve üretime entegre - Çoklu model yetenek profilleri — model katmanına göre düşünme modunu, çabayı ve prompt biçimini otomatik olarak uyarlar -- Yerleşik ajan çalışma ortamı (Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini sağlayıcıları +- Yerleşik ajan çalışma ortamı (Rust) + Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot ve Google Gemini API sağlayıcıları - Çinli LLM sağlayıcıları için Anthropic formatlı geçiş — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Git Entegrasyonu** diff --git a/README.vi.md b/README.vi.md index 11635ab1c..8165c008e 100644 --- a/README.vi.md +++ b/README.vi.md @@ -64,7 +64,7 @@ Tự động thích ứng với khả năng của từng mô hình. Claude nhậ ### 🔌 Máy chủ MCP -Cài đặt một cú nhấp vào Claude Code, Codex, Gemini, OpenCode, Kiro hoặc Copilot CLI. Thiết kế từ terminal — đọc, tạo và chỉnh sửa tệp `.op` thông qua bất kỳ tác nhân tương thích MCP nào. +Cài đặt một cú nhấp vào Claude Code, Codex, OpenCode, Kiro hoặc Copilot CLI. Thiết kế từ terminal — đọc, tạo và chỉnh sửa tệp `.op` thông qua bất kỳ tác nhân tương thích MCP nào. @@ -125,7 +125,7 @@ Các bản phát hành Rust có tag chỉ phát hành một image web host. Các | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host, wasm bundle và tài nguyên CanvasKit | -Web UI chỉ hiển thị các built-in agent profiles; công cụ Claude/Codex/OpenCode/Copilot/Gemini CLI không được đóng gói trong Docker images. +Web UI chỉ hiển thị các built-in agent profiles; công cụ Claude/Codex/OpenCode/Copilot CLI không được đóng gói trong Docker images. **Chạy:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | Kết nối trong Cài đặt tác nhân (`Cmd+,`) | | **OpenCode** | Kết nối trong Cài đặt tác nhân (`Cmd+,`) | | **GitHub Copilot** | `copilot login` rồi kết nối trong Cài đặt tác nhân (`Cmd+,`) | -| **Gemini CLI** | Kết nối trong Cài đặt tác nhân (`Cmd+,`) | **Hồ sơ Năng lực Mô hình** — tự động thích ứng prompt, chế độ thinking và thời gian chờ theo từng cấp mô hình. Mô hình cấp đầy đủ (Claude) nhận prompt hoàn chỉnh; cấp tiêu chuẩn (GPT-4o, Gemini, DeepSeek) tắt thinking; cấp cơ bản (MiniMax, Qwen, Llama, Mistral) nhận prompt JSON lồng nhau đơn giản hóa để đảm bảo độ tin cậy tối đa. @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **Máy chủ MCP** -- Máy chủ MCP tích hợp sẵn (crate `op-mcp`) — cài đặt một cú nhấp vào Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI +- Máy chủ MCP tích hợp sẵn (crate `op-mcp`) — cài đặt một cú nhấp vào Claude Code / Codex / OpenCode / Kiro / Copilot CLI - Không cần Node.js — stdio transport qua tệp nhị phân desktop (`--mcp `), cộng với một HTTP endpoint trực tiếp (`127.0.0.1:/mcp`) từ ứng dụng đang chạy - Tự động hóa thiết kế từ terminal: đọc, tạo và chỉnh sửa các tệp `.op` qua bất kỳ tác nhân tương thích MCP nào - **Quy trình thiết kế phân lớp** — `design_skeleton` → `design_content` → `design_refine` cho thiết kế đa phần có độ trung thực cao hơn @@ -229,7 +228,7 @@ Hỗ trợ chuỗi inline, `@filepath` và stdin (`-`). Hoạt động với ứ - Quy trình phân lớp — `design_skeleton` → `design_content` → `design_refine` với prompt tập trung cho từng giai đoạn - Style Guides — hơn 50 style tích hợp (glassmorphism, brutalist, retro, v.v.) với khớp mờ dựa trên tag, tích hợp vào lập kế hoạch và tạo - Hồ sơ năng lực đa mô hình — tự động điều chỉnh chế độ tư duy, nỗ lực và hình thức prompt theo cấp mô hình -- Runtime tác nhân tích hợp (Rust) + nhà cung cấp Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot, Gemini +- Runtime tác nhân tích hợp (Rust) + nhà cung cấp Anthropic, Claude Agent SDK, OpenCode, Codex, Copilot và Google Gemini API - Chuyển tiếp định dạng Anthropic cho các nhà cung cấp LLM Trung Quốc — Kimi, Zhipu, GLM, DouBao, Ark, Bailian/DashScope, ModelScope, Coding Plans **Tích hợp Git** diff --git a/README.zh-TW.md b/README.zh-TW.md index 9574dbcf7..6d418c628 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -64,7 +64,7 @@ ### 🔌 MCP 伺服器 -一鍵安裝至 Claude Code、Codex、Gemini、OpenCode、Kiro 或 Copilot CLI。從終端機進行設計 — 透過任意 MCP 相容的智能體讀取、建立和修改 `.op` 檔案。 +一鍵安裝至 Claude Code、Codex、OpenCode、Kiro 或 Copilot CLI。從終端機進行設計 — 透過任意 MCP 相容的智能體讀取、建立和修改 `.op` 檔案。 @@ -125,7 +125,7 @@ cargo run -p op-host-desktop | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host、wasm bundle 和 CanvasKit 資源 | -Web UI 僅公開內建 agent profiles;Docker 映像檔不再內建 Claude/Codex/OpenCode/Copilot/Gemini CLI 工具。 +Web UI 僅公開內建 agent profiles;Docker 映像檔不再內建 Claude/Codex/OpenCode/Copilot CLI 工具。 **執行:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | 在 Agent 設定中連接(`Cmd+,`) | | **OpenCode** | 在 Agent 設定中連接(`Cmd+,`) | | **GitHub Copilot** | 執行 `copilot login` 後在 Agent 設定中連接(`Cmd+,`) | -| **Gemini CLI** | 在 Agent 設定中連接(`Cmd+,`) | **模型能力設定檔** — 自動依據模型層級調整提示詞、思考模式和逾時設定。完整層級模型(Claude)獲得完整提示詞;標準層級(GPT-4o、Gemini、DeepSeek)停用思考模式;基礎層級(MiniMax、Qwen、Llama、Mistral)獲得精簡巢狀 JSON 提示詞,確保最大可靠性。 @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP 伺服器** -- 內建 MCP 伺服器(`op-mcp` crate)— 一鍵安裝至 Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI +- 內建 MCP 伺服器(`op-mcp` crate)— 一鍵安裝至 Claude Code / Codex / OpenCode / Kiro / Copilot CLI - 無需 Node.js — 透過桌面二進位檔(`--mcp `)提供 stdio 傳輸,並由執行中的應用程式提供即時 HTTP 端點(`127.0.0.1:/mcp`) - 從終端機進行設計自動化:透過任意 MCP 相容的智能體讀取、建立和修改 `.op` 檔案 - **分層設計工作流** — `design_skeleton` → `design_content` → `design_refine`,適用於高保真多區塊設計 @@ -229,7 +228,7 @@ cat design.dsl | op design - # 從 stdin 管道輸入 - 分層工作流 — `design_skeleton` → `design_content` → `design_refine`,每個階段使用聚焦的提示詞 - 風格指南 — 50+ 內建風格(glassmorphism、brutalist、retro 等),支援基於標籤的模糊匹配,並接入規劃與生成流程 - 多模型能力設定檔 — 依模型層級自動適配思考模式、推理強度與提示詞形態 -- 內建智能體執行環境(Rust)+ Anthropic、Claude Agent SDK、OpenCode、Codex、Copilot、Gemini 提供商 +- 內建智能體執行環境(Rust)+ Anthropic、Claude Agent SDK、OpenCode、Codex、Copilot、Google Gemini API 提供商 - 中國大型語言模型 Anthropic 格式透傳 — Kimi、Zhipu、GLM、DouBao、Ark、Bailian/DashScope、ModelScope、Coding Plans **Git 整合** diff --git a/README.zh.md b/README.zh.md index 33b502806..cf190da13 100644 --- a/README.zh.md +++ b/README.zh.md @@ -64,7 +64,7 @@ ### 🔌 MCP 服务器 -一键安装到 Claude Code、Codex、Gemini、OpenCode、Kiro 或 Copilot CLI。从终端进行设计 — 通过任意 MCP 兼容的智能体读取、创建和修改 `.op` 文件。 +一键安装到 Claude Code、Codex、OpenCode、Kiro 或 Copilot CLI。从终端进行设计 — 通过任意 MCP 兼容的智能体读取、创建和修改 `.op` 文件。 @@ -125,7 +125,7 @@ cargo run -p op-host-desktop | --- | --- | | `ghcr.io/zseven-w/openpencil-web:vX.Y.Z` | Rust web host、wasm bundle 和 CanvasKit 资源 | -Web UI 只暴露内置 agent profiles;Docker 镜像不再内置 Claude/Codex/OpenCode/Copilot/Gemini CLI 工具。 +Web UI 只暴露内置 agent profiles;Docker 镜像不再内置 Claude/Codex/OpenCode/Copilot CLI 工具。 **运行:** @@ -161,7 +161,6 @@ docker run -p 3100:3100 openpencil-web-rust | **Codex CLI** | 在 Agent 设置中连接(`Cmd+,`) | | **OpenCode** | 在 Agent 设置中连接(`Cmd+,`) | | **GitHub Copilot** | 运行 `copilot login` 后在 Agent 设置中连接(`Cmd+,`) | -| **Gemini CLI** | 在 Agent 设置中连接(`Cmd+,`) | **模型能力配置** — 自动根据模型层级适配提示词、思考模式和超时时间。完整层级模型(Claude)获得完整提示词;标准层级模型(GPT-4o、Gemini、DeepSeek)关闭思考模式;基础层级模型(MiniMax、Qwen、Llama、Mistral)使用简化的嵌套 JSON 提示词以确保最大可靠性。 @@ -169,7 +168,7 @@ docker run -p 3100:3100 openpencil-web-rust **MCP 服务器** -- 内置 MCP 服务器(`op-mcp` crate)— 一键安装到 Claude Code / Codex / Gemini / OpenCode / Kiro / Copilot CLI +- 内置 MCP 服务器(`op-mcp` crate)— 一键安装到 Claude Code / Codex / OpenCode / Kiro / Copilot CLI - 无需 Node.js — 通过桌面应用二进制文件(`--mcp `)使用 stdio 传输,运行中的应用还提供实时 HTTP 端点(`127.0.0.1:/mcp`) - 从终端进行设计自动化:通过任意 MCP 兼容的智能体读取、创建和修改 `.op` 文件 - **分层设计工作流** — `design_skeleton` → `design_content` → `design_refine`,实现更高保真度的多区块设计 @@ -229,7 +228,7 @@ cat design.dsl | op design - # 从 stdin 管道输入 - 分层工作流 — `design_skeleton` → `design_content` → `design_refine`,每个阶段使用聚焦的提示词 - 风格指南 — 50+ 内置风格(glassmorphism、brutalist、retro 等),支持基于标签的模糊匹配,并接入规划与生成流程 - 多模型能力配置 — 按模型层级自动适配思考模式、推理强度与提示词形态 -- 内置智能体运行时(Rust)+ Anthropic、Claude Agent SDK、OpenCode、Codex、Copilot、Gemini 提供商 +- 内置智能体运行时(Rust)+ Anthropic、Claude Agent SDK、OpenCode、Codex、Copilot、Google Gemini API 提供商 - 国产大模型 Anthropic 格式透传 — Kimi、Zhipu、GLM、DouBao、Ark、Bailian/DashScope、ModelScope、Coding Plans **Git 集成** diff --git a/crates/CLAUDE.md b/crates/CLAUDE.md index c0ce056f6..68409dedc 100644 --- a/crates/CLAUDE.md +++ b/crates/CLAUDE.md @@ -106,7 +106,7 @@ Mutators on `Document`: | LocalePicker | TopBar Globe-button dropdown (15 native names + Check) | `locale_picker.rs` | | StatusBar | Floating bottom-right — zoom controls | `status_bar.rs` | | icons | lucide d-string library (50+ icons; 24×24 viewBox stroke art) | `icons.rs` | -| brand_icons | Claude / OpenAI / Gemini / Copilot / OpenCode brand logos (filled SVG paths, non-24×24 viewBoxes) | `brand_icons.rs` | +| brand_icons | Claude / OpenAI / Gemini / Copilot / Antigravity / Grok filled logos + OpenCode primitive logo | `brand_icons.rs` | | ColorPicker | HSV overlay (Cmd-Shift-C or fill/stroke swatch click) — sat/value box + hue strip + hex input | `color_picker.rs` | | LayerContextMenu | Right-click overlay on layer rows + page tabs (Rename / Duplicate / Delete / Group / Ungroup / Lock / Hide; subset on page tabs) | `layer_context_menu.rs` | | AgentSettings | Cmd+, modal — 880×640 with sidebar nav (Agents / MCP / Images / System) + scrollable right pane | `agent_settings_panel.rs` + `agent_settings_{i18n,images,mcp,system}.rs` | @@ -286,8 +286,8 @@ Every input path that reasons about the canvas region MUST derive its rects from `agent_settings_panel.rs` + 4 tab modules render an 880×640 modal opened from the TopBar agent chip or `Cmd+,`. Sidebar nav: Agents / MCP / Images / System. Right pane scrolls; modal paints last (over dim scrim) so it covers every other widget. -- **Agents** — `+ 添加服务商` and `+ 添加 Agent` actions in two empty-state sections, then 5 provider cards (Claude / Codex / OpenCode / GitHub Copilot / Gemini) with real brand logos from `widgets/brand_icons.rs`. Hovering a connected card swaps the green `✓ Connected` row for a red `断开连接` button; both lifecycle actions toggle `agent_settings.connected[i]`. -- **MCP** — server status card with port input + Start/Stop button, then a 2×4 grid of CLI integration toggles (Claude Code / Codex / Gemini / OpenCode / Kiro / GitHub Copilot / Antigravity / Grok Build). Port input is editable (see "Settings input editing" below). +- **Agents** — `+ 添加服务商` and `+ 添加 Agent` actions in two empty-state sections, then 6 provider cards (Claude / Codex / OpenCode / GitHub Copilot / Antigravity / Grok Build) with real brand logos from `widgets/brand_icons.rs`. Hovering a connected card swaps the green `✓ Connected` row for a red `断开连接` button; both lifecycle actions toggle `agent_settings.connected[i]`. +- **MCP** — server status card with port input + Start/Stop button, then a grid of 7 CLI integration toggles (Claude Code / Codex / OpenCode / Kiro / GitHub Copilot / Antigravity / Grok Build). Port input is editable (see "Settings input editing" below). - **Images** — Image Search Ready/Not-configured indicator + collapsible Advanced section (Openverse OAuth Client ID / Secret + Register link + Test button), then Image Generation section with `+ Add` empty state. - **System** — read-only Auto-update status card (no updater backend wired yet — a togglable switch would lie to the user; the row paints as informational text). @@ -506,7 +506,7 @@ mcp_tests.rs (in crate root) Cross-cutting: stdio dispatch, parser invariants ### Host wiring -`openpencil-desktop --mcp ` (`crates/openpencil-desktop/src/mcp_serve.rs`) runs a JSON-RPC stdio MCP server backed by the .op file at ``. External CLIs (Claude Code / Codex / Gemini / Copilot) spawn the binary in this mode to drive the Rust editor the same way they drive TS pen-mcp. +`openpencil-desktop --mcp ` (`crates/op-host-desktop/src/mcp_serve.rs`) runs a JSON-RPC stdio MCP server backed by the .op file at ``. External CLIs (Claude Code / Codex / OpenCode / Kiro / Copilot / Antigravity / Grok Build) spawn the binary in this mode to drive the Rust editor. - Handshake: `initialize` returns protocol version + capabilities + serverInfo; `tools/list` enumerates all 21 tools with JSON inputSchemas; `notifications/initialized` + `ping` handled inline. - Per-call lifecycle: re-build the `ToolRegistry` against the live document (so read-tool snapshots reflect prior writes) → dispatch through `run_stdio_with_applier` → applier closure mutates the doc + saves to disk on each successful write. @@ -535,9 +535,8 @@ real CLI agents, not a stub: transport-free trait; real impls live desktop-side: `chat_runtime.rs` (`BuiltInProvider`, agent-rs), `chat_claude.rs` (`ClaudeCodeProvider`, `anthropic-agent-sdk`), `chat_subprocess.rs` - (`SubprocessProvider` for Claude/Gemini/Copilot), `chat_copilot.rs`, - `chat_http_server.rs` (Codex/OpenCode — `for_cli` returns `None`, - protocol unverified upstream). + (`SubprocessProvider` for Codex/Antigravity/Grok Build), + `chat_copilot.rs`, `chat_http_server.rs` (OpenCode). - `chat_session.rs` — `ChatSession` runs a turn on a worker thread (`ChatProvider::send` is a blocking iterator). `launch_if_pending` drains `pending_send` → `provider_for_agent(chat_selected_agent)`; diff --git a/crates/op-ai-skills/skills/phases/generation/overflow.md b/crates/op-ai-skills/skills/phases/generation/overflow.md index 2ba7f6477..e2b2ab17b 100644 --- a/crates/op-ai-skills/skills/phases/generation/overflow.md +++ b/crates/op-ai-skills/skills/phases/generation/overflow.md @@ -21,7 +21,7 @@ When the spec says "horizontal scrolling cards", "swipeable row", "chip row", "m ### Preferred (MCP tool path): pick one of 3 narrow row tools -If you have access to MCP tools (external client: Claude Code / Codex / Gemini CLI / Cursor), call the tool matching what's in the row — all three produce the overflow-safe wrapper+clipContent+fit_content structure and cannot be made incorrectly by schema. +If you have access to MCP tools (external client: Claude Code / Codex / Cursor), call the tool matching what's in the row — all three produce the overflow-safe wrapper+clipContent+fit_content structure and cannot be made incorrectly by schema. - **`add_card_row_v0`** — items with `title` + optional `subtitle` + optional `icon` (workout cards, feature tiles, content cards). Default card size 140×160. - **`add_metric_row_v0`** — items with `label` + `value` + optional `icon` (dashboard stats: Steps/Kcal/Sleep/Revenue). Default tile size 120×100, value rendered 28/700. diff --git a/crates/op-ai/src/agent_settings_state.rs b/crates/op-ai/src/agent_settings_state.rs index 68a839a74..5f1478759 100644 --- a/crates/op-ai/src/agent_settings_state.rs +++ b/crates/op-ai/src/agent_settings_state.rs @@ -33,18 +33,16 @@ pub enum AgentProvider { CodexCli, OpenCode, GithubCopilot, - GeminiCli, Antigravity, GrokBuild, } impl AgentProvider { - pub const ALL: [AgentProvider; 7] = [ + pub const ALL: [AgentProvider; 6] = [ AgentProvider::ClaudeCode, AgentProvider::CodexCli, AgentProvider::OpenCode, AgentProvider::GithubCopilot, - AgentProvider::GeminiCli, AgentProvider::Antigravity, AgentProvider::GrokBuild, ]; @@ -54,7 +52,6 @@ impl AgentProvider { AgentProvider::CodexCli => "Codex CLI", AgentProvider::OpenCode => "OpenCode", AgentProvider::GithubCopilot => "GitHub Copilot", - AgentProvider::GeminiCli => "Gemini CLI", AgentProvider::Antigravity => "Antigravity", AgentProvider::GrokBuild => "Grok Build", } @@ -70,7 +67,6 @@ impl AgentProvider { AgentProvider::CodexCli => "settings.provider.codexCli", AgentProvider::OpenCode => "settings.provider.openCode", AgentProvider::GithubCopilot => "settings.provider.githubCopilot", - AgentProvider::GeminiCli => "settings.provider.geminiCli", AgentProvider::Antigravity => "settings.provider.antigravity", AgentProvider::GrokBuild => "settings.provider.grokBuild", } @@ -78,14 +74,13 @@ impl AgentProvider { } /// Terminal-side MCP integrations the user can flip on/off. Order -/// matches the product's MCP settings grid (Claude / Codex / Gemini / -/// OpenCode / Kiro / Copilot / Antigravity / Grok Build) so the index is +/// matches the product's MCP settings grid (Claude / Codex / OpenCode / +/// Kiro / Copilot / Antigravity / Grok Build) so the index is /// reusable for both layout and `mcp_cli_enabled[i]`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum McpCli { ClaudeCode, Codex, - Gemini, OpenCode, Kiro, GithubCopilot, @@ -94,10 +89,9 @@ pub enum McpCli { } impl McpCli { - pub const ALL: [McpCli; 8] = [ + pub const ALL: [McpCli; 7] = [ McpCli::ClaudeCode, McpCli::Codex, - McpCli::Gemini, McpCli::OpenCode, McpCli::Kiro, McpCli::GithubCopilot, @@ -108,7 +102,6 @@ impl McpCli { match self { McpCli::ClaudeCode => "Claude Code CLI", McpCli::Codex => "Codex CLI", - McpCli::Gemini => "Gemini CLI", McpCli::OpenCode => "OpenCode CLI", McpCli::Kiro => "Kiro CLI", McpCli::GithubCopilot => "GitHub Copilot CLI", @@ -147,13 +140,13 @@ pub enum SettingsFocus { #[derive(Debug, Clone, Copy)] pub struct AgentSettings { pub tab: AgentSettingsTab, - pub connected: [bool; 7], + pub connected: [bool; 6], /// Vertical scroll offset of the right content pane in px. /// Clamped to `[0, content_height - viewport_height]` by the /// host on wheel input. pub scroll_y: f32, pub mcp_server: McpServer, - pub mcp_cli_enabled: [bool; 8], + pub mcp_cli_enabled: [bool; 7], pub images_advanced_open: bool, pub images_search_ready: bool, /// Currently-focused editable input on the modal. `None` while @@ -177,10 +170,10 @@ impl Default for AgentSettings { tab: AgentSettingsTab::Agents, // Connection state is wired manually for now — no auth // backend exists, so every provider starts disconnected. - connected: [false; 7], + connected: [false; 6], scroll_y: 0.0, mcp_server: McpServer::default(), - mcp_cli_enabled: [false; 8], + mcp_cli_enabled: [false; 7], images_advanced_open: true, images_search_ready: true, focus: None, diff --git a/crates/op-ai/src/chat_provider.rs b/crates/op-ai/src/chat_provider.rs index 822b115e4..957ec917e 100644 --- a/crates/op-ai/src/chat_provider.rs +++ b/crates/op-ai/src/chat_provider.rs @@ -6,8 +6,8 @@ //! against the user's chosen `Provider` (Anthropic, OpenAI-compat, //! Ollama, ...). This is the OP-native agent. //! - **Subprocess(CliName)** — spawn an external CLI binary -//! (Claude Code / Gemini / Copilot) and pipe line-delimited JSON -//! over its stdin / stdout. +//! (Claude Code / Copilot / Antigravity / Grok Build) and pipe +//! line-delimited JSON over its stdin / stdout. //! - **HttpServer(CliName)** — spawn `codex serve` / `opencode serve` //! and hit its local HTTP/SSE endpoint with reqwest. //! - **Acp** — Agent Client Protocol (ndJSON over stdio); the @@ -31,8 +31,6 @@ use std::sync::Arc; pub enum CliName { /// Anthropic's `claude` CLI (subprocess IPC). ClaudeCode, - /// Google's `gemini` CLI (subprocess IPC). - Gemini, /// GitHub Copilot CLI (subprocess IPC). Copilot, /// OpenAI Codex CLI (HTTP server mode). @@ -49,7 +47,6 @@ impl CliName { pub fn label(self) -> &'static str { match self { CliName::ClaudeCode => "Claude Code", - CliName::Gemini => "Gemini", CliName::Copilot => "GitHub Copilot", CliName::Codex => "Codex", CliName::OpenCode => "OpenCode", @@ -63,7 +60,6 @@ impl CliName { pub fn default_binary(self) -> &'static str { match self { CliName::ClaudeCode => "claude", - CliName::Gemini => "gemini", // The standalone `copilot` CLI (the `gh-copilot` gh // extension is retired; the official SDK + model // discovery both target `copilot`). @@ -76,14 +72,13 @@ impl CliName { } /// Which backend transport this CLI uses. Mirrors the table in /// [[project_agent_runtime]] memory: - /// Claude/Gemini/Copilot = subprocess IPC; Codex/OpenCode = HTTP server. + /// Claude/Copilot/Antigravity/Grok Build = subprocess IPC; + /// Codex/OpenCode = HTTP server. pub fn backend(self) -> ChatProviderKind { match self { - CliName::ClaudeCode - | CliName::Gemini - | CliName::Copilot - | CliName::Antigravity - | CliName::GrokBuild => ChatProviderKind::Subprocess(self), + CliName::ClaudeCode | CliName::Copilot | CliName::Antigravity | CliName::GrokBuild => { + ChatProviderKind::Subprocess(self) + } CliName::Codex | CliName::OpenCode => ChatProviderKind::HttpServer(self), } } @@ -285,8 +280,8 @@ pub struct ChatRequest { pub attachments: Vec, /// Model id the user picked in the chat model picker (e.g. /// `gpt-5.5`, `claude-sonnet-4-6`). Each transport forwards it on - /// its own knob (`--model` for Codex, `-m` for Gemini, SDK - /// `options.model` for Claude Code / Copilot). `None` keeps the + /// its own knob (`--model` for Codex / Antigravity, `-m` for + /// Grok Build, SDK `options.model` for Claude Code / Copilot). `None` keeps the /// provider's own default — TS parity: every provider in /// `apps/web/server/api/ai/chat.ts` only sets the model when one /// was supplied. @@ -438,16 +433,12 @@ mod tests { #[test] fn cli_name_backend_table_matches_architecture_memo() { // project_agent_runtime memory: - // Subprocess IPC = Claude Code / Gemini / Copilot + // Subprocess IPC = Claude Code / Copilot / Antigravity / Grok Build // HTTP server = Codex / OpenCode assert!(matches!( CliName::ClaudeCode.backend(), ChatProviderKind::Subprocess(_) )); - assert!(matches!( - CliName::Gemini.backend(), - ChatProviderKind::Subprocess(_) - )); assert!(matches!( CliName::Copilot.backend(), ChatProviderKind::Subprocess(_) diff --git a/crates/op-cli/assets/skill-bundle.json b/crates/op-cli/assets/skill-bundle.json index 42e070835..98aa9ef2e 100644 --- a/crates/op-cli/assets/skill-bundle.json +++ b/crates/op-cli/assets/skill-bundle.json @@ -5,8 +5,6 @@ ".claude-plugin/plugin.json": "{\n \"name\": \"openpencil-skill\",\n \"description\": \"Design skill for OpenPencil — op CLI, batch DSL, MCP tools, PenNode schema, and UI design best practices\",\n \"version\": \"__OPENPENCIL_VERSION__\",\n \"author\": {\n \"name\": \"ZSeven-W\",\n \"email\": \"xkayshen@gmail.com\"\n },\n \"homepage\": \"https://github.com/zseven-w/openpencil-skill\",\n \"repository\": \"https://github.com/zseven-w/openpencil-skill\",\n \"license\": \"MIT\",\n \"keywords\": [\n \"design\",\n \"ui\",\n \"vector\",\n \"openpencil\",\n \"cli\",\n \"mcp\",\n \"dsl\"\n ]\n}\n", ".claude-plugin/marketplace.json": "{\n \"name\": \"openpencil-skill\",\n \"description\": \"Design skill for OpenPencil — op CLI, batch DSL, MCP tools, and UI best practices\",\n \"owner\": {\n \"name\": \"ZSeven-W\",\n \"email\": \"xkayshen@gmail.com\"\n },\n \"plugins\": [\n {\n \"name\": \"openpencil-skill\",\n \"description\": \"Design skill for OpenPencil — op CLI, batch DSL, MCP tools, PenNode schema, and UI design best practices\",\n \"version\": \"__OPENPENCIL_VERSION__\",\n \"source\": \"./\",\n \"author\": {\n \"name\": \"ZSeven-W\",\n \"email\": \"xkayshen@gmail.com\"\n }\n }\n ]\n}\n", ".cursor-plugin/plugin.json": "{\n \"name\": \"openpencil-skill\",\n \"displayName\": \"OpenPencil Design\",\n \"description\": \"Design skill for OpenPencil — op CLI, batch DSL, MCP tools, PenNode schema, and UI design best practices\",\n \"version\": \"__OPENPENCIL_VERSION__\",\n \"author\": {\n \"name\": \"ZSeven-W\",\n \"email\": \"xkayshen@gmail.com\"\n },\n \"homepage\": \"https://github.com/zseven-w/openpencil-skill\",\n \"repository\": \"https://github.com/zseven-w/openpencil-skill\",\n \"license\": \"MIT\",\n \"keywords\": [\n \"design\",\n \"ui\",\n \"vector\",\n \"openpencil\",\n \"cli\",\n \"mcp\",\n \"dsl\"\n ],\n \"skills\": \"./skills/\"\n}\n", - "package.json": "{\n \"name\": \"openpencil-skill\",\n \"version\": \"__OPENPENCIL_VERSION__\",\n \"type\": \"module\"\n}\n", - "GEMINI.md": "@./skills/openpencil-design/SKILL.md\n", - "gemini-extension.json": "{\n \"name\": \"openpencil-skill\",\n \"description\": \"Design skill for OpenPencil — op CLI, batch DSL, MCP tools, and UI best practices\",\n \"version\": \"__OPENPENCIL_VERSION__\",\n \"contextFileName\": \"GEMINI.md\"\n}\n" + "package.json": "{\n \"name\": \"openpencil-skill\",\n \"version\": \"__OPENPENCIL_VERSION__\",\n \"type\": \"module\"\n}\n" } } diff --git a/crates/op-cli/src/skill_install_cli.rs b/crates/op-cli/src/skill_install_cli.rs index 14f2f0516..06859c97d 100644 --- a/crates/op-cli/src/skill_install_cli.rs +++ b/crates/op-cli/src/skill_install_cli.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; const BUNDLE_JSON: &str = include_str!("../assets/skill-bundle.json"); const VERSION_SENTINEL: &str = "__OPENPENCIL_VERSION__"; -// Top-level bundle version plus five embedded plugin/package manifest versions. -const EXPECTED_VERSION_SENTINEL_COUNT: usize = 6; +// Top-level bundle version plus four embedded plugin/package manifest versions. +const EXPECTED_VERSION_SENTINEL_COUNT: usize = 5; const REPO: &str = "zseven-w/openpencil-skill"; const SKILL_NAME: &str = "openpencil-skill"; @@ -21,7 +21,6 @@ enum Target { Claude, Codex, Cursor, - Gemini, OpenCode, } @@ -31,10 +30,9 @@ impl Target { "claude" | "claude-code" | "claudecode" => Ok(Target::Claude), "codex" => Ok(Target::Codex), "cursor" => Ok(Target::Cursor), - "gemini" | "gemini-cli" => Ok(Target::Gemini), "opencode" | "open-code" => Ok(Target::OpenCode), _ => Err(format!( - "unknown target {raw:?}; available: claude, codex, cursor, gemini, opencode" + "unknown target {raw:?}; available: claude, codex, cursor, opencode" )), } } @@ -44,7 +42,6 @@ impl Target { Target::Claude => "claude", Target::Codex => "codex", Target::Cursor => "cursor", - Target::Gemini => "gemini", Target::OpenCode => "opencode", } } @@ -110,7 +107,7 @@ fn resolve_targets( let detected = detect_targets(home); if detected.is_empty() && matches!(action, Action::Install) { return Err( - "no supported AI coding agents detected; pass --target claude|codex|cursor|gemini|opencode" + "no supported AI coding agents detected; pass --target claude|codex|cursor|opencode" .into(), ); } @@ -128,9 +125,6 @@ fn detect_targets(home: &Path) -> Vec { if home.join(".cursor").exists() { targets.push(Target::Cursor); } - if command_exists("gemini") { - targets.push(Target::Gemini); - } if command_exists("opencode") { targets.push(Target::OpenCode); } @@ -152,9 +146,6 @@ fn install_target(target: Target, home: &Path, bundle: &SkillBundle) -> Result<( Target::Claude => install_claude(home, bundle), Target::Codex => install_codex(home, bundle), Target::Cursor => write_bundle_to(&home.join(".cursor/plugins").join(SKILL_NAME), bundle), - Target::Gemini => { - write_bundle_to(&home.join(".gemini/extensions").join(SKILL_NAME), bundle) - } Target::OpenCode => install_opencode(home, bundle), } } @@ -164,7 +155,6 @@ fn uninstall_target(target: Target, home: &Path) -> Result<(), String> { Target::Claude => uninstall_claude(home), Target::Codex => uninstall_codex(home), Target::Cursor => remove_path(&home.join(".cursor/plugins").join(SKILL_NAME)), - Target::Gemini => remove_path(&home.join(".gemini/extensions").join(SKILL_NAME)), Target::OpenCode => uninstall_opencode(home), } } @@ -491,7 +481,6 @@ mod tests { ".claude-plugin/plugin.json", ".cursor-plugin/plugin.json", "package.json", - "gemini-extension.json", ] { let content = bundle .files @@ -544,11 +533,26 @@ mod tests { fn bundle_renderer_rejects_partially_templated_versions() { let partial_template = BUNDLE_JSON.replacen(VERSION_SENTINEL, env!("CARGO_PKG_VERSION"), 1); let error = render_bundle_template(&partial_template, env!("CARGO_PKG_VERSION")) - .expect_err("template with only five version sentinels should fail"); + .expect_err("partially rendered template should fail"); let expected = format!("expected {EXPECTED_VERSION_SENTINEL_COUNT}"); let found = format!("found {}", EXPECTED_VERSION_SENTINEL_COUNT - 1); assert!(error.contains(&expected), "unexpected error: {error}"); assert!(error.contains(&found), "unexpected error: {error}"); } + + #[test] + fn gemini_cli_is_not_an_install_target() { + let error = super::Target::parse("gemini-cli") + .expect_err("retired Gemini CLI integration must stay unavailable"); + + assert!( + error.contains("unknown target"), + "unexpected error: {error}" + ); + assert!( + !error.contains("available: gemini"), + "unexpected error: {error}" + ); + } } diff --git a/crates/op-editor-core/src/agent_provider_wire.rs b/crates/op-editor-core/src/agent_provider_wire.rs index 9032b7da3..bbf1b273b 100644 --- a/crates/op-editor-core/src/agent_provider_wire.rs +++ b/crates/op-editor-core/src/agent_provider_wire.rs @@ -8,7 +8,6 @@ impl AgentProvider { Self::CodexCli => "codex-cli", Self::OpenCode => "open-code", Self::GithubCopilot => "github-copilot", - Self::GeminiCli => "gemini-cli", Self::Antigravity => "antigravity", Self::GrokBuild => "grok-build", } @@ -21,7 +20,6 @@ impl AgentProvider { "codex-cli" => Some(Self::CodexCli), "open-code" => Some(Self::OpenCode), "github-copilot" => Some(Self::GithubCopilot), - "gemini-cli" => Some(Self::GeminiCli), "antigravity" => Some(Self::Antigravity), "grok-build" => Some(Self::GrokBuild), _ => None, @@ -42,5 +40,6 @@ mod tests { ); } assert_eq!(AgentProvider::from_wire_id("default"), None); + assert_eq!(AgentProvider::from_wire_id("gemini-cli"), None); } } diff --git a/crates/op-editor-core/src/agent_settings.rs b/crates/op-editor-core/src/agent_settings.rs index 8b9176db4..2cb96f283 100644 --- a/crates/op-editor-core/src/agent_settings.rs +++ b/crates/op-editor-core/src/agent_settings.rs @@ -57,7 +57,6 @@ impl AgentSettingsTab { pub enum McpCli { ClaudeCode, Codex, - Gemini, OpenCode, Kiro, GithubCopilot, @@ -66,10 +65,9 @@ pub enum McpCli { } impl McpCli { - pub const ALL: [McpCli; 8] = [ + pub const ALL: [McpCli; 7] = [ McpCli::ClaudeCode, McpCli::Codex, - McpCli::Gemini, McpCli::OpenCode, McpCli::Kiro, McpCli::GithubCopilot, @@ -81,7 +79,6 @@ impl McpCli { match self { McpCli::ClaudeCode => "Claude Code CLI", McpCli::Codex => "Codex CLI", - McpCli::Gemini => "Gemini CLI", McpCli::OpenCode => "OpenCode CLI", McpCli::Kiro => "Kiro CLI", McpCli::GithubCopilot => "GitHub Copilot CLI", @@ -416,7 +413,7 @@ pub struct ImageGenProfile { #[derive(Debug, Clone, PartialEq)] pub struct AgentSettings { pub tab: AgentSettingsTab, - pub connected: [bool; 7], + pub connected: [bool; 6], /// The embedding host's real MCP endpoint (e.g. the VS Code /// extension's McpProxy URL), delivered via the bridge `init` /// message. When set, the MCP tab's client-config card displays @@ -426,7 +423,7 @@ pub struct AgentSettings { pub embed_mcp_url: Option, /// Probe-derived per-provider connect status, indexed like /// `connected`. Runtime-only — not persisted. - pub provider_connection: [ProviderConnection; 7], + pub provider_connection: [ProviderConnection; 6], /// Connect-press request seam — the desktop host drains this /// into the async provider probe (`provider_probe_host.rs`). pub pending_provider_connect: Option, @@ -450,7 +447,7 @@ pub struct AgentSettings { pub acp_agent_connection: BTreeMap, pub scroll_y: jian_core::scroll::ScrollState, pub mcp_server: McpServer, - pub mcp_cli_enabled: [bool; 8], + pub mcp_cli_enabled: [bool; 7], pub mcp_client_config_copied_at_ms: Option, pub hover_agent_settings_close: bool, pub hover_mcp_server_button: bool, @@ -502,7 +499,7 @@ impl Default for AgentSettings { fn default() -> Self { Self { tab: AgentSettingsTab::Agents, - connected: [false; 7], + connected: [false; 6], embed_mcp_url: None, provider_connection: Default::default(), pending_provider_connect: None, @@ -520,7 +517,7 @@ impl Default for AgentSettings { acp_agent_connection: BTreeMap::new(), scroll_y: Default::default(), mcp_server: McpServer::default(), - mcp_cli_enabled: [false; 8], + mcp_cli_enabled: [false; 7], mcp_client_config_copied_at_ms: None, hover_agent_settings_close: false, hover_mcp_server_button: false, diff --git a/crates/op-editor-core/src/agent_settings_connection.rs b/crates/op-editor-core/src/agent_settings_connection.rs index 3748c4c0e..c6f5553b5 100644 --- a/crates/op-editor-core/src/agent_settings_connection.rs +++ b/crates/op-editor-core/src/agent_settings_connection.rs @@ -56,8 +56,7 @@ pub struct ProviderConnection { /// Config-file path hint (TS `hintPath`). pub hint_path: Option, /// CLI version string when the probe ran a version check - /// (`codex --version` / `gemini --version`, mirroring the TS - /// responsiveness gates). + /// (for example, `codex --version`). pub version: Option, } @@ -172,7 +171,7 @@ impl AgentSettings { self.provider_verified_connected_at(Self::provider_index(provider)) } - pub fn verified_connected_mask(&self) -> [bool; 7] { + pub fn verified_connected_mask(&self) -> [bool; 6] { std::array::from_fn(|i| self.provider_verified_connected_at(i)) } @@ -303,20 +302,20 @@ mod tests { fn not_installed_outcome_carries_install_guidance() { let mut s = AgentSettings::default(); s.apply_provider_connect_outcome( - AgentProvider::GeminiCli, + AgentProvider::CodexCli, ProviderConnectOutcome { connected: false, not_installed: true, - install_command: Some("npm install -g @anthropic-ai/gemini-cli".into()), - error: Some("Gemini CLI not found".into()), + install_command: Some("npm install -g @openai/codex".into()), + error: Some("Codex CLI not found".into()), ..ProviderConnectOutcome::default() }, ); - let conn = &s.provider_connection[4]; + let conn = &s.provider_connection[1]; assert!(conn.not_installed); assert_eq!( conn.install_command.as_deref(), - Some("npm install -g @anthropic-ai/gemini-cli") + Some("npm install -g @openai/codex") ); } @@ -342,7 +341,7 @@ mod tests { assert!(s.provider_verified_connected(AgentProvider::ClaudeCode)); assert_eq!( s.verified_connected_mask(), - [true, false, false, false, false, false, false] + [true, false, false, false, false, false] ); } } diff --git a/crates/op-editor-core/src/chat.rs b/crates/op-editor-core/src/chat.rs index 7cee88104..99c46265a 100644 --- a/crates/op-editor-core/src/chat.rs +++ b/crates/op-editor-core/src/chat.rs @@ -33,18 +33,16 @@ pub enum AgentProvider { CodexCli, OpenCode, GithubCopilot, - GeminiCli, Antigravity, GrokBuild, } impl AgentProvider { - pub const ALL: [AgentProvider; 7] = [ + pub const ALL: [AgentProvider; 6] = [ AgentProvider::ClaudeCode, AgentProvider::CodexCli, AgentProvider::OpenCode, AgentProvider::GithubCopilot, - AgentProvider::GeminiCli, AgentProvider::Antigravity, AgentProvider::GrokBuild, ]; @@ -55,7 +53,6 @@ impl AgentProvider { AgentProvider::CodexCli => "Codex CLI", AgentProvider::OpenCode => "OpenCode", AgentProvider::GithubCopilot => "GitHub Copilot", - AgentProvider::GeminiCli => "Gemini CLI", AgentProvider::Antigravity => "Antigravity", AgentProvider::GrokBuild => "Grok Build", } @@ -68,7 +65,6 @@ impl AgentProvider { AgentProvider::CodexCli => "settings.provider.codexCli", AgentProvider::OpenCode => "settings.provider.openCode", AgentProvider::GithubCopilot => "settings.provider.githubCopilot", - AgentProvider::GeminiCli => "settings.provider.geminiCli", AgentProvider::Antigravity => "settings.provider.antigravity", AgentProvider::GrokBuild => "settings.provider.grokBuild", } @@ -544,7 +540,7 @@ impl ChatState { /// /// [`available_models`]: ChatState::available_models /// [`discovered_models`]: ChatState::discovered_models - pub fn rebuild_available_models(&mut self, connected: &[bool; 7]) { + pub fn rebuild_available_models(&mut self, connected: &[bool; 6]) { let prev = self.available_models.get(self.selected_model).cloned(); self.available_models = self .discovered_models @@ -1464,7 +1460,7 @@ mod tests { ..Default::default() }; // Only Claude Code (index 0 of AgentProvider::ALL) connected. - let mut connected = [false; 7]; + let mut connected = [false; 6]; connected[0] = true; chat.rebuild_available_models(&connected); assert_eq!(chat.available_models.len(), 2); @@ -1483,7 +1479,7 @@ mod tests { ], ..Default::default() }; - let mut connected = [false; 7]; + let mut connected = [false; 6]; connected[0] = true; // Claude connected[1] = true; // Codex chat.rebuild_available_models(&connected); diff --git a/crates/op-editor-core/src/tests_agent_settings.rs b/crates/op-editor-core/src/tests_agent_settings.rs index d9751a651..6e3ec7cd6 100644 --- a/crates/op-editor-core/src/tests_agent_settings.rs +++ b/crates/op-editor-core/src/tests_agent_settings.rs @@ -2,13 +2,13 @@ use crate::agent_settings::{ AcpConnectionType, AgentSettings, AgentSettingsTab, BuiltinAgentConfig, BuiltinAgentKind, ImageGenProvider, ImageTestStatus, McpCli, }; -use crate::agent_settings_builtin_presets::BuiltinAgentPresetKey; +use crate::agent_settings_builtin_presets::{builtin_agent_preset, BuiltinAgentPresetKey}; #[test] fn default_settings_are_quiescent() { let s = AgentSettings::default(); assert_eq!(s.tab, AgentSettingsTab::Agents); - assert_eq!(s.connected, [false; 7]); + assert_eq!(s.connected, [false; 6]); assert!(s.builtin_agents.is_empty()); assert!(s.builtin_agent_draft.is_none()); assert!(s.acp_agent_draft.is_none()); @@ -31,7 +31,7 @@ fn default_settings_are_quiescent() { #[test] fn tab_and_cli_arrays_cover_all_variants() { assert_eq!(AgentSettingsTab::ALL.len(), 6); - assert_eq!(McpCli::ALL.len(), 8); + assert_eq!(McpCli::ALL.len(), 7); } #[test] @@ -142,6 +142,19 @@ fn add_builtin_agent_prefills_ts_provider_presets_first() { ); } +#[test] +fn gemini_api_preset_remains_available_after_cli_retirement() { + let preset = builtin_agent_preset(BuiltinAgentPresetKey::Gemini); + + assert_eq!(preset.display_name, "Google Gemini"); + assert_eq!(preset.kind, BuiltinAgentKind::OpenAiCompat); + assert_eq!(preset.model, "gemini-3-flash-preview"); + assert_eq!( + preset.base_url, + "https://generativelanguage.googleapis.com/v1beta/openai" + ); +} + #[test] fn ark_coding_builtin_agent_infers_ark_coding_preset() { let mut s = AgentSettings::default(); diff --git a/crates/op-editor-core/src/tests_mutators.rs b/crates/op-editor-core/src/tests_mutators.rs index 3a221d179..56592317f 100644 --- a/crates/op-editor-core/src/tests_mutators.rs +++ b/crates/op-editor-core/src/tests_mutators.rs @@ -609,12 +609,16 @@ fn select_chat_model_picks_model_and_syncs_agent() { let mut s = sample(); s.chat.available_models = vec![ crate::ModelEntry::new(crate::AgentProvider::ClaudeCode, "claude", "Claude"), - crate::ModelEntry::new(crate::AgentProvider::GeminiCli, "gemini", "Gemini"), + crate::ModelEntry::new( + crate::AgentProvider::Antigravity, + "antigravity", + "Antigravity", + ), ]; s.editor_ui.chat_model_picker.open = true; s.select_chat_model(1); assert_eq!(s.chat.selected_model, 1); - // GeminiCli is index 4 in AgentProvider::ALL. + // Antigravity is index 4 in AgentProvider::ALL. assert_eq!(s.editor_ui.chat_selected_agent, 4); // Picker closes on selection. assert!(!s.editor_ui.chat_model_picker.open); @@ -667,7 +671,7 @@ fn rebuild_chat_models_syncs_agent_to_selected_model_provider() { "gpt-5.5", "GPT-5.5", )]; - s.editor_ui.agent_settings.connected = [false, true, false, false, false, false, false]; + s.editor_ui.agent_settings.connected = [false, true, false, false, false, false]; s.editor_ui.agent_settings.provider_connection[1].phase = crate::agent_settings::ProviderConnectPhase::Connected; s.editor_ui.chat_selected_agent = 0; @@ -682,7 +686,7 @@ fn rebuild_chat_models_syncs_agent_to_selected_model_provider() { fn rebuild_chat_models_does_not_invent_cli_models_without_discovery() { let mut s = sample(); s.chat.discovered_models.clear(); - s.editor_ui.agent_settings.connected = [false, true, false, false, false, false, false]; + s.editor_ui.agent_settings.connected = [false, true, false, false, false, false]; s.rebuild_chat_models(); diff --git a/crates/op-editor-ui/src/widgets/agent_settings_connect_tests.rs b/crates/op-editor-ui/src/widgets/agent_settings_connect_tests.rs index 9b18f9412..88be05886 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_connect_tests.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_connect_tests.rs @@ -166,10 +166,10 @@ fn failed_probe_paints_error_in_destructive_red() { fn not_installed_card_paints_amber_install_guidance() { let mut state = EditorState::default(); let settings = &mut state.editor_ui.agent_settings; - settings.provider_connection[4].phase = ProviderConnectPhase::Error; - settings.provider_connection[4].not_installed = true; - settings.provider_connection[4].install_command = - Some("npm install -g @anthropic-ai/gemini-cli".to_string()); + settings.provider_connection[1].phase = ProviderConnectPhase::Error; + settings.provider_connection[1].not_installed = true; + settings.provider_connection[1].install_command = + Some("npm install -g @openai/codex".to_string()); let capture = paint_panel(&mut state); let (text, color) = find_text(&capture, "Not installed") .expect("not-installed card should show install guidance"); @@ -177,7 +177,7 @@ fn not_installed_card_paints_amber_install_guidance() { // install command may ellipsize at the tail; the actionable prefix must // still paint so the user knows what to run. assert!( - text.contains("npm install -g @anthropic-ai/gemin"), + text.contains("npm install -g @openai/codex"), "guidance line should carry the install command prefix, got: {text}" ); let amber = (Color { diff --git a/crates/op-editor-ui/src/widgets/agent_settings_panel_card.rs b/crates/op-editor-ui/src/widgets/agent_settings_panel_card.rs index d70105d39..899c8c017 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_panel_card.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_panel_card.rs @@ -81,13 +81,6 @@ pub(super) fn paint_agent_card( AVATAR_ICON, theme.foreground, ), - AgentProvider::GeminiCli => paint_brand_logo( - cx.backend, - BrandLogo::Gemini, - icon_top_left, - AVATAR_ICON, - theme.foreground, - ), AgentProvider::Antigravity => paint_brand_logo( cx.backend, BrandLogo::Antigravity, diff --git a/crates/op-editor-ui/src/widgets/ai_chat_model_picker.rs b/crates/op-editor-ui/src/widgets/ai_chat_model_picker.rs index f4b0a2572..8372cf1ce 100644 --- a/crates/op-editor-ui/src/widgets/ai_chat_model_picker.rs +++ b/crates/op-editor-ui/src/widgets/ai_chat_model_picker.rs @@ -608,9 +608,6 @@ pub fn paint_provider_logo( AgentProvider::CodexCli => { paint_brand_logo(cx.backend, BrandLogo::OpenAI, top_left, size, color) } - AgentProvider::GeminiCli => { - paint_brand_logo(cx.backend, BrandLogo::Gemini, top_left, size, color) - } AgentProvider::GithubCopilot => { paint_brand_logo(cx.backend, BrandLogo::Copilot, top_left, size, color) } @@ -630,7 +627,6 @@ pub(super) fn provider_label(provider: AgentProvider) -> &'static str { match provider { AgentProvider::ClaudeCode => "ANTHROPIC", AgentProvider::CodexCli => "OPENAI", - AgentProvider::GeminiCli => "GOOGLE GEMINI", AgentProvider::GithubCopilot => "GITHUB COPILOT", AgentProvider::OpenCode => "OPENCODE", AgentProvider::Antigravity => "ANTIGRAVITY", @@ -643,7 +639,6 @@ fn group_label(provider: AgentProvider, builtin: bool) -> &'static str { match provider { AgentProvider::ClaudeCode => "ANTHROPIC API KEY", AgentProvider::CodexCli => "OPENAI API KEY", - AgentProvider::GeminiCli => "GEMINI API KEY", AgentProvider::GithubCopilot => "COPILOT API KEY", AgentProvider::OpenCode => "OPENCODE API KEY", AgentProvider::Antigravity => "ANTIGRAVITY API KEY", diff --git a/crates/op-editor-ui/src/widgets/ai_chat_model_picker_tests.rs b/crates/op-editor-ui/src/widgets/ai_chat_model_picker_tests.rs index ddd06c2b0..dbe6196c6 100644 --- a/crates/op-editor-ui/src/widgets/ai_chat_model_picker_tests.rs +++ b/crates/op-editor-ui/src/widgets/ai_chat_model_picker_tests.rs @@ -378,8 +378,7 @@ fn builtin_group_header_falls_back_to_generic_label_without_retained_name() { } #[test] -fn gemini_provider_group_label_matches_ts_provider_name() { - assert_eq!(provider_label(AgentProvider::GeminiCli), "GOOGLE GEMINI"); +fn newer_provider_group_labels_match_their_provider_names() { assert_eq!(provider_label(AgentProvider::Antigravity), "ANTIGRAVITY"); assert_eq!(provider_label(AgentProvider::GrokBuild), "GROK BUILD"); } diff --git a/crates/op-editor-ui/src/widgets/brand_icons.rs b/crates/op-editor-ui/src/widgets/brand_icons.rs index d4863bd91..ebe96c641 100644 --- a/crates/op-editor-ui/src/widgets/brand_icons.rs +++ b/crates/op-editor-ui/src/widgets/brand_icons.rs @@ -1,8 +1,8 @@ //! Brand logos for the agent-settings provider cards. //! //! Lucide-flavored stroke icons (in `icons.rs`) are wrong for the -//! AI provider avatars because Anthropic / OpenAI / Google / GitHub -//! / OpenCode ship filled-path logos with their own viewBoxes — +//! AI provider avatars because Anthropic / OpenAI / Google / xAI / +//! GitHub / OpenCode ship brand-specific logos with their own viewBoxes — //! lucide approximations (Sparkles / Component / Diamond …) don't //! read as the real brand. Path strings here are copied verbatim //! from `apps/web/src/components/icons/*-logo.tsx` so the native @@ -21,7 +21,7 @@ const CLAUDE_D: &str = "M19.7986 25.3287L27.6214 29.7179L27.753 30.0991L27.6214 /// OpenAI — 64×64 viewBox, single filled sub-path. const OPENAI_D: &str = "M51.0515 31.4958C51.4895 32.4869 51.7674 33.5463 51.8811 34.627C51.9906 35.7078 51.9359 36.8013 51.7085 37.865C51.4853 38.9286 51.0978 39.9496 50.5588 40.8894C50.205 41.5173 49.7881 42.1068 49.308 42.6493C48.8321 43.1875 48.3015 43.6745 47.7246 44.1017C47.1434 44.5289 46.5243 44.8877 45.8674 45.1824C45.2146 45.4729 44.5324 45.695 43.8333 45.8403C43.5048 46.874 43.0163 47.8523 42.3846 48.7322C41.7571 49.6122 40.9949 50.3854 40.1273 51.0219C39.2598 51.6626 38.2996 52.1582 37.2805 52.4914C36.2613 52.8288 35.1958 52.9954 34.122 52.9954C33.4102 52.9997 32.6943 52.9228 31.9952 52.7776C31.3004 52.6281 30.6181 52.4017 29.9654 52.1069C29.3126 51.8122 28.6935 51.4448 28.1166 51.0176C27.5439 50.5904 27.0132 50.0992 26.5416 49.5567C25.4887 49.7874 24.4106 49.8429 23.3452 49.7318C22.2797 49.6165 21.2353 49.3346 20.254 48.8903C19.277 48.4503 18.3716 47.8523 17.5756 47.1218C16.7797 46.3913 16.1017 45.537 15.5668 44.5972C15.2089 43.9693 14.9141 43.3072 14.6909 42.6194C14.4677 41.9317 14.3203 41.2226 14.2445 40.5006C14.1687 39.783 14.1729 39.0568 14.2487 38.3349C14.3245 37.6172 14.4803 36.9081 14.7035 36.2204C13.9876 35.413 13.398 34.4946 12.96 33.5035C12.5262 32.5082 12.2441 31.4531 12.1346 30.3724C12.0209 29.2916 12.0798 28.1981 12.303 27.1344C12.5262 26.0707 12.9137 25.0498 13.4527 24.11C13.8065 23.4821 14.2234 22.8883 14.6993 22.3501C15.1752 21.8118 15.71 21.3249 16.287 20.8977C16.8639 20.4705 17.4872 20.1074 18.1399 19.8169C18.7969 19.5222 19.4792 19.3043 20.1782 19.1591C20.5067 18.1211 20.9952 17.1471 21.6227 16.2671C22.2544 15.3872 23.0167 14.614 23.8842 13.9732C24.7517 13.3367 25.7119 12.8412 26.7311 12.5038C27.7502 12.1706 28.8157 11.9997 29.8896 12.004C30.6013 11.9997 31.3172 12.0723 32.0163 12.2218C32.7154 12.3713 33.3976 12.5935 34.0504 12.8882C34.7031 13.1872 35.3222 13.5503 35.8991 13.9775C36.4761 14.4089 37.0067 14.8959 37.4784 15.4384C38.527 15.212 39.6051 15.1565 40.6706 15.2676C41.736 15.3786 42.7762 15.6648 43.7575 16.1048C44.7345 16.5491 45.6399 17.1428 46.4359 17.8733C47.2318 18.5995 47.9099 19.4496 48.4447 20.3936C48.8027 21.0173 49.0975 21.6794 49.3207 22.3714C49.5439 23.0592 49.6955 23.7683 49.7671 24.4902C49.8429 25.2121 49.8429 25.9383 49.7628 26.6602C49.687 27.3822 49.5312 28.0913 49.308 28.779C50.0282 29.5864 50.6135 30.5005 51.0515 31.4958ZM37.0194 49.7318C37.9374 49.3474 38.7713 48.7792 39.4746 48.0659C40.1779 47.3525 40.738 46.5067 41.117 45.5712C41.496 44.6399 41.6939 43.6403 41.6939 42.6322V33.1063C41.6911 33.0977 41.6883 33.0878 41.6855 33.0764C41.6827 33.0678 41.6785 33.0593 41.6729 33.0507C41.6673 33.0422 41.6602 33.0351 41.6518 33.0294C41.6434 33.0208 41.635 33.0151 41.6265 33.0123L38.228 31.0217V42.5297C38.228 42.645 38.2112 42.7646 38.1817 42.8757C38.1522 42.991 38.1101 43.0978 38.0511 43.2004C37.9922 43.3029 37.9248 43.3969 37.8406 43.478C37.7587 43.5608 37.6667 43.6326 37.5668 43.6916L29.519 48.4033C29.4516 48.446 29.3379 48.5058 29.2789 48.54C29.6116 48.8262 29.9738 49.0783 30.3528 49.3004C30.736 49.5225 31.1319 49.7105 31.5446 49.8642C31.9573 50.0138 32.3827 50.1291 32.8122 50.206C33.246 50.2829 33.684 50.3213 34.122 50.3213C35.1158 50.3213 36.1013 50.1206 37.0194 49.7318ZM17.8536 43.2644C18.3547 44.1401 19.0159 44.9005 19.8034 45.5156C20.5952 46.1308 21.4922 46.5793 22.4524 46.8399C23.4125 47.1004 24.4148 47.1688 25.4003 47.0364C26.3857 46.9039 27.3333 46.5793 28.1966 46.0752L36.3329 41.3123L36.354 41.2909C36.3596 41.2852 36.3638 41.2767 36.3666 41.2653C36.3722 41.2567 36.3764 41.2482 36.3792 41.2396V37.2242L26.5584 42.9868C26.4573 43.0466 26.352 43.0893 26.2426 43.1235C26.1288 43.1534 26.0151 43.1662 25.8972 43.1662C25.7835 43.1662 25.6698 43.1534 25.5561 43.1235C25.4466 43.0893 25.3371 43.0466 25.236 42.9868L17.1882 38.2708C17.1166 38.2281 17.0113 38.164 16.9524 38.1256C16.8765 38.5655 16.8386 39.0098 16.8386 39.4541C16.8386 39.8983 16.8808 40.3426 16.9566 40.7826C17.0324 41.2183 17.1503 41.6497 17.2977 42.0684C17.4493 42.487 17.6346 42.8885 17.8536 43.273V43.2644ZM15.7395 25.4513C15.2426 26.3271 14.9225 27.2925 14.7919 28.292C14.6614 29.2916 14.7288 30.304 14.9857 31.2823C15.2426 32.2562 15.6847 33.1661 16.2912 33.9692C16.8976 34.768 17.6514 35.4386 18.5105 35.9427L26.6426 40.7099C26.6511 40.7128 26.6609 40.7156 26.6721 40.7185H26.7016C26.7128 40.7185 26.7226 40.7156 26.7311 40.7099C26.7395 40.7071 26.7479 40.7028 26.7563 40.6971L30.1675 38.698L20.3467 32.9482C20.2498 32.8884 20.1572 32.8158 20.073 32.7346C19.9913 32.6516 19.9206 32.5583 19.8624 32.457C19.8076 32.3545 19.7613 32.2477 19.7318 32.1323C19.7024 32.0213 19.6855 31.9059 19.6897 31.7863V22.0852C19.277 22.239 18.8769 22.427 18.4979 22.6491C18.1189 22.8755 17.7609 23.1318 17.424 23.418C17.0913 23.7042 16.7797 24.0203 16.4975 24.3621C16.2154 24.6995 15.9669 25.0669 15.7479 25.4513H15.7395ZM43.6733 32.0469C43.7743 32.1067 43.867 32.175 43.9512 32.2605C44.0312 32.3416 44.1028 32.4356 44.1618 32.5381C44.2165 32.6407 44.2628 32.7517 44.2923 32.8628C44.3176 32.9781 44.3344 33.0935 44.3302 33.2131V42.9142C45.6821 42.4101 46.8612 41.5258 47.733 40.3639C48.6089 39.202 49.1354 37.8137 49.2575 36.3613C49.3796 34.9089 49.0932 33.448 48.4278 32.1537C47.7625 30.8594 46.7475 29.7829 45.501 29.0567L37.3689 24.2894C37.3605 24.2866 37.3506 24.2837 37.3394 24.2809H37.3099C37.3015 24.2837 37.2917 24.2866 37.2805 24.2894C37.272 24.2923 37.2636 24.2966 37.2552 24.3023L33.8609 26.2929L43.6817 32.0469H43.6733ZM47.0634 26.8781H47.0592V26.8824L47.0634 26.8781ZM47.0592 26.8738C47.3034 25.4385 47.1392 23.9605 46.5833 22.6149C46.0316 21.2693 45.1093 20.1117 43.9301 19.2744C42.751 18.4414 41.3612 17.963 39.9252 17.8989C38.4849 17.8391 37.0615 18.1937 35.8149 18.9199L27.6828 23.6829C27.6744 23.6886 27.6674 23.6957 27.6618 23.7042L27.6449 23.7298C27.6421 23.7384 27.6393 23.7484 27.6365 23.7597C27.6337 23.7683 27.6323 23.7783 27.6323 23.7896V27.7709L37.4531 22.0169C37.5542 21.9571 37.6637 21.9144 37.7732 21.8802C37.8869 21.8503 38.0006 21.8375 38.1143 21.8375C38.2322 21.8375 38.3459 21.8503 38.4596 21.8802C38.5691 21.9144 38.6744 21.9571 38.7755 22.0169L46.8233 26.7329C46.8949 26.7756 47.0002 26.8354 47.0592 26.8738ZM25.7793 22.4654C25.7793 22.3501 25.7962 22.2347 25.8256 22.1194C25.8551 22.0083 25.8972 21.8973 25.9562 21.7948C26.0151 21.6965 26.0825 21.6025 26.1667 21.5171C26.2468 21.4359 26.3394 21.3633 26.4405 21.3078L34.4883 16.5961C34.5641 16.5491 34.6694 16.4893 34.7284 16.4594C33.625 15.5239 32.2774 14.9258 30.8498 14.7421C29.4221 14.5542 27.9734 14.7849 26.6721 15.4043C25.3666 16.0237 24.2632 17.0104 23.4926 18.2407C22.7219 19.4752 22.3134 20.902 22.3134 22.3629V31.8888C22.3162 31.9002 22.319 31.9102 22.3218 31.9187C22.3246 31.9273 22.3288 31.9358 22.3344 31.9444C22.3401 31.9529 22.3471 31.9615 22.3555 31.97C22.3611 31.9757 22.3695 31.9814 22.3808 31.9871L25.7793 33.9777V22.4654ZM27.6239 35.0542L31.9994 37.6172L36.375 35.0542V29.9324L32.0037 27.3694L27.6281 29.9324L27.6239 35.0542Z"; -/// Google Gemini — 65×65 viewBox, single filled 4-point sparkle. +/// Google Gemini — retained for built-in Gemini API branding. const GEMINI_D: &str = "M32.447 0c.68 0 1.273.465 1.439 1.125a38.904 38.904 0 001.999 5.905c2.152 5 5.105 9.376 8.854 13.125 3.751 3.75 8.126 6.703 13.125 8.855a38.98 38.98 0 005.906 1.999c.66.166 1.124.758 1.124 1.438 0 .68-.464 1.273-1.125 1.439a38.902 38.902 0 00-5.905 1.999c-5 2.152-9.375 5.105-13.125 8.854-3.749 3.751-6.702 8.126-8.854 13.125a38.973 38.973 0 00-2 5.906 1.485 1.485 0 01-1.438 1.124c-.68 0-1.272-.464-1.438-1.125a38.913 38.913 0 00-2-5.905c-2.151-5-5.103-9.375-8.854-13.125-3.75-3.749-8.125-6.702-13.125-8.854a38.973 38.973 0 00-5.905-2A1.485 1.485 0 010 32.448c0-.68.465-1.272 1.125-1.438a38.903 38.903 0 005.905-2c5-2.151 9.376-5.104 13.125-8.854 3.75-3.749 6.703-8.125 8.855-13.125a38.972 38.972 0 001.999-5.905A1.485 1.485 0 0132.447 0z"; /// Google Antigravity — supplied 24×24 single-path brand mark. diff --git a/crates/op-editor-ui/src/widgets/top_bar.rs b/crates/op-editor-ui/src/widgets/top_bar.rs index 4b1314130..e52ae2f78 100644 --- a/crates/op-editor-ui/src/widgets/top_bar.rs +++ b/crates/op-editor-ui/src/widgets/top_bar.rs @@ -106,7 +106,7 @@ pub struct TopBar { pub agent_count: u32, /// Per-provider connect state, indexed by `AgentProvider::ALL`. /// The active chip paints one brand icon per connected provider. - pub connected: [bool; 7], + pub connected: [bool; 6], /// Number of enabled MCP CLI integrations — the `· N MCP` half /// of the chip status. pub mcp_count: u32, @@ -164,7 +164,7 @@ impl TopBar { file_name: file_name.into(), edited: false, agent_count: 1, - connected: [false; 7], + connected: [false; 6], mcp_count: 0, theme: Theme::dark(), label_edited: "", diff --git a/crates/op-editor-ui/src/widgets/top_bar_tests.rs b/crates/op-editor-ui/src/widgets/top_bar_tests.rs index 83a5c5316..e5becc017 100644 --- a/crates/op-editor-ui/src/widgets/top_bar_tests.rs +++ b/crates/op-editor-ui/src/widgets/top_bar_tests.rs @@ -325,10 +325,10 @@ fn agent_chip_counts_ready_builtin_agents() { fn chip_with_only_builtin_agents_reserves_no_icon_cluster() { let mut bar = TopBar::new("test.op"); bar.agent_count = 4; - bar.connected = [false; 7]; + bar.connected = [false; 6]; assert_eq!(bar.agent_icons_span(), 0.0, "no painted icons, no span"); - bar.connected = [true, false, false, false, false, false, false]; + bar.connected = [true, false, false, false, false, false]; assert!( bar.agent_icons_span() > 0.0, "a connected CLI provider brings the cluster back" diff --git a/crates/op-host-desktop/src/agent_connect_store.rs b/crates/op-host-desktop/src/agent_connect_store.rs index 5bc8bcd29..adf0de8e4 100644 --- a/crates/op-host-desktop/src/agent_connect_store.rs +++ b/crates/op-host-desktop/src/agent_connect_store.rs @@ -22,7 +22,7 @@ struct PersistedAgentConnections { /// Persist the currently-connected provider ids. Best-effort: a failed /// write must never break the probe flow. -pub(crate) fn save(connected: &[bool; 7]) { +pub(crate) fn save(connected: &[bool; 6]) { let value = PersistedAgentConnections { connected: AgentProvider::ALL .iter() @@ -42,6 +42,10 @@ pub(crate) fn load() -> Vec { let Ok(Some(value)) = op_config_store::read_json::(FILE) else { return Vec::new(); }; + providers_from_persisted(&value) +} + +fn providers_from_persisted(value: &PersistedAgentConnections) -> Vec { AgentProvider::ALL .iter() .copied() @@ -54,12 +58,19 @@ mod tests { use super::*; #[test] - fn round_trips_connected_providers_through_json() { + fn legacy_gemini_cli_entry_is_ignored_without_hiding_supported_providers() { let value = PersistedAgentConnections { - connected: vec!["Claude Code".into(), "Gemini CLI".into()], + connected: vec![ + "Claude Code".into(), + "Gemini CLI".into(), + "Antigravity".into(), + ], }; let json = serde_json::to_string(&value).expect("serialize"); let back: PersistedAgentConnections = serde_json::from_str(&json).expect("parse"); - assert_eq!(back.connected, vec!["Claude Code", "Gemini CLI"]); + assert_eq!( + providers_from_persisted(&back), + vec![AgentProvider::ClaudeCode, AgentProvider::Antigravity] + ); } } diff --git a/crates/op-host-desktop/src/chat_session_launch.rs b/crates/op-host-desktop/src/chat_session_launch.rs index abb201447..0be7ca262 100644 --- a/crates/op-host-desktop/src/chat_session_launch.rs +++ b/crates/op-host-desktop/src/chat_session_launch.rs @@ -644,8 +644,8 @@ fn near(a: f64, b: f64) -> bool { /// Build the `ChatProvider` for an agent index (into /// `AgentProvider::ALL`: 0 ClaudeCode, 1 CodexCli, 2 OpenCode, -/// 3 GithubCopilot, 4 GeminiCli, 5 Antigravity, 6 GrokBuild). Claude Code uses its dedicated -/// SDK adapter; Codex / Gemini use the subprocess transport; Copilot +/// 3 GithubCopilot, 4 Antigravity, 5 GrokBuild). Claude Code uses its dedicated +/// SDK adapter; Codex uses the subprocess transport; Copilot /// rides the official SDK; OpenCode chats over its local HTTP server /// (`chat_http_server.rs`). /// @@ -671,10 +671,8 @@ fn provider_for_agent(agent_idx: usize, chat_session: bool) -> Option SubprocessProvider::for_cli(CliName::Gemini) - .map(|p| Box::new(p) as Box), - 5 => subprocess_provider(CliName::Antigravity, chat_session), - 6 => subprocess_provider(CliName::GrokBuild, chat_session), + 4 => subprocess_provider(CliName::Antigravity, chat_session), + 5 => subprocess_provider(CliName::GrokBuild, chat_session), _ => None, } } diff --git a/crates/op-host-desktop/src/chat_session_tests.rs b/crates/op-host-desktop/src/chat_session_tests.rs index 91ec0037f..73783f545 100644 --- a/crates/op-host-desktop/src/chat_session_tests.rs +++ b/crates/op-host-desktop/src/chat_session_tests.rs @@ -346,9 +346,9 @@ fn selected_cli_model_is_none_when_entry_provider_diverges_from_routed_agent() { "GPT-5.5", )]; host.editor_state_mut().select_chat_model(0); - // Force a divergence: route Gemini while the selected entry + // Force a divergence: route Antigravity while the selected entry // still belongs to Codex. The Codex model id must NOT be - // passed to the Gemini CLI. + // passed to Antigravity. host.editor_state_mut().editor_ui.chat_selected_agent = 4; assert!(selected_cli_model_id(&host).is_none()); } diff --git a/crates/op-host-desktop/src/main.rs b/crates/op-host-desktop/src/main.rs index 25d64d313..145c9f01a 100644 --- a/crates/op-host-desktop/src/main.rs +++ b/crates/op-host-desktop/src/main.rs @@ -281,7 +281,7 @@ struct DesktopApp { last_saved_pencil_cursor: Option, /// Last persisted `connected` flags — any change (Connect landing, /// Disconnect press in the widget layer) writes through to the store. - last_saved_connections: Option<[bool; 7]>, + last_saved_connections: Option<[bool; 6]>, /// In-flight ACP-agent connect probe (Settings → Agents → ACP /// Connect), drained by `drain_acp_agent_connect`. acp_agent_connect_job: Option, diff --git a/crates/op-host-desktop/src/mcp_integrations.rs b/crates/op-host-desktop/src/mcp_integrations.rs index ea7f3a56b..647b59c9d 100644 --- a/crates/op-host-desktop/src/mcp_integrations.rs +++ b/crates/op-host-desktop/src/mcp_integrations.rs @@ -26,9 +26,9 @@ pub(crate) fn set_cli_enabled(cli: McpCli, enabled: bool, port: u16) -> Result

[bool; 8] { +pub(crate) fn detect_enabled_clis() -> [bool; 7] { let Some(home) = dirs::home_dir() else { - return [false; 8]; + return [false; 7]; }; detect_enabled_clis_for_home(&home, true) } @@ -50,12 +50,12 @@ pub(crate) fn set_cli_enabled_at_home( } /// Like [`detect_enabled_clis`] but against an explicit home dir (no env). -pub(crate) fn detect_enabled_clis_at_home(home: &Path) -> [bool; 8] { +pub(crate) fn detect_enabled_clis_at_home(home: &Path) -> [bool; 7] { detect_enabled_clis_for_home(home, false) } -fn detect_enabled_clis_for_home(home: &Path, use_env: bool) -> [bool; 8] { - let mut flags = [false; 8]; +fn detect_enabled_clis_for_home(home: &Path, use_env: bool) -> [bool; 7] { + let mut flags = [false; 7]; for (idx, cli) in McpCli::ALL.iter().copied().enumerate() { flags[idx] = if cli == McpCli::Antigravity { antigravity_config_has_openpencil(&config_path(cli, home, use_env)) @@ -80,11 +80,9 @@ fn set_cli_enabled_at_path( McpCli::Antigravity => { return Err("Antigravity configuration requires a home directory".into()) } - McpCli::ClaudeCode - | McpCli::Gemini - | McpCli::OpenCode - | McpCli::Kiro - | McpCli::GithubCopilot => update_json_config(&path, enabled, port)?, + McpCli::ClaudeCode | McpCli::OpenCode | McpCli::Kiro | McpCli::GithubCopilot => { + update_json_config(&path, enabled, port)? + } } Ok(path) } @@ -98,11 +96,9 @@ fn cli_config_has_openpencil(cli: McpCli, path: &Path) -> bool { .map(|text| grok_config_has_openpencil(&text)) .unwrap_or(false), McpCli::Antigravity => antigravity_config_has_openpencil(path), - McpCli::ClaudeCode - | McpCli::Gemini - | McpCli::OpenCode - | McpCli::Kiro - | McpCli::GithubCopilot => json_config_has_openpencil(path), + McpCli::ClaudeCode | McpCli::OpenCode | McpCli::Kiro | McpCli::GithubCopilot => { + json_config_has_openpencil(path) + } } } @@ -119,7 +115,6 @@ fn config_path(cli: McpCli, home: &Path, use_env: bool) -> PathBuf { home.join(".codex").join("config.toml") } } - McpCli::Gemini => home.join(".gemini").join("settings.json"), McpCli::OpenCode => home.join(".opencode").join("config.json"), McpCli::Kiro => home.join(".kiro").join("settings.json"), McpCli::GithubCopilot => home.join(".config").join("github-copilot").join("mcp.json"), diff --git a/crates/op-host-desktop/src/mcp_runtime.rs b/crates/op-host-desktop/src/mcp_runtime.rs index a4a559755..e96c994e2 100644 --- a/crates/op-host-desktop/src/mcp_runtime.rs +++ b/crates/op-host-desktop/src/mcp_runtime.rs @@ -35,7 +35,7 @@ impl DesktopApp { } changed |= self.reconcile_mcp_server_from_settings(); if any_cli_enabled { - changed |= self.reconcile_mcp_cli_integrations(Some(([false; 8], port))); + changed |= self.reconcile_mcp_cli_integrations(Some(([false; 7], port))); } if self.mcp_server_active() { changed |= self.request_redraw(false); @@ -226,7 +226,7 @@ impl DesktopApp { pub(crate) fn reconcile_mcp_cli_integrations( &mut self, - before: Option<([bool; 8], u16)>, + before: Option<([bool; 7], u16)>, ) -> bool { let Some((before_flags, before_port)) = before else { return false; diff --git a/crates/op-host-desktop/src/mcp_serve.rs b/crates/op-host-desktop/src/mcp_serve.rs index adcc89e95..a9c4f66ad 100644 --- a/crates/op-host-desktop/src/mcp_serve.rs +++ b/crates/op-host-desktop/src/mcp_serve.rs @@ -18,9 +18,9 @@ use op_host_services::mcp_serve::{run, run_http}; /// - `--mcp-http ` — Streamable-HTTP MCP server. /// - `--serve-web [doc] [--host ]` — headless web-canvas daemon. /// -/// External CLIs (Claude Code / Codex / Gemini / Copilot) spawn the -/// binary in these modes to drive the Rust editor the same way they -/// drive TS pen-mcp. +/// External CLIs (Claude Code / Codex / OpenCode / Kiro / Copilot / +/// Antigravity / Grok Build) spawn the binary in these modes to drive +/// the Rust editor. pub fn run_cli_if_requested() -> bool { let mut args = std::env::args().skip(1); let Some(first) = args.next() else { diff --git a/crates/op-host-desktop/src/provider_probe_host.rs b/crates/op-host-desktop/src/provider_probe_host.rs index 95c5434b4..0ae2a8239 100644 --- a/crates/op-host-desktop/src/provider_probe_host.rs +++ b/crates/op-host-desktop/src/provider_probe_host.rs @@ -214,7 +214,7 @@ mod tests { fn reset_settings(app: &mut DesktopApp) { let es = app.host.editor_state_mut(); - es.editor_ui.agent_settings.connected = [false; 7]; + es.editor_ui.agent_settings.connected = [false; 6]; es.editor_ui.agent_settings.provider_connection = Default::default(); es.editor_ui.agent_settings.pending_provider_connect = None; es.editor_ui.agent_settings.builtin_agents.clear(); @@ -256,9 +256,9 @@ mod tests { .chat .discovered_models .push(op_editor_core::ModelEntry::new( - AgentProvider::GeminiCli, - "gemini-2.5-pro", - "Gemini 2.5 Pro", + AgentProvider::Antigravity, + "default", + "Antigravity Default", )); app.host .editor_state_mut() @@ -297,15 +297,15 @@ mod tests { settings.provider_connection[0].info.as_deref(), Some("Connected via pro (a@b.c)") ); - // Claude's entry spliced in, sorted before the seeded Gemini - // entry (ALL order), which survived. + // Claude's entry spliced in, sorted before the seeded + // Antigravity entry (ALL order), which survived. let values: Vec<&str> = es .chat .discovered_models .iter() .map(|m| m.value.as_str()) .collect(); - assert_eq!(values, ["claude-sonnet-4-6", "gemini-2.5-pro"]); + assert_eq!(values, ["claude-sonnet-4-6", "default"]); // Connected → the picker lists the Claude model. assert!(es .chat diff --git a/crates/op-host-native/src/widget_host/deferred_press_tests.rs b/crates/op-host-native/src/widget_host/deferred_press_tests.rs index d15313a5a..b82fff7d9 100644 --- a/crates/op-host-native/src/widget_host/deferred_press_tests.rs +++ b/crates/op-host-native/src/widget_host/deferred_press_tests.rs @@ -22,9 +22,9 @@ fn seed_two_chat_models(host: &mut WidgetHostNative) { .chat .available_models .push(ModelEntry::new( - AgentProvider::GeminiCli, - "gemini-2.5-pro", - "Gemini 2.5 Pro", + AgentProvider::Antigravity, + "default", + "Antigravity Default", )); } diff --git a/crates/op-host-services/src/chat_provider_llm.rs b/crates/op-host-services/src/chat_provider_llm.rs index 881d0f161..f78b83d73 100644 --- a/crates/op-host-services/src/chat_provider_llm.rs +++ b/crates/op-host-services/src/chat_provider_llm.rs @@ -1,12 +1,13 @@ //! `ChatProvider` → `LlmClient` adapter. //! //! Lets the orchestrator reuse whichever chat-panel agent the user -//! already selected (Claude Code / Copilot / Gemini / …) as its LLM +//! already selected (Claude Code / Copilot / Antigravity / …) as its LLM //! transport, instead of forcing a separate Anthropic API key. //! //! The CLI agents (`ClaudeCodeProvider`, `CopilotProvider`, //! `SubprocessProvider`) manage their own auth — `claude` is logged in -//! by the user, Copilot rides GitHub auth, Gemini rides `gcloud`. +//! by the user, Copilot rides GitHub auth, and Antigravity manages its +//! Google account. //! `agent::Provider` (the `QueryEngine`-facing trait) is a different //! shape and only `AnthropicProvider` implements it, hence the original //! Anthropic-key requirement. This adapter eliminates that @@ -232,9 +233,10 @@ mod tests { // // The manual per-subtask retry (failed-subtask remediation, phase 2) // reuses `ChatProviderLlmClient` with WHATEVER `ChatProvider` the user - // currently has selected — a CLI subprocess agent (Claude Code / - // Copilot / Gemini via `SubprocessProvider`) exactly as often as a - // builtin API-key provider. `call()` above has no branch on the + // currently has selected — a CLI-backed agent (Claude Code / + // Copilot adapters, or Codex / Antigravity / Grok Build via + // `SubprocessProvider`) exactly as often as a builtin API-key + // provider. `call()` above has no branch on the // concrete provider type anywhere — it only calls the `ChatProvider` // trait method — so these two tests prove that structurally, with two // stub providers shaped like the two real families instead of relying diff --git a/crates/op-host-services/src/chat_subprocess.rs b/crates/op-host-services/src/chat_subprocess.rs index f48aa1c3e..155feb90f 100644 --- a/crates/op-host-services/src/chat_subprocess.rs +++ b/crates/op-host-services/src/chat_subprocess.rs @@ -1,5 +1,5 @@ //! Subprocess CLI bridge — spawns an external CLI binary -//! (Claude Code / Codex / Gemini / Antigravity / Grok Build) and bridges its stdio into the +//! (Claude Code / Codex / Antigravity / Grok Build) and bridges its stdio into the //! shell-core `ChatProvider` shape. //! //! Per-CLI wire protocol (single-shot mode; multi-turn context rides @@ -22,13 +22,6 @@ //! Divergence from TS (documented): TS buffers the whole turn and //! reads `--output-last-message`; Rust streams `item.completed` //! agent messages live — same final text, no temp file. -//! - **Gemini CLI (`gemini`)** — `gemini -o stream-json -//! --approval-mode plan [-m ] -p ' '` with the prompt piped via -//! stdin (TS parity: `gemini-client.ts::streamGeminiExec`; the -//! `-p ' '` marker is the TS quirk — Gemini appends the `-p` value -//! after stdin content). Lines parse via -//! [`chat_subprocess_quirks::parse_gemini_stream_line`]; child env -//! is allowlist-filtered. //! - **GitHub Copilot** — no subprocess template. The routed path is //! the official SDK (`chat_copilot.rs`); the old `gh-copilot //! suggest` fallback was stale (the `gh` extension was retired in @@ -51,13 +44,13 @@ //! Its NDJSON `text`, `thought`, `end`, and `error` events parse through //! [`crate::chat_grok_stream::parse_grok_stream_line`]. //! -//! Codex / Gemini parse-misses are skipped silently (TS parity — TS +//! Codex parse-misses are skipped silently (TS parity — TS //! drops unparsed lines); generic custom binaries degrade unparsed //! lines to raw `TextDelta` so plain-stdout CLIs still show output. //! On stdout EOF the bridge reaps the child + interprets exit status — //! non-zero exit surfaces as `Error + Done { Aborted }` (codex BLOCK //! 4 / 5), with Codex stderr routed through the TS error extractor. -//! Codex / Gemini turns also carry the TS 15-minute wall clock +//! Codex turns also carry the TS 15-minute wall clock //! (` request timed out after 900s.`). On receiver drop the //! bridge `child.start_kill()` so the user can navigate away without //! leaking processes. @@ -85,8 +78,8 @@ pub use crate::chat_subprocess_parse::parse_line; /// How the user's prompt reaches the CLI. Claude Code's `--print` /// mode requires the prompt as a positional argv after `--` and -/// closes stdin immediately. Codex (`-` prompt arg) and Gemini read -/// the message off piped stdin. Generic `with_binary` callers can +/// closes stdin immediately. Codex (`-` prompt arg) reads the +/// message off piped stdin. Generic `with_binary` callers can /// pick either via [`SubprocessProvider::with_binary_mode`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PromptMode { @@ -101,9 +94,9 @@ pub enum PromptMode { PromptFile(&'static str), } -/// TS `DEFAULT_CODEX_TIMEOUT_MS` / `DEFAULT_GEMINI_TIMEOUT_MS` — -/// both reference clients cap a turn at 15 minutes then SIGTERM. -const CLI_TURN_TIMEOUT: Duration = Duration::from_secs(15 * 60); +/// TS `DEFAULT_CODEX_TIMEOUT_MS` — the reference client caps a turn +/// at 15 minutes then SIGTERM. +const CODEX_TURN_TIMEOUT: Duration = Duration::from_secs(15 * 60); /// Cap on the retained Codex stderr tail used for error extraction. const STDERR_TAIL_CAP: usize = 64 * 1024; @@ -117,8 +110,7 @@ pub struct SubprocessProvider { label: String, prompt_mode: PromptMode, /// Argv flag that selects a model for this CLI (`--model` for - /// Codex, `-m` for Gemini — both verified against the TS - /// reference clients). `None` = the transport has no model + /// Codex and Antigravity, `-m` for Grok Build). `None` = the transport has no model /// selector; `ChatRequest::model` is ignored and the CLI keeps /// its own default. model_flag: Option<&'static str>, @@ -129,8 +121,7 @@ pub struct SubprocessProvider { /// prose directive). native_effort_config: bool, /// Trailing argv appended after the per-turn flags — Codex's `-` - /// stdin marker, Gemini's `-p ' '` marker. TS keeps the same - /// flag-then-marker order (`codex-client.ts` / `gemini-client.ts`). + /// stdin marker. TS keeps the same flag-then-marker order. tail_args: Vec, /// Which known CLI this provider bridges (drives per-CLI env /// filtering, line parsing, stderr capture, and timeout quirks). @@ -156,9 +147,8 @@ impl SubprocessProvider { fn for_cli_with_purpose(cli: CliName, turn_purpose: safety::TurnPurpose) -> Option { // Per-CLI model selector (third tuple slot): Codex takes - // `--model ` and Gemini `-m ` — matching the TS - // reference (`codex-client.ts` / `gemini-client.ts`). Claude - // Code's model rides the SDK adapter (`chat_claude.rs`), so + // `--model ` — matching the TS reference. Claude Code's + // model rides the SDK adapter (`chat_claude.rs`), so // its subprocess template carries no flag here. type Template = (Vec, PromptMode, Option<&'static str>, Vec); let (args, prompt_mode, model_flag, tail_args): Template = match cli { @@ -173,20 +163,6 @@ impl SubprocessProvider { None, Vec::new(), ), - // TS `gemini-client.ts::streamGeminiExec` argv order: - // `-o stream-json --approval-mode plan [-m model] -p ' '`, - // prompt via stdin. - CliName::Gemini => ( - vec![ - "-o".into(), - "stream-json".into(), - "--approval-mode".into(), - "plan".into(), - ], - PromptMode::Stdin, - Some("-m"), - vec!["-p".into(), " ".into()], - ), // TS `codex-client.ts` argv: `exec --json // --skip-git-repo-check --sandbox read-only [--model] // [--config model_reasoning_effort=…] -` with the prompt @@ -324,8 +300,8 @@ fn codex_reasoning_effort(thinking: ThinkingMode, effort: EffortLevel) -> Option /// can substitute a malicious binary; runtime-library paths /// (NODE_OPTIONS, PYTHONPATH, etc.) can inject code into Node-based /// CLIs. Mirrors bartolli/anthropic-agent-sdk's `DANGEROUS_ENV_VARS`. -/// Used for Claude Code + custom binaries; Codex / Gemini get the -/// stricter TS allowlists (`chat_subprocess_quirks`). Returns the +/// Used for Claude Code + custom binaries; Codex gets the stricter +/// TS allowlist (`chat_subprocess_quirks`). Returns the /// env-var pairs the child will receive (parent env minus the /// dangerous names — preserving every safe var so node version /// managers like nvm / volta still pick the right Node). @@ -353,8 +329,8 @@ impl ChatProvider for SubprocessProvider { fn send(&self, request: ChatRequest) -> Box + Send> { let binary = self.binary.clone(); let cli = self.cli; - // Build the effective prompt. Neither claude `--print` nor - // gemini exposes a portable reasoning flag, so the thinking + + // Build the effective prompt. Claude `--print` does not + // expose a portable reasoning flag, so the thinking + // effort knobs travel in-band as a leading directive line // (documented beyond-TS-baseline behavior); staged attachments // are appended as `[attached …: ]` lines the CLI can @@ -400,13 +376,11 @@ impl ChatProvider for SubprocessProvider { if !digest.is_empty() { prompt = format!("{digest}\n\n{prompt}"); } - // System-prompt framing: Codex + Gemini mirror the TS - // GUIDELINES / TASK `buildPrompt` byte-for-byte; everything + // System-prompt framing: Codex mirrors the TS GUIDELINES / + // TASK `buildPrompt` byte-for-byte; everything // else keeps the generic `system\n\n---\n\nprompt` join. prompt = match cli { - Some(CliName::Codex) | Some(CliName::Gemini) => { - quirks::guidelines_task_prompt(&request.system_prompt, &prompt) - } + Some(CliName::Codex) => quirks::guidelines_task_prompt(&request.system_prompt, &prompt), _ => prompt_with_system_prompt(&request.system_prompt, prompt), }; let attachment_paths = guard.as_ref().map(|g| g.paths()).unwrap_or(&[]); @@ -467,12 +441,11 @@ impl ChatProvider for SubprocessProvider { } let args = Arc::new(args_with_prompt); let prompt_mode = self.prompt_mode; - // Per-CLI child env: Codex / Gemini use the TS allowlists so + // Per-CLI child env: Codex uses the TS allowlist so // unrelated secrets never reach the CLI; Claude Code + custom // binaries keep the scrub-the-dangerous-vars policy. let mut env_pairs = match cli { Some(CliName::Codex) => quirks::codex_child_env(), - Some(CliName::Gemini) => quirks::gemini_child_env(), Some(CliName::Antigravity | CliName::GrokBuild) => { safety::child_env(cli).unwrap_or_default() } @@ -480,7 +453,7 @@ impl ChatProvider for SubprocessProvider { }; safety::append_isolated_env(&mut env_pairs, isolation.as_ref()); let turn_timeout = match cli { - Some(CliName::Codex | CliName::Gemini) => Some(CLI_TURN_TIMEOUT), + Some(CliName::Codex) => Some(CODEX_TURN_TIMEOUT), Some(CliName::Antigravity) => Some(safety::ANTIGRAVITY_TIMEOUT), Some(CliName::GrokBuild) => Some(safety::GROK_TIMEOUT), _ => None, @@ -518,8 +491,7 @@ impl ChatProvider for SubprocessProvider { // Drain stderr on a sibling task so the CLI never // deadlocks on a full stderr pipe (codex BLOCK 1). Codex // keeps a bounded tail for the TS error extraction - // (`extractCodexCliError`); other CLIs discard it (TS - // parity: gemini stream path discards stderr). + // (`extractCodexCliError`); other CLIs discard it. let stderr_tail: Arc> = Arc::default(); if let Some(stderr) = child.take_stderr() { let capture = (cli == Some(CliName::Codex) || safety::is_guarded_cli(cli)) @@ -607,7 +579,7 @@ impl ChatProvider for SubprocessProvider { break; } // TS wall clock: SIGTERM + "request timed out" - // (codex-client.ts / gemini-client.ts reject text). + // (`codex-client.ts` rejects text). _ = tokio::time::sleep_until(deadline), if turn_timeout.is_some() => { let secs = turn_timeout.map(|d| d.as_secs()).unwrap_or_default(); let _ = tx @@ -633,12 +605,11 @@ impl ChatProvider for SubprocessProvider { let _ = child.start_kill(); break; } - // Per-CLI parse: Codex / Gemini skip - // unparsed lines (TS parity); generic + // Per-CLI parse: Codex skips unparsed + // lines (TS parity); generic // CLIs degrade them to raw text. let delta = match cli { Some(CliName::Codex) => quirks::parse_codex_line(&line), - Some(CliName::Gemini) => quirks::parse_gemini_stream_line(&line), Some(CliName::GrokBuild) => { crate::chat_grok_stream::parse_grok_stream_line(&line) } diff --git a/crates/op-host-services/src/chat_subprocess_quirks.rs b/crates/op-host-services/src/chat_subprocess_quirks.rs index 9b8a85097..cfd7f2d66 100644 --- a/crates/op-host-services/src/chat_subprocess_quirks.rs +++ b/crates/op-host-services/src/chat_subprocess_quirks.rs @@ -1,13 +1,11 @@ -//! Per-CLI quirks for the Codex / Gemini subprocess transports — -//! verbatim ports of the TS reference clients: +//! Per-CLI quirks for the Codex subprocess transport — a verbatim +//! port of the TS reference client: //! //! - `apps/web/server/utils/codex-client.ts` — env allowlist (+ //! `~/.codex/config.toml` `env_key` opt-ins), stderr error //! extraction with auth-hint rewrites, JSONL line parsing. -//! - `apps/web/server/utils/gemini-client.ts` — env allowlist, -//! `-o stream-json` line parsing, user-friendly API error mapping. //! -//! Both also share the TS `buildPrompt` GUIDELINES / TASK framing so +//! It also keeps the TS `buildPrompt` GUIDELINES / TASK framing so //! the wire prompt matches the TS server byte-for-byte. use op_ai::chat_provider::{ChatDelta, StopReason}; @@ -50,11 +48,6 @@ const CODEX_ENV_ALLOWLIST: &[&str] = &[ "HOMEPATH", ]; -/// Allowlist-based env filter for the Gemini CLI subprocess (TS -/// `gemini-client.ts::GEMINI_ENV_ALLOWLIST` — same system core, no -/// extra config-file opt-ins). -const GEMINI_ENV_ALLOWLIST: &[&str] = CODEX_ENV_ALLOWLIST; - /// Extract provider-declared `env_key` entries from /// `~/.codex/config.toml` content. Preserves the default safety /// boundary of not forwarding sensitive environment variables @@ -120,22 +113,9 @@ pub fn codex_child_env() -> Vec<(String, String)> { .collect() } -/// Gemini child env: allowlisted system vars + `GOOGLE_*` / -/// `GEMINI_*` / `GCLOUD_*` prefixes (TS `filterGeminiEnv`). -pub fn gemini_child_env() -> Vec<(String, String)> { - std::env::vars() - .filter(|(k, _)| { - GEMINI_ENV_ALLOWLIST.contains(&k.as_str()) - || k.starts_with("GOOGLE_") - || k.starts_with("GEMINI_") - || k.starts_with("GCLOUD_") - }) - .collect() -} - -/// TS `codex-client.ts::buildPrompt` / `gemini-client.ts::buildPrompt` -/// framing: an empty system prompt passes the task through; otherwise -/// the system prompt rides a GUIDELINES block ahead of the TASK block. +/// TS `codex-client.ts::buildPrompt` framing: an empty system prompt +/// passes the task through; otherwise the system prompt rides a +/// GUIDELINES block ahead of the TASK block. pub fn guidelines_task_prompt(system_prompt: &str, task: &str) -> String { let task = task.trim(); let system = system_prompt.trim(); @@ -320,88 +300,6 @@ fn is_codex_auth_error(msg: &str) -> bool { false } -/// Parse one `gemini -o stream-json` stdout line (TS -/// `parseStreamJsonLine`). `None` = skip silently — non-JSON noise -/// like "Loaded cached credentials." never reaches the transcript. -pub fn parse_gemini_stream_line(line: &str) -> Option { - let trimmed = line.trim(); - if !trimmed.starts_with('{') { - return None; - } - let val: serde_json::Value = serde_json::from_str(trimmed).ok()?; - let ty = val.get("type").and_then(|v| v.as_str()).unwrap_or(""); - - if ty == "message" && val.get("role").and_then(|v| v.as_str()) == Some("assistant") { - let content = val.get("content").and_then(|v| v.as_str()).unwrap_or(""); - if !content.is_empty() { - return Some(ChatDelta::TextDelta(content.to_string())); - } - return None; - } - - if ty == "result" { - // Check for error in result event; a success result carries - // no renderable delta (the text already streamed). - if val.get("status").and_then(|v| v.as_str()) == Some("error") { - if let Some(err) = val.get("error") { - let msg = err - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or("Unknown error"); - return Some(ChatDelta::Error(friendly_gemini_api_error(msg))); - } - } - return None; - } - - if ty == "error" { - let msg = val - .get("message") - .and_then(|v| v.as_str()) - .unwrap_or("Unknown error"); - return Some(ChatDelta::Error(friendly_gemini_api_error(msg))); - } - - None -} - -/// Map raw Gemini API errors to user-friendly messages (TS -/// `friendlyGeminiApiError`). -pub fn friendly_gemini_api_error(raw: &str) -> String { - let lower = raw.to_ascii_lowercase(); - if lower.contains("quota") - || lower.contains("exhausted") - || lower.contains("429") - || lower.contains("capacity") - { - if let Some(reset) = match_reset_after(raw) { - return format!("Gemini quota exhausted. Resets after {reset}."); - } - return "Gemini quota exhausted. Please wait and try again.".to_string(); - } - if lower.contains("401") || lower.contains("unauthenticated") || lower.contains("auth") { - return "Gemini auth expired. Run \"gemini\" in your terminal to re-authenticate." - .to_string(); - } - if raw.contains("[object Object]") { - return "Gemini API error. Check your quota or try a different model.".to_string(); - } - raw.to_string() -} - -/// TS regex `/reset after (\S+)/i` — the quota-reset timestamp token. -fn match_reset_after(raw: &str) -> Option<&str> { - let lower = raw.to_ascii_lowercase(); - let pos = lower.find("reset after ")?; - let tail = &raw[pos + "reset after ".len()..]; - let token: &str = tail.split_whitespace().next()?; - if token.is_empty() { - None - } else { - Some(token) - } -} - #[cfg(test)] mod tests { use super::*; @@ -529,60 +427,4 @@ env_key = not_quoted Some("something odd happened") ); } - - #[test] - fn gemini_line_parser_assistant_messages_and_noise() { - assert_eq!(parse_gemini_stream_line("Loaded cached credentials."), None); - assert_eq!( - parse_gemini_stream_line(r#"{"type":"message","role":"assistant","content":"Hello"}"#), - Some(ChatDelta::TextDelta("Hello".into())) - ); - // Empty content / non-assistant roles are skipped. - assert_eq!( - parse_gemini_stream_line(r#"{"type":"message","role":"assistant","content":""}"#), - None - ); - assert_eq!( - parse_gemini_stream_line(r#"{"type":"message","role":"user","content":"x"}"#), - None - ); - } - - #[test] - fn gemini_line_parser_result_and_error_events() { - // Success result carries no delta. - assert_eq!( - parse_gemini_stream_line(r#"{"type":"result","status":"ok","response":"done"}"#), - None - ); - assert_eq!( - parse_gemini_stream_line( - r#"{"type":"result","status":"error","error":{"message":"401 unauthenticated"}}"# - ), - Some(ChatDelta::Error( - "Gemini auth expired. Run \"gemini\" in your terminal to re-authenticate.".into() - )) - ); - assert_eq!( - parse_gemini_stream_line(r#"{"type":"error","message":"plain failure"}"#), - Some(ChatDelta::Error("plain failure".into())) - ); - } - - #[test] - fn gemini_friendly_error_table_matches_ts() { - assert_eq!( - friendly_gemini_api_error("Quota will reset after 3:00PM details"), - "Gemini quota exhausted. Resets after 3:00PM." - ); - assert_eq!( - friendly_gemini_api_error("429 too many requests"), - "Gemini quota exhausted. Please wait and try again." - ); - assert_eq!( - friendly_gemini_api_error("[object Object]"), - "Gemini API error. Check your quota or try a different model." - ); - assert_eq!(friendly_gemini_api_error("boring"), "boring"); - } } diff --git a/crates/op-host-services/src/chat_subprocess_tests.rs b/crates/op-host-services/src/chat_subprocess_tests.rs index e57de0775..443d4009d 100644 --- a/crates/op-host-services/src/chat_subprocess_tests.rs +++ b/crates/op-host-services/src/chat_subprocess_tests.rs @@ -124,26 +124,6 @@ fn for_cli_claude_code_seeds_print_stream_json_flags() { assert_eq!(p.prompt_mode, PromptMode::PositionalArg); } -#[test] -fn for_cli_uses_default_binary_per_cli_name() { - // Resolved path may be bare or absolute depending on what's - // installed on the test host; check the basename only. - let gemini = SubprocessProvider::for_cli(CliName::Gemini).unwrap(); - assert!( - gemini.binary.ends_with("gemini"), - "binary={}", - gemini.binary - ); - assert_eq!(gemini.prompt_mode, PromptMode::Stdin); - // TS gemini-client.ts streamGeminiExec argv: `-o stream-json - // --approval-mode plan … -p ' '` (prompt via stdin). - assert_eq!( - gemini.args, - vec!["-o", "stream-json", "--approval-mode", "plan"] - ); - assert_eq!(gemini.tail_args, vec!["-p", " "]); -} - #[test] fn for_cli_rejects_opencode_and_copilot() { // OpenCode chats over its HTTP server (chat_http_server.rs); @@ -299,29 +279,6 @@ fn codex_turn_args_map_effort_to_reasoning_config() { } } -#[test] -fn gemini_turn_args_append_m_flag_when_selected() { - let p = SubprocessProvider::for_cli(CliName::Gemini).unwrap(); - let args = p.turn_args(&request_with_model(Some("gemini-2.5-pro"))); - let pos = args - .iter() - .position(|a| a == "-m") - .expect("-m flag present"); - assert_eq!(args[pos + 1], "gemini-2.5-pro"); - // Gemini has no native effort knob — never a --config arg. - assert!(!args.iter().any(|a| a == "--config")); - // The `-p ' '` stdin marker trails the model flag (TS order). - assert_eq!(args[args.len() - 2], "-p"); - assert_eq!(args[args.len() - 1], " "); -} - -#[test] -fn gemini_turn_args_omit_m_flag_when_unset() { - let p = SubprocessProvider::for_cli(CliName::Gemini).unwrap(); - let args = p.turn_args(&request_with_model(None)); - assert!(!args.iter().any(|a| a == "-m"), "args={args:?}"); -} - #[test] fn claude_subprocess_template_ignores_model() { // Claude Code's model rides the SDK adapter (chat_claude.rs); its diff --git a/crates/op-host-services/src/model_discovery.rs b/crates/op-host-services/src/model_discovery.rs index ee6f98c13..19c98d33b 100644 --- a/crates/op-host-services/src/model_discovery.rs +++ b/crates/op-host-services/src/model_discovery.rs @@ -36,7 +36,6 @@ pub fn model_entry_to_ec(m: ModelEntry) -> op_editor_core::ModelEntry { ScP::CodexCli => op_editor_core::AgentProvider::CodexCli, ScP::OpenCode => op_editor_core::AgentProvider::OpenCode, ScP::GithubCopilot => op_editor_core::AgentProvider::GithubCopilot, - ScP::GeminiCli => op_editor_core::AgentProvider::GeminiCli, ScP::Antigravity => op_editor_core::AgentProvider::Antigravity, ScP::GrokBuild => op_editor_core::AgentProvider::GrokBuild, }; @@ -47,12 +46,12 @@ pub fn model_entry_to_ec(m: ModelEntry) -> op_editor_core::ModelEntry { /// provider-grouped model list. Safe to call off the UI thread — /// it only reads files and spawns short-lived subprocesses. pub fn discover_models() -> Vec { - discover_models_for_connected([true; 7]) + discover_models_for_connected([true; 6]) } /// Discover a startup-selected provider set concurrently while preserving /// the stable Settings/model-picker provider order in the returned catalog. -pub fn discover_models_for_connected(connected: [bool; 7]) -> Vec { +pub fn discover_models_for_connected(connected: [bool; 6]) -> Vec { let workers: Vec<_> = discovery_provider_order() .into_iter() .enumerate() @@ -71,7 +70,6 @@ fn discover_provider(provider: AgentProvider) -> Vec { AgentProvider::CodexCli => discover_codex(), AgentProvider::OpenCode => discover_opencode(), AgentProvider::GithubCopilot => discover_copilot(), - AgentProvider::GeminiCli => discover_gemini(), AgentProvider::Antigravity => crate::cli_model_discovery::discover_antigravity(), AgentProvider::GrokBuild => crate::cli_model_discovery::discover_grok(), } @@ -79,7 +77,7 @@ fn discover_provider(provider: AgentProvider) -> Vec { /// Provider probe order mirrors TS `DEFAULT_PROVIDERS`, which is /// also the core `AgentProvider::ALL` order used by Settings. -fn discovery_provider_order() -> [AgentProvider; 7] { +fn discovery_provider_order() -> [AgentProvider; 6] { AgentProvider::ALL } @@ -344,23 +342,6 @@ pub fn parse_codex_models_cache(raw: &str) -> Option> { Some(keyed.into_iter().map(|(_, model)| model).collect()) } -/// Gemini CLI — live model listing from the generativelanguage API -/// using the CLI's own credentials (API key env or OAuth token, -/// connect-agent.ts:904-973), falling back to the TS -/// `FALLBACK_GEMINI_MODELS` list when the fetch fails or returns -/// nothing — gated on the CLI being installed. -fn discover_gemini() -> Vec { - if resolve_cli("gemini").is_none() { - return Vec::new(); - } - if let Some(models) = crate::provider_probe_models::gemini_models_from_api() { - if !models.is_empty() { - return models; - } - } - crate::provider_probe_models::fallback_gemini_models() -} - /// How long to wait for `copilot --stdio` to answer `models.list`. const COPILOT_STDIO_TIMEOUT: Duration = Duration::from_secs(8); diff --git a/crates/op-host-services/src/model_probe.rs b/crates/op-host-services/src/model_probe.rs index aedc8d487..96333a05b 100644 --- a/crates/op-host-services/src/model_probe.rs +++ b/crates/op-host-services/src/model_probe.rs @@ -8,26 +8,26 @@ use crate::model_discovery::{discover_models_for_connected, model_entry_to_ec}; pub struct ModelProbe { rx: Option>>, - providers: [bool; 7], + providers: [bool; 6], } impl ModelProbe { pub fn idle() -> Self { Self { rx: None, - providers: [false; 7], + providers: [false; 6], } } /// Spawn a full-catalog discovery worker for compatibility with callers /// that explicitly need every locally installed provider. pub fn spawn() -> Self { - Self::spawn_for_connected([true; 7]) + Self::spawn_for_connected([true; 6]) } /// Probe only providers connected at startup. Provider queries execute /// concurrently, so their individual timeouts do not stack serially. - pub fn spawn_for_connected(connected: [bool; 7]) -> Self { + pub fn spawn_for_connected(connected: [bool; 6]) -> Self { if !connected.iter().any(|is_connected| *is_connected) { return Self::idle(); } @@ -47,12 +47,12 @@ impl ModelProbe { #[cfg(test)] pub(crate) fn pending_for_test() -> (Self, mpsc::Sender>) { - Self::pending_for_providers_for_test([true; 7]) + Self::pending_for_providers_for_test([true; 6]) } #[cfg(test)] fn pending_for_providers_for_test( - providers: [bool; 7], + providers: [bool; 6], ) -> (Self, mpsc::Sender>) { let (tx, rx) = mpsc::channel(); ( @@ -111,13 +111,13 @@ mod tests { #[test] fn empty_connected_mask_stays_idle() { - assert!(!ModelProbe::spawn_for_connected([false; 7]).is_pending()); + assert!(!ModelProbe::spawn_for_connected([false; 6]).is_pending()); } #[test] fn filtered_result_does_not_erase_unprobed_provider() { - let mut providers = [false; 7]; - providers[5] = true; + let mut providers = [false; 6]; + providers[4] = true; let (mut probe, tx) = ModelProbe::pending_for_providers_for_test(providers); let mut state = EditorState::default(); state.chat.discovered_models.push(EditorModelEntry::new( diff --git a/crates/op-host-services/src/provider_probe.rs b/crates/op-host-services/src/provider_probe.rs index 2865fe57e..0cb2ce13e 100644 --- a/crates/op-host-services/src/provider_probe.rs +++ b/crates/op-host-services/src/provider_probe.rs @@ -3,7 +3,7 @@ //! //! Pressing Connect on a provider card runs a real probe: binary //! resolution (installed?), a responsiveness gate where TS runs one -//! (`codex --version` / `gemini --version`), a live model query, and +//! (`codex --version`), a live model query, and //! an auth-state read that yields the human-readable //! `connectionInfo` string ("Connected via pro (a@b.c)"). Failures //! map through the same friendly-error tables the TS route uses. @@ -27,8 +27,8 @@ use crate::model_discovery::{ parse_copilot_model_list, resolve_cli, write_lsp_frame, }; use crate::provider_probe_models::{ - claude_initialize_query, codex_home, codex_models_from_latest_md, gemini_models_from_api, - ClaudeAccount, ClaudeInitResult, + claude_initialize_query, codex_home, codex_models_from_latest_md, ClaudeAccount, + ClaudeInitResult, }; /// Probe result — the TS `ConnectResult` shape plus the install @@ -78,9 +78,6 @@ fn no_models_error(provider: AgentProvider) -> String { AgentProvider::GithubCopilot => { "No models found. Run \"copilot login\" to authenticate first.".to_string() } - AgentProvider::GeminiCli => { - "No models found. Run \"gemini\" once to authenticate, or set GEMINI_API_KEY.".to_string() - } AgentProvider::Antigravity => { "No model available. Run \"agy\" once to authenticate.".to_string() } @@ -119,7 +116,6 @@ pub fn connect_provider(provider: AgentProvider) -> ProbeOutcome { AgentProvider::CodexCli => connect_codex_cli(), AgentProvider::OpenCode => connect_opencode(), AgentProvider::GithubCopilot => connect_copilot(), - AgentProvider::GeminiCli => connect_gemini_cli(), AgentProvider::Antigravity => crate::cli_provider_probe::connect_antigravity(), AgentProvider::GrokBuild => crate::cli_provider_probe::connect_grok_build(), } @@ -157,7 +153,6 @@ fn install_command_for_platform( "See documentation" } } - AgentProvider::GeminiCli => "npm install -g @anthropic-ai/gemini-cli", AgentProvider::Antigravity if windows => { "irm https://antigravity.google/cli/install.ps1 | iex" } @@ -704,73 +699,6 @@ fn friendly_copilot_error(raw: &str) -> String { raw.to_string() } -// --------------------------------------------------------------- -// Gemini CLI (connect-agent.ts:975-1063) -// --------------------------------------------------------------- - -fn connect_gemini_cli() -> ProbeOutcome { - let Some(exe) = resolve_cli("gemini") else { - return ProbeOutcome::not_installed(AgentProvider::GeminiCli, "Gemini CLI not found"); - }; - // Responsiveness gate — TS runs `gemini --version` with a 10 s - // budget (connect-agent.ts:986-997). - let Some(version) = cli_version(&exe, Duration::from_secs(10)) else { - return ProbeOutcome::failed("Gemini CLI not responding".to_string()); - }; - let models = match gemini_models_from_api() { - Some(models) if !models.is_empty() => models, - Some(_) => return ProbeOutcome::failed(no_models_error(AgentProvider::GeminiCli)), - None => { - return ProbeOutcome::failed( - "Unable to fetch Gemini models. Run \"gemini\" once to authenticate, or set GEMINI_API_KEY.".to_string(), - ) - } - }; - let (info, hint) = build_gemini_connection_info(); - connected_probe_outcome( - AgentProvider::GeminiCli, - models, - Some(info), - None, - Some(hint), - Some(version), - ) -} - -/// TS `buildGeminiConnectionInfo` (connect-agent.ts:1027-1063). -fn build_gemini_connection_info() -> (String, String) { - let hint = config_path( - "~/.gemini/settings.json", - "%USERPROFILE%\\.gemini\\settings.json", - ); - let env_key = std::env::var("GEMINI_API_KEY") - .ok() - .filter(|k| !k.is_empty()) - .or_else(|| { - std::env::var("GOOGLE_API_KEY") - .ok() - .filter(|k| !k.is_empty()) - }); - if let Some(key) = env_key { - return (format!("Connected via API key ({})", mask_key(&key)), hint); - } - let gemini_dir = dirs::home_dir().map(|h| h.join(".gemini")); - if let Some(dir) = gemini_dir { - if dir.join("oauth_creds.json").is_file() { - // Try the active Google account email. - if let Ok(raw) = std::fs::read_to_string(dir.join("google_accounts.json")) { - if let Ok(accounts) = serde_json::from_str::(&raw) { - if let Some(active) = accounts.get("active").and_then(|v| v.as_str()) { - return (format!("Connected via Google ({active})"), hint); - } - } - } - return ("Connected via Google OAuth".to_string(), hint); - } - } - ("Connected via Gemini CLI".to_string(), hint) -} - #[cfg(test)] #[path = "provider_probe_tests.rs"] mod tests; diff --git a/crates/op-host-services/src/provider_probe_host.rs b/crates/op-host-services/src/provider_probe_host.rs index 6d8d203c9..0c21771ac 100644 --- a/crates/op-host-services/src/provider_probe_host.rs +++ b/crates/op-host-services/src/provider_probe_host.rs @@ -84,7 +84,6 @@ fn provider_to_sc(p: op_editor_core::AgentProvider) -> op_ai::agent_settings_sta op_editor_core::AgentProvider::CodexCli => Sc::CodexCli, op_editor_core::AgentProvider::OpenCode => Sc::OpenCode, op_editor_core::AgentProvider::GithubCopilot => Sc::GithubCopilot, - op_editor_core::AgentProvider::GeminiCli => Sc::GeminiCli, op_editor_core::AgentProvider::Antigravity => Sc::Antigravity, op_editor_core::AgentProvider::GrokBuild => Sc::GrokBuild, } @@ -116,9 +115,6 @@ pub fn missing_models_connect_error(provider: op_editor_core::AgentProvider) -> op_editor_core::AgentProvider::GithubCopilot => { "No models found. GitHub Copilot did not return a model list.".to_string() } - op_editor_core::AgentProvider::GeminiCli => { - "No models found. Gemini CLI did not return a model list.".to_string() - } op_editor_core::AgentProvider::Antigravity => { "No model available. Antigravity did not expose its default model.".to_string() } diff --git a/crates/op-host-services/src/provider_probe_models.rs b/crates/op-host-services/src/provider_probe_models.rs index d2a27ef6e..fc1a0c0de 100644 --- a/crates/op-host-services/src/provider_probe_models.rs +++ b/crates/op-host-services/src/provider_probe_models.rs @@ -1,4 +1,4 @@ -//! Live model-list queries for Claude + Gemini, plus the Codex +//! Live model-list queries for Claude, plus the Codex //! `latest-model.md` fallback parser. //! //! These are the "no hardcoded lists" upgrades shared by startup @@ -14,11 +14,6 @@ //! --verbose --input-format stream-json …`, write one //! `control_request {subtype:"initialize"}` line, read the //! `control_response` carrying `models` + `account`. -//! - Gemini: the `generativelanguage.googleapis.com/v1beta/models` -//! listing authenticated by `GEMINI_API_KEY` / `GOOGLE_API_KEY` -//! or the CLI's `~/.gemini/oauth_creds.json` access token -//! (connect-agent.ts:904-973), filtered to `generateContent` -//! models and sorted gemini-3 first. //! - Codex: `~/.codex/skills/.system/openai-docs/references/ //! latest-model.md` markdown-table rows when `models_cache.json` //! is missing (connect-agent.ts:378-413). @@ -215,156 +210,6 @@ pub fn fallback_claude_models() -> Vec { .collect() } -/// TS `FALLBACK_GEMINI_MODELS` (connect-agent.ts:870-901). -pub fn fallback_gemini_models() -> Vec { - [ - ("gemini-3-pro-preview", "Gemini 3 Pro"), - ("gemini-3-flash-preview", "Gemini 3 Flash"), - ("gemini-2.5-pro", "Gemini 2.5 Pro"), - ("gemini-2.5-flash", "Gemini 2.5 Flash"), - ("gemini-2.0-flash", "Gemini 2.0 Flash"), - ] - .iter() - .map(|(value, name)| ModelEntry::new(AgentProvider::GeminiCli, *value, *name)) - .collect() -} - -/// Fetch the Gemini model list from the generativelanguage API -/// using the same local credentials the TS route reads -/// (connect-agent.ts:904-973). `None` = no usable credentials or -/// the request failed (callers fall back silently, like the TS -/// `catch`); `Some(vec![])` = the API answered with nothing usable -/// (TS surfaces a warning). -pub fn gemini_models_from_api() -> Option> { - const BASE: &str = "https://generativelanguage.googleapis.com/v1beta/models"; - let env_key = std::env::var("GEMINI_API_KEY") - .ok() - .filter(|k| !k.is_empty()) - .or_else(|| { - std::env::var("GOOGLE_API_KEY") - .ok() - .filter(|k| !k.is_empty()) - }); - let (url, bearer) = match env_key { - Some(key) => (format!("{BASE}?key={key}"), None), - None => { - // OAuth token from the Gemini CLI login, with the same - // 60 s expiry guard the TS route applies. - let creds_path = dirs::home_dir()?.join(".gemini").join("oauth_creds.json"); - let raw = std::fs::read_to_string(creds_path).ok()?; - let creds: serde_json::Value = serde_json::from_str(&raw).ok()?; - let token = creds.get("access_token")?.as_str()?.to_string(); - if let Some(expiry) = creds.get("expiry_date").and_then(|v| v.as_f64()) { - let now_ms = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .ok()? - .as_millis() as f64; - if now_ms > expiry - 60_000.0 { - return None; // Token expired. - } - } - (BASE.to_string(), Some(token)) - } - }; - - let body = http_get_json(&url, bearer.as_deref())?; - Some(parse_gemini_models_json(&body)) -} - -/// Blocking GET returning the response body. reqwest is async-only -/// in this workspace, so spin a current-thread runtime — the same -/// shape `iconify_host.rs` uses. -fn http_get_json(url: &str, bearer: Option<&str>) -> Option { - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .ok()?; - runtime.block_on(async { - let client = reqwest::Client::builder() - .timeout(Duration::from_secs(15)) - .user_agent(concat!("openpencil-desktop/", env!("CARGO_PKG_VERSION"))) - .build() - .ok()?; - let mut req = client.get(url); - if let Some(token) = bearer { - req = req.header("Authorization", format!("Bearer {token}")); - } - let res = req.send().await.ok()?.error_for_status().ok()?; - res.text().await.ok() - }) -} - -/// Parse + filter + sort the generativelanguage models listing — -/// `generateContent` models only, embedding/AQA/legacy ids skipped, -/// gemini-3 sorted first (connect-agent.ts:933-972). -pub fn parse_gemini_models_json(body: &str) -> Vec { - let Ok(json) = serde_json::from_str::(body) else { - return Vec::new(); - }; - let Some(arr) = json.get("models").and_then(|v| v.as_array()) else { - return Vec::new(); - }; - let mut models = Vec::new(); - let mut seen = std::collections::HashSet::new(); - for m in arr { - let supports_generate = m - .get("supportedGenerationMethods") - .and_then(|v| v.as_array()) - .is_some_and(|methods| { - methods - .iter() - .any(|v| v.as_str() == Some("generateContent")) - }); - if !supports_generate { - continue; - } - let id = m - .get("name") - .and_then(|v| v.as_str()) - .unwrap_or("") - .trim_start_matches("models/") - .to_string(); - if id.is_empty() || seen.contains(&id) || gemini_id_is_skipped(&id) { - continue; - } - seen.insert(id.clone()); - let display = m - .get("displayName") - .and_then(|v| v.as_str()) - .unwrap_or(&id) - .to_string(); - models.push(ModelEntry::new(AgentProvider::GeminiCli, id, display)); - } - // Stable sort keeps the API order within each tier. - models.sort_by_key(|m| gemini_tier(&m.value)); - models -} - -/// TS skip regex `/embed|aqa|^chat-bison|^text-bison|^gemini-1\.0/i`. -fn gemini_id_is_skipped(id: &str) -> bool { - let lower = id.to_ascii_lowercase(); - lower.contains("embed") - || lower.contains("aqa") - || lower.starts_with("chat-bison") - || lower.starts_with("text-bison") - || lower.starts_with("gemini-1.0") -} - -/// TS sort order fn (connect-agent.ts:961-969). -fn gemini_tier(value: &str) -> u8 { - if value.contains("gemini-3") { - 0 - } else if value.contains("gemini-2.5-pro") { - 1 - } else if value.contains("gemini-2.5-flash") { - 2 - } else if value.contains("gemini-2.0") { - 3 - } else { - 4 - } -} - /// `CODEX_HOME` env override or `~/.codex` — the same resolution /// the TS route applies (connect-agent.ts:526). pub fn codex_home() -> Option { @@ -472,38 +317,11 @@ mod tests { } #[test] - fn fallback_model_lists_mirror_ts_constants() { + fn claude_fallback_models_mirror_ts_constants() { let claude = fallback_claude_models(); assert_eq!(claude.len(), 7); assert_eq!(claude[0].value, "claude-sonnet-4-6"); assert_eq!(claude[6].display_name, "Claude 3.5 Haiku"); - let gemini = fallback_gemini_models(); - assert_eq!(gemini.len(), 5); - assert_eq!(gemini[0].value, "gemini-3-pro-preview"); - assert_eq!(gemini[4].display_name, "Gemini 2.0 Flash"); - } - - #[test] - fn gemini_listing_filters_sorts_and_dedupes_like_ts() { - let body = r#"{"models":[ - {"name":"models/gemini-2.0-flash","displayName":"Gemini 2.0 Flash","supportedGenerationMethods":["generateContent"]}, - {"name":"models/text-embedding-004","displayName":"Embedding","supportedGenerationMethods":["embedContent"]}, - {"name":"models/gemini-embedding-001","displayName":"Gemini Embedding","supportedGenerationMethods":["generateContent"]}, - {"name":"models/aqa","displayName":"AQA","supportedGenerationMethods":["generateContent"]}, - {"name":"models/gemini-1.0-pro","displayName":"Legacy","supportedGenerationMethods":["generateContent"]}, - {"name":"models/gemini-3-pro-preview","displayName":"Gemini 3 Pro","supportedGenerationMethods":["generateContent"]}, - {"name":"models/gemini-2.5-pro","displayName":"Gemini 2.5 Pro","supportedGenerationMethods":["generateContent"]}, - {"name":"models/gemini-2.5-pro","displayName":"Duplicate","supportedGenerationMethods":["generateContent"]} - ]}"#; - let models = parse_gemini_models_json(body); - let values: Vec<&str> = models.iter().map(|m| m.value.as_str()).collect(); - // gemini-3 first, then 2.5-pro, then 2.0; embed/aqa/legacy - // skipped; duplicate deduped. - assert_eq!( - values, - ["gemini-3-pro-preview", "gemini-2.5-pro", "gemini-2.0-flash"] - ); - assert_eq!(models[0].display_name, "Gemini 3 Pro"); } #[test] @@ -524,15 +342,4 @@ mod tests { // displayName mirrors the slug like the TS mapper. assert_eq!(models[0].display_name, "gpt-5.5"); } - - #[test] - fn gemini_skip_filter_matches_ts_regex() { - assert!(gemini_id_is_skipped("text-embedding-004")); - assert!(gemini_id_is_skipped("aqa")); - assert!(gemini_id_is_skipped("chat-bison-001")); - assert!(gemini_id_is_skipped("gemini-1.0-pro")); - assert!(!gemini_id_is_skipped("gemini-2.5-flash")); - // `^` anchors: bison/legacy markers only skip at the start. - assert!(!gemini_id_is_skipped("my-chat-bison")); - } } diff --git a/crates/op-host-services/src/provider_probe_tests.rs b/crates/op-host-services/src/provider_probe_tests.rs index 26bacb089..5044083cf 100644 --- a/crates/op-host-services/src/provider_probe_tests.rs +++ b/crates/op-host-services/src/provider_probe_tests.rs @@ -169,10 +169,6 @@ fn install_commands_mirror_install_agent_ts() { install_command(AgentProvider::CodexCli), "npm install -g @openai/codex" ); - assert_eq!( - install_command(AgentProvider::GeminiCli), - "npm install -g @anthropic-ai/gemini-cli" - ); let antigravity = if cfg!(windows) { "irm https://antigravity.google/cli/install.ps1 | iex" } else { diff --git a/crates/op-host-services/src/settings_io.rs b/crates/op-host-services/src/settings_io.rs index 17365c588..8c03c248e 100644 --- a/crates/op-host-services/src/settings_io.rs +++ b/crates/op-host-services/src/settings_io.rs @@ -10,9 +10,8 @@ use std::sync::atomic::{AtomicU64, Ordering}; use op_editor_core::editor_ui_state::{RecentFile, RECENT_FILE_CAP}; use op_editor_core::{ - AcpAgentConfig, AcpConnectionType, AgentProvider, BuiltinAgentConfig, BuiltinAgentKind, - BuiltinAgentPresetKey, EditorState, ImageGenProfile, ImageGenProvider, Locale, McpCli, - ThemeMode, + AcpAgentConfig, AcpConnectionType, BuiltinAgentConfig, BuiltinAgentKind, BuiltinAgentPresetKey, + EditorState, ImageGenProfile, ImageGenProvider, Locale, ThemeMode, }; use serde::{Deserialize, Serialize}; @@ -79,14 +78,14 @@ pub struct Fingerprint { theme: ThemeMode, locale: Locale, port: u16, - cli: [bool; 8], + cli: [bool; 7], images_adv: bool, openverse_client_id: String, openverse_client_secret: String, openverse_credential_owner: Option, auto_update_enabled: bool, experimental_features_enabled: bool, - connected: [bool; 7], + connected: [bool; 6], builtin_agents: Vec, acp_agents: Vec, image_gen_profiles: Vec, @@ -148,10 +147,8 @@ struct SettingsPayload { auto_update_enabled: Option, #[serde(default)] experimental_features_enabled: Option, - /// Per-provider connect state, indexed by `AgentProvider::ALL` - /// (Claude / Codex / OpenCode / Copilot / Gemini / Antigravity / - /// Grok Build). Restored on - /// launch so the chat model picker survives a restart. + /// Per-provider connect state, indexed by `AgentProvider::ALL`. + /// Restored on launch so the chat model picker survives a restart. #[serde(default)] connected: Option>, #[serde(default)] @@ -259,10 +256,7 @@ fn apply_payload_with_options( eui.agent_settings.mcp_server.port = port.max(1024); } if let Some(flags) = payload.mcp_cli_enabled { - eui.agent_settings.mcp_cli_enabled = [false; 8]; - for (index, enabled) in flags.into_iter().take(McpCli::ALL.len()).enumerate() { - eui.agent_settings.mcp_cli_enabled[index] = enabled; - } + eui.agent_settings.mcp_cli_enabled = migrate_mcp_cli_flags(flags); } if let Some(b) = payload.images_advanced_open { eui.agent_settings.images_advanced_open = b; @@ -279,10 +273,7 @@ fn apply_payload_with_options( eui.agent_settings.experimental_features_enabled = b; } if let Some(c) = payload.connected { - eui.agent_settings.connected = [false; 7]; - for (index, connected) in c.into_iter().take(AgentProvider::ALL.len()).enumerate() { - eui.agent_settings.connected[index] = connected; - } + eui.agent_settings.connected = migrate_connected_provider_flags(c); } if let Some(agents) = payload.builtin_agents { let agents = agents @@ -365,6 +356,52 @@ fn apply_payload_with_options( state.rebuild_chat_models(); } +/// Remove the retired Gemini CLI slot from positional v1 settings without +/// shifting the providers that followed it. Released settings used either +/// five slots (through Gemini) or seven slots (Gemini + Antigravity + Grok); +/// the current six-slot layout omits Gemini. +fn migrate_connected_provider_flags(flags: Vec) -> [bool; 6] { + let mut migrated = [false; 6]; + match flags.len() { + 6 => migrated.copy_from_slice(&flags), + 5 => migrated[..4].copy_from_slice(&flags[..4]), + 7.. => { + migrated[..4].copy_from_slice(&flags[..4]); + migrated[4] = flags[5]; + migrated[5] = flags[6]; + } + _ => { + let unchanged = flags.len().min(4); + migrated[..unchanged].copy_from_slice(&flags[..unchanged]); + } + } + migrated +} + +/// Remove the retired Gemini CLI MCP slot from positional v1 settings. +/// Historical layouts had six or eight slots; the current seven-slot layout +/// keeps every other CLI in its original relative order. +fn migrate_mcp_cli_flags(flags: Vec) -> [bool; 7] { + let mut migrated = [false; 7]; + match flags.len() { + 7 => migrated.copy_from_slice(&flags), + 8.. => { + migrated[0] = flags[0]; + migrated[1] = flags[1]; + migrated[2..].copy_from_slice(&flags[3..8]); + } + 3..=6 => { + migrated[0] = flags[0]; + migrated[1] = flags[1]; + migrated[2..flags.len() - 1].copy_from_slice(&flags[3..]); + } + _ => { + migrated[..flags.len()].copy_from_slice(&flags); + } + } + migrated +} + fn builtin_agent_to_payload(agent: &BuiltinAgentConfig) -> BuiltinAgentPayload { BuiltinAgentPayload { id: agent.id.clone(), diff --git a/crates/op-host-services/src/settings_io_checked_tests.rs b/crates/op-host-services/src/settings_io_checked_tests.rs index 24f12ddff..3fa914476 100644 --- a/crates/op-host-services/src/settings_io_checked_tests.rs +++ b/crates/op-host-services/src/settings_io_checked_tests.rs @@ -62,6 +62,31 @@ fn checked_settings_load_rejects_an_unsupported_settings_version() { let _ = std::fs::remove_dir_all(root); } +#[test] +fn checked_settings_load_migrates_retired_gemini_cli_slots() { + let root = checked_settings_test_path("retired-gemini-cli"); + let path = root.join("settings.json"); + std::fs::create_dir_all(&root).expect("create settings test directory"); + std::fs::write( + &path, + br#"{"version":1,"connected":[true,false,true,false,true,true,false],"mcp_cli_enabled":[true,false,true,false,true,false,true,true]}"#, + ) + .expect("write legacy settings"); + let mut state = EditorState::new(); + + load_checked_from_path(&mut state, &path).expect("legacy v1 layout should migrate"); + + assert_eq!( + state.editor_ui.agent_settings.connected, + [true, false, true, false, true, false] + ); + assert_eq!( + state.editor_ui.agent_settings.mcp_cli_enabled, + [true, false, false, true, false, true, true] + ); + let _ = std::fs::remove_dir_all(root); +} + #[test] fn checked_settings_load_rejects_unknown_fields_at_every_settings_nesting_level() { let cases = vec![ diff --git a/crates/op-host-services/src/settings_io_tests.rs b/crates/op-host-services/src/settings_io_tests.rs index 0917aff1b..104969a36 100644 --- a/crates/op-host-services/src/settings_io_tests.rs +++ b/crates/op-host-services/src/settings_io_tests.rs @@ -109,9 +109,9 @@ fn imported_agents_are_excluded_from_persistence() { #[test] fn connected_state_round_trips_through_payload() { - // Connect Claude (0) + Gemini (4), leave the rest off. + // Connect Claude (0) + Antigravity (4), leave the rest off. let mut src = EditorState::new(); - src.editor_ui.agent_settings.connected = [true, false, false, false, true, true, false]; + src.editor_ui.agent_settings.connected = [true, false, false, false, true, false]; // Serialize → JSON → deserialize, the real on-disk path. let json = serde_json::to_string(&to_payload(&src)).unwrap(); let payload: SettingsPayload = serde_json::from_str(&json).unwrap(); @@ -119,7 +119,7 @@ fn connected_state_round_trips_through_payload() { apply_payload(&mut dst, payload); assert_eq!( dst.editor_ui.agent_settings.connected, - [true, false, false, false, true, true, false] + [true, false, false, false, true, false] ); } @@ -130,26 +130,58 @@ fn six_cli_mcp_payload_migrates_to_new_cli_count() { ) .unwrap(); let mut dst = EditorState::new(); - dst.editor_ui.agent_settings.mcp_cli_enabled = [true; 8]; + dst.editor_ui.agent_settings.mcp_cli_enabled = [true; 7]; apply_payload(&mut dst, payload); assert_eq!( dst.editor_ui.agent_settings.mcp_cli_enabled, - [true, false, true, false, true, true, false, false] + [true, false, false, true, true, false, false] ); } #[test] -fn five_provider_connected_payload_migrates_to_new_provider_count() { +fn eight_cli_mcp_payload_drops_gemini_without_shifting_later_clis() { + let payload: SettingsPayload = serde_json::from_str( + r#"{"version":1,"mcp_cli_enabled":[true,false,true,false,true,false,true,true]}"#, + ) + .unwrap(); + let mut dst = EditorState::new(); + + apply_payload(&mut dst, payload); + + assert_eq!( + dst.editor_ui.agent_settings.mcp_cli_enabled, + [true, false, false, true, false, true, true] + ); +} + +#[test] +fn seven_provider_connected_payload_drops_gemini_without_shifting_later_providers() { + let payload: SettingsPayload = serde_json::from_str( + r#"{"version":1,"connected":[true,false,true,false,true,true,false]}"#, + ) + .unwrap(); + let mut dst = EditorState::new(); + + apply_payload(&mut dst, payload); + + assert_eq!( + dst.editor_ui.agent_settings.connected, + [true, false, true, false, true, false] + ); +} + +#[test] +fn five_provider_connected_payload_drops_retired_gemini() { let payload: SettingsPayload = serde_json::from_str(r#"{"version":1,"connected":[true,false,false,false,true]}"#).unwrap(); let mut dst = EditorState::new(); - dst.editor_ui.agent_settings.connected = [false, false, false, false, false, true, true]; + dst.editor_ui.agent_settings.connected = [false, false, false, false, true, true]; apply_payload(&mut dst, payload); assert_eq!( dst.editor_ui.agent_settings.connected, - [true, false, false, false, true, false, false] + [true, false, false, false, false, false] ); } @@ -162,7 +194,7 @@ fn legacy_settings_without_connected_field_default_to_disconnected() { let payload: SettingsPayload = serde_json::from_str(legacy).unwrap(); let mut dst = EditorState::new(); apply_payload(&mut dst, payload); - assert_eq!(dst.editor_ui.agent_settings.connected, [false; 7]); + assert_eq!(dst.editor_ui.agent_settings.connected, [false; 6]); } #[test] diff --git a/crates/op-host-services/src/web_canvas_server.rs b/crates/op-host-services/src/web_canvas_server.rs index 5aa754af9..addfab5e6 100644 --- a/crates/op-host-services/src/web_canvas_server.rs +++ b/crates/op-host-services/src/web_canvas_server.rs @@ -965,7 +965,6 @@ fn parse_agent_provider(raw: &str) -> Option { "codex" | "codexcli" => Some(AgentProvider::CodexCli), "opencode" => Some(AgentProvider::OpenCode), "githubcopilot" | "copilot" => Some(AgentProvider::GithubCopilot), - "gemini" | "geminicli" => Some(AgentProvider::GeminiCli), "antigravity" | "agy" => Some(AgentProvider::Antigravity), "grok" | "grokbuild" => Some(AgentProvider::GrokBuild), _ => None, @@ -982,7 +981,6 @@ fn provider_to_probe( AgentProvider::CodexCli => ProbeProvider::CodexCli, AgentProvider::OpenCode => ProbeProvider::OpenCode, AgentProvider::GithubCopilot => ProbeProvider::GithubCopilot, - AgentProvider::GeminiCli => ProbeProvider::GeminiCli, AgentProvider::Antigravity => ProbeProvider::Antigravity, AgentProvider::GrokBuild => ProbeProvider::GrokBuild, } @@ -1086,7 +1084,6 @@ fn provider_key(provider: op_editor_core::AgentProvider) -> &'static str { AgentProvider::CodexCli => "codex", AgentProvider::OpenCode => "opencode", AgentProvider::GithubCopilot => "github-copilot", - AgentProvider::GeminiCli => "gemini", AgentProvider::Antigravity => "antigravity", AgentProvider::GrokBuild => "grok-build", } diff --git a/crates/op-host-services/src/web_canvas_server_tests.rs b/crates/op-host-services/src/web_canvas_server_tests.rs index e7ca36c85..e6578bc8c 100644 --- a/crates/op-host-services/src/web_canvas_server_tests.rs +++ b/crates/op-host-services/src/web_canvas_server_tests.rs @@ -817,6 +817,26 @@ fn web_cli_and_acp_connect_routes_are_unavailable_in_both_dispatchers() { } } +#[test] +fn retired_gemini_cli_connect_aliases_are_rejected_before_probe() { + for provider in ["gemini", "gemini-cli"] { + let mut state = fresh_state(); + let body = serde_json::json!({ "provider": provider }).to_string(); + + let reply = handle_provider_connect_request_with_probe(&body, &mut state, |_| { + panic!("retired Gemini CLI request must not reach the probe") + }); + + assert_eq!(reply.status, "400 Bad Request", "provider={provider}"); + assert!(state + .editor + .editor_ui + .agent_settings + .pending_provider_connect + .is_none()); + } +} + #[test] fn post_open_recent_loads_recent_path_and_bumps_version() { use op_editor_core::editor_ui_state::RecentFile; diff --git a/crates/op-host-web/src/web_agent_connect.rs b/crates/op-host-web/src/web_agent_connect.rs index 9c4368a27..d736b0091 100644 --- a/crates/op-host-web/src/web_agent_connect.rs +++ b/crates/op-host-web/src/web_agent_connect.rs @@ -200,9 +200,6 @@ fn missing_models_connect_error(provider: AgentProvider) -> String { AgentProvider::GithubCopilot => { "No models found. GitHub Copilot did not return a model list.".to_string() } - AgentProvider::GeminiCli => { - "No models found. Gemini CLI did not return a model list.".to_string() - } AgentProvider::Antigravity => { "No model available. Antigravity did not expose its default model.".to_string() } @@ -218,7 +215,6 @@ fn provider_key(provider: AgentProvider) -> &'static str { AgentProvider::CodexCli => "codex", AgentProvider::OpenCode => "opencode", AgentProvider::GithubCopilot => "github-copilot", - AgentProvider::GeminiCli => "gemini", AgentProvider::Antigravity => "antigravity", AgentProvider::GrokBuild => "grok-build", } diff --git a/crates/op-host-web/src/web_chat.rs b/crates/op-host-web/src/web_chat.rs index 50ee5d14c..20cdd7329 100644 --- a/crates/op-host-web/src/web_chat.rs +++ b/crates/op-host-web/src/web_chat.rs @@ -635,7 +635,7 @@ mod tests { .all(|entry| entry.builtin_provider_id.is_some())); assert_eq!( state.chat.available_models[1].provider, - AgentProvider::GeminiCli + AgentProvider::CodexCli ); // Select the second model, then re-apply a re-ordered catalog — the // selection follows the entry by identity. @@ -661,7 +661,7 @@ mod tests { assert_eq!(provider_for_model_id("gpt-5.5"), AgentProvider::CodexCli); assert_eq!( provider_for_model_id("gemini-2.5-pro"), - AgentProvider::GeminiCli + AgentProvider::CodexCli ); assert_eq!( provider_for_model_id("copilot-fast"), diff --git a/crates/op-host-web/src/web_model_catalog.rs b/crates/op-host-web/src/web_model_catalog.rs index f7c1ff675..35cf234a5 100644 --- a/crates/op-host-web/src/web_model_catalog.rs +++ b/crates/op-host-web/src/web_model_catalog.rs @@ -109,13 +109,14 @@ fn parse_builtin_model_key(value: &str) -> Option<(&str, &str)> { /// Heuristic provider tag for a legacy daemon built-in model id. pub(crate) fn provider_for_model_id(id: &str) -> AgentProvider { let lower = id.to_ascii_lowercase(); - if lower.contains("gemini") { - AgentProvider::GeminiCli - } else if lower.contains("antigravity") { + if lower.contains("antigravity") { AgentProvider::Antigravity } else if lower.contains("grok") { AgentProvider::GrokBuild - } else if lower.contains("gpt") || lower.contains("codex") { + } else if lower.contains("gpt") || lower.contains("codex") || lower.contains("gemini") { + // Legacy bare model ids have no transport identity. Gemini API + // built-ins use the generic OpenAI-compatible tag; they must not be + // mislabeled as the retired Gemini CLI or as Antigravity. AgentProvider::CodexCli } else if lower.contains("copilot") { AgentProvider::GithubCopilot diff --git a/crates/op-host-web/src/web_settings.rs b/crates/op-host-web/src/web_settings.rs index 71c09d3b6..04cfd3d53 100644 --- a/crates/op-host-web/src/web_settings.rs +++ b/crates/op-host-web/src/web_settings.rs @@ -8,7 +8,7 @@ use op_editor_core::editor_ui_state::{RecentFile, RECENT_FILE_CAP}; use op_editor_core::{ BuiltinAgentConfig, BuiltinAgentKind, BuiltinAgentPresetKey, EditorState, ImageGenProfile, - ImageGenProvider, Locale, McpCli, ThemeMode, + ImageGenProvider, Locale, ThemeMode, }; use serde::{Deserialize, Serialize}; @@ -75,7 +75,7 @@ pub(crate) struct Fingerprint { theme: ThemeMode, locale: Locale, port: u16, - cli: [bool; 8], + cli: [bool; 7], images_adv: bool, auto_update_enabled: bool, experimental_features_enabled: bool, @@ -250,10 +250,7 @@ fn apply_payload(state: &mut EditorState, payload: SettingsPayload) { eui.agent_settings.mcp_server.port = port.max(1024); } if let Some(flags) = payload.mcp_cli_enabled { - eui.agent_settings.mcp_cli_enabled = [false; 8]; - for (index, enabled) in flags.into_iter().take(McpCli::ALL.len()).enumerate() { - eui.agent_settings.mcp_cli_enabled[index] = enabled; - } + eui.agent_settings.mcp_cli_enabled = migrate_mcp_cli_flags(flags); } if let Some(open) = payload.images_advanced_open { eui.agent_settings.images_advanced_open = open; @@ -321,6 +318,29 @@ fn apply_payload(state: &mut EditorState, payload: SettingsPayload) { state.rebuild_chat_models(); } +/// Remove the retired Gemini CLI slot from positional browser settings. +/// Released snapshots used six or eight entries; current snapshots use seven. +fn migrate_mcp_cli_flags(flags: Vec) -> [bool; 7] { + let mut migrated = [false; 7]; + match flags.len() { + 7 => migrated.copy_from_slice(&flags), + 8.. => { + migrated[0] = flags[0]; + migrated[1] = flags[1]; + migrated[2..].copy_from_slice(&flags[3..8]); + } + 3..=6 => { + migrated[0] = flags[0]; + migrated[1] = flags[1]; + migrated[2..flags.len() - 1].copy_from_slice(&flags[3..]); + } + _ => { + migrated[..flags.len()].copy_from_slice(&flags); + } + } + migrated +} + fn apply_credential_payload(state: &mut EditorState, payload: CredentialPayload) { let settings = &mut state.editor_ui.agent_settings; settings.builtin_agents = dedupe_builtin_agents( diff --git a/crates/op-host-web/src/web_settings_legacy.rs b/crates/op-host-web/src/web_settings_legacy.rs index 49758cda6..115a54eda 100644 --- a/crates/op-host-web/src/web_settings_legacy.rs +++ b/crates/op-host-web/src/web_settings_legacy.rs @@ -74,6 +74,18 @@ pub(super) fn prepare(raw: &str) -> PreparedSettings { .as_object_mut() .expect("browser settings object was checked above"); let mut sanitized = removed_forbidden; + if let Some(flags) = payload + .mcp_cli_enabled + .as_ref() + .filter(|flags| flags.len() != op_editor_core::McpCli::ALL.len()) + { + object.insert( + "mcp_cli_enabled".into(), + serde_json::to_value(super::migrate_mcp_cli_flags(flags.clone())) + .expect("boolean array serialization cannot fail"), + ); + sanitized = true; + } for key in [ "openverse_oauth", "builtin_agents", diff --git a/crates/op-host-web/src/web_settings_tests.rs b/crates/op-host-web/src/web_settings_tests.rs index eebd74574..e3ea77e12 100644 --- a/crates/op-host-web/src/web_settings_tests.rs +++ b/crates/op-host-web/src/web_settings_tests.rs @@ -58,6 +58,39 @@ fn settings_payload_round_trips_recent_files_and_mcp_preferences() { assert_eq!(dst.editor_ui.recent_files[0].path, "/tmp/a.op"); } +#[test] +fn legacy_mcp_flags_drop_gemini_without_shifting_google_antigravity() { + let legacy = r#"{ + "version":1, + "mcp_cli_enabled":[true,false,true,false,true,false,true,true] + }"#; + let mut state = EditorState::new(); + let mut writes = Vec::new(); + + let loaded = load_into_with(&mut state, Some(legacy), None, |key, json| { + writes.push((key.to_string(), json.to_string())); + true + }); + + assert!( + !loaded.loaded, + "ordinary settings do not contain a credential payload" + ); + assert_eq!( + state.editor_ui.agent_settings.mcp_cli_enabled, + [true, false, false, true, false, true, true] + ); + let rewritten = writes + .iter() + .find_map(|(key, json)| (key == STORAGE_KEY).then_some(json)) + .expect("legacy positional settings should be rewritten"); + let value: serde_json::Value = serde_json::from_str(rewritten).expect("rewritten settings"); + assert_eq!( + value["mcp_cli_enabled"], + serde_json::json!([true, false, false, true, false, true, true]) + ); +} + #[test] fn separate_settings_and_credential_payloads_round_trip_their_own_fields() { let mut src = EditorState::new(); diff --git a/crates/op-host-web/src/web_settings_validation.rs b/crates/op-host-web/src/web_settings_validation.rs index 1dce4dc1b..3b8dabe3b 100644 --- a/crates/op-host-web/src/web_settings_validation.rs +++ b/crates/op-host-web/src/web_settings_validation.rs @@ -185,9 +185,9 @@ fn validate_general_semantics(payload: &SettingsPayload) -> Result<(), String> { if payload .mcp_cli_enabled .as_ref() - .is_some_and(|enabled| enabled.len() != McpCli::ALL.len()) + .is_some_and(|enabled| !matches!(enabled.len(), 6..=8)) { - return Err("browser MCP CLI flags would be normalized".into()); + return Err("unsupported browser MCP CLI flag layout".into()); } if payload .recent_files diff --git a/crates/op-host-web/src/widget_host/deferred_press_tests.rs b/crates/op-host-web/src/widget_host/deferred_press_tests.rs index 0399a8213..07f7b2656 100644 --- a/crates/op-host-web/src/widget_host/deferred_press_tests.rs +++ b/crates/op-host-web/src/widget_host/deferred_press_tests.rs @@ -20,9 +20,9 @@ fn seed_two_chat_models(host: &mut WidgetHost) { .chat .available_models .push(ModelEntry::new( - AgentProvider::GeminiCli, - "gemini-2.5-pro", - "Gemini 2.5 Pro", + AgentProvider::Antigravity, + "default", + "Antigravity Default", )); } diff --git a/crates/op-i18n/src/i18n/de.rs b/crates/op-i18n/src/i18n/de.rs index 491e22414..813d2af8f 100644 --- a/crates/op-i18n/src/i18n/de.rs +++ b/crates/op-i18n/src/i18n/de.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ LLM-Anbieter", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot-Modelle", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini-Modelle", "agents.mcpServer" => "MCP-Server", "agents.mcpServerStart" => "Starten", "agents.mcpServerStop" => "Stoppen", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI-Modelle", "settings.provider.openCode" => "Über 75 LLM-Anbieter", "settings.provider.githubCopilot" => "GitHub-Copilot-Modelle", - "settings.provider.geminiCli" => "Google-Gemini-Modelle", "settings.provider.antigravity" => "Antigravity-Modelle", "settings.provider.grokBuild" => "Grok-Build-Modelle", "settings.system.title" => "System", diff --git a/crates/op-i18n/src/i18n/en.rs b/crates/op-i18n/src/i18n/en.rs index a151c9829..68d59f941 100644 --- a/crates/op-i18n/src/i18n/en.rs +++ b/crates/op-i18n/src/i18n/en.rs @@ -429,8 +429,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ LLM providers", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot models", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini models", "agents.mcpServer" => "MCP Server", "agents.mcpServerStart" => "Start", "agents.mcpServerStop" => "Stop", @@ -633,7 +631,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI models", "settings.provider.openCode" => "75+ LLM providers", "settings.provider.githubCopilot" => "GitHub Copilot models", - "settings.provider.geminiCli" => "Google Gemini models", "settings.provider.antigravity" => "Antigravity models", "settings.provider.grokBuild" => "Grok Build models", "settings.system.title" => "System", diff --git a/crates/op-i18n/src/i18n/es.rs b/crates/op-i18n/src/i18n/es.rs index dfa1ac834..a8abaedb3 100644 --- a/crates/op-i18n/src/i18n/es.rs +++ b/crates/op-i18n/src/i18n/es.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ proveedores LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "Modelos GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Modelos Google Gemini", "agents.mcpServer" => "Servidor MCP", "agents.mcpServerStart" => "Iniciar", "agents.mcpServerStop" => "Detener", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "Modelos OpenAI", "settings.provider.openCode" => "Más de 75 proveedores de LLM", "settings.provider.githubCopilot" => "Modelos GitHub Copilot", - "settings.provider.geminiCli" => "Modelos Google Gemini", "settings.provider.antigravity" => "Modelos Antigravity", "settings.provider.grokBuild" => "Modelos Grok Build", "settings.system.title" => "Sistema", diff --git a/crates/op-i18n/src/i18n/fr.rs b/crates/op-i18n/src/i18n/fr.rs index 32de903be..038deb994 100644 --- a/crates/op-i18n/src/i18n/fr.rs +++ b/crates/op-i18n/src/i18n/fr.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ fournisseurs LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "Modèles GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Modèles Google Gemini", "agents.mcpServer" => "Serveur MCP", "agents.mcpServerStart" => "Démarrer", "agents.mcpServerStop" => "Arrêter", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "Modèles OpenAI", "settings.provider.openCode" => "Plus de 75 fournisseurs de LLM", "settings.provider.githubCopilot" => "Modèles GitHub Copilot", - "settings.provider.geminiCli" => "Modèles Google Gemini", "settings.provider.antigravity" => "Modèles Antigravity", "settings.provider.grokBuild" => "Modèles Grok Build", "settings.system.title" => "Système", diff --git a/crates/op-i18n/src/i18n/hi.rs b/crates/op-i18n/src/i18n/hi.rs index e54be75a9..028c3fb91 100644 --- a/crates/op-i18n/src/i18n/hi.rs +++ b/crates/op-i18n/src/i18n/hi.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ LLM प्रदाता", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot मॉडल", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini मॉडल", "agents.mcpServer" => "MCP सर्वर", "agents.mcpServerStart" => "शुरू करें", "agents.mcpServerStop" => "रोकें", @@ -590,7 +588,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI मॉडल", "settings.provider.openCode" => "75+ LLM प्रदाता", "settings.provider.githubCopilot" => "GitHub Copilot मॉडल", - "settings.provider.geminiCli" => "Google Gemini मॉडल", "settings.provider.antigravity" => "Antigravity मॉडल", "settings.provider.grokBuild" => "Grok Build मॉडल", "settings.system.title" => "सिस्टम", diff --git a/crates/op-i18n/src/i18n/id.rs b/crates/op-i18n/src/i18n/id.rs index d0c37b6ee..185c531c1 100644 --- a/crates/op-i18n/src/i18n/id.rs +++ b/crates/op-i18n/src/i18n/id.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ penyedia LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "Model GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Model Google Gemini", "agents.mcpServer" => "Server MCP", "agents.mcpServerStart" => "Mulai", "agents.mcpServerStop" => "Hentikan", @@ -590,7 +588,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "Model OpenAI", "settings.provider.openCode" => "75+ penyedia LLM", "settings.provider.githubCopilot" => "Model GitHub Copilot", - "settings.provider.geminiCli" => "Model Google Gemini", "settings.provider.antigravity" => "Model Antigravity", "settings.provider.grokBuild" => "Model Grok Build", "settings.system.title" => "Sistem", diff --git a/crates/op-i18n/src/i18n/ja.rs b/crates/op-i18n/src/i18n/ja.rs index ffb8b6b3d..6f7aa4231 100644 --- a/crates/op-i18n/src/i18n/ja.rs +++ b/crates/op-i18n/src/i18n/ja.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75 以上の LLM プロバイダー", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot モデル", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini モデル", "agents.mcpServer" => "MCP サーバー", "agents.mcpServerStart" => "開始", "agents.mcpServerStop" => "停止", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI モデル", "settings.provider.openCode" => "75+ の LLM プロバイダー", "settings.provider.githubCopilot" => "GitHub Copilot モデル", - "settings.provider.geminiCli" => "Google Gemini モデル", "settings.provider.antigravity" => "Antigravity モデル", "settings.provider.grokBuild" => "Grok Build モデル", "settings.system.title" => "システム", diff --git a/crates/op-i18n/src/i18n/ko.rs b/crates/op-i18n/src/i18n/ko.rs index e78b72dc8..446fd8897 100644 --- a/crates/op-i18n/src/i18n/ko.rs +++ b/crates/op-i18n/src/i18n/ko.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75개 이상의 LLM 제공자", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot 모델", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini 모델", "agents.mcpServer" => "MCP 서버", "agents.mcpServerStart" => "시작", "agents.mcpServerStop" => "정지", @@ -590,7 +588,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI 모델", "settings.provider.openCode" => "75개 이상의 LLM 제공자", "settings.provider.githubCopilot" => "GitHub Copilot 모델", - "settings.provider.geminiCli" => "Google Gemini 모델", "settings.provider.antigravity" => "Antigravity 모델", "settings.provider.grokBuild" => "Grok Build 모델", "settings.system.title" => "시스템", diff --git a/crates/op-i18n/src/i18n/pt.rs b/crates/op-i18n/src/i18n/pt.rs index 9e18614c3..ce9c258b3 100644 --- a/crates/op-i18n/src/i18n/pt.rs +++ b/crates/op-i18n/src/i18n/pt.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ provedores de LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "Modelos GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Modelos Google Gemini", "agents.mcpServer" => "Servidor MCP", "agents.mcpServerStart" => "Iniciar", "agents.mcpServerStop" => "Parar", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "Modelos OpenAI", "settings.provider.openCode" => "Mais de 75 provedores de LLM", "settings.provider.githubCopilot" => "Modelos GitHub Copilot", - "settings.provider.geminiCli" => "Modelos Google Gemini", "settings.provider.antigravity" => "Modelos Antigravity", "settings.provider.grokBuild" => "Modelos Grok Build", "settings.system.title" => "Sistema", diff --git a/crates/op-i18n/src/i18n/ru.rs b/crates/op-i18n/src/i18n/ru.rs index 88138bd1d..98cfd7ac1 100644 --- a/crates/op-i18n/src/i18n/ru.rs +++ b/crates/op-i18n/src/i18n/ru.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ провайдеров LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "Модели GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Модели Google Gemini", "agents.mcpServer" => "MCP Сервер", "agents.mcpServerStart" => "Запустить", "agents.mcpServerStop" => "Остановить", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "Модели OpenAI", "settings.provider.openCode" => "Более 75 провайдеров LLM", "settings.provider.githubCopilot" => "Модели GitHub Copilot", - "settings.provider.geminiCli" => "Модели Google Gemini", "settings.provider.antigravity" => "Модели Antigravity", "settings.provider.grokBuild" => "Модели Grok Build", "settings.system.title" => "Система", diff --git a/crates/op-i18n/src/i18n/th.rs b/crates/op-i18n/src/i18n/th.rs index 9bed354c9..99bbd38b0 100644 --- a/crates/op-i18n/src/i18n/th.rs +++ b/crates/op-i18n/src/i18n/th.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ ผู้ให้บริการ LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "โมเดล GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "โมเดล Google Gemini", "agents.mcpServer" => "เซิร์ฟเวอร์ MCP", "agents.mcpServerStart" => "เริ่ม", "agents.mcpServerStop" => "หยุด", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "โมเดล OpenAI", "settings.provider.openCode" => "ผู้ให้บริการ LLM มากกว่า 75 ราย", "settings.provider.githubCopilot" => "โมเดล GitHub Copilot", - "settings.provider.geminiCli" => "โมเดล Google Gemini", "settings.provider.antigravity" => "โมเดล Antigravity", "settings.provider.grokBuild" => "โมเดล Grok Build", "settings.system.title" => "ระบบ", diff --git a/crates/op-i18n/src/i18n/tr.rs b/crates/op-i18n/src/i18n/tr.rs index 810a2e19a..eed69dfe2 100644 --- a/crates/op-i18n/src/i18n/tr.rs +++ b/crates/op-i18n/src/i18n/tr.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ LLM sağlayıcı", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot modelleri", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini modelleri", "agents.mcpServer" => "MCP Sunucu", "agents.mcpServerStart" => "Başlat", "agents.mcpServerStop" => "Durdur", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI modelleri", "settings.provider.openCode" => "75'ten fazla LLM sağlayıcısı", "settings.provider.githubCopilot" => "GitHub Copilot modelleri", - "settings.provider.geminiCli" => "Google Gemini modelleri", "settings.provider.antigravity" => "Antigravity modelleri", "settings.provider.grokBuild" => "Grok Build modelleri", "settings.system.title" => "Sistem", diff --git a/crates/op-i18n/src/i18n/vi.rs b/crates/op-i18n/src/i18n/vi.rs index fbf508e2d..429e1358f 100644 --- a/crates/op-i18n/src/i18n/vi.rs +++ b/crates/op-i18n/src/i18n/vi.rs @@ -403,8 +403,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ nhà cung cấp LLM", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "Các mô hình GitHub Copilot", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Các mô hình Google Gemini", "agents.mcpServer" => "Máy chủ MCP", "agents.mcpServerStart" => "Khởi động", "agents.mcpServerStop" => "Dừng", @@ -592,7 +590,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "Mô hình OpenAI", "settings.provider.openCode" => "Hơn 75 nhà cung cấp LLM", "settings.provider.githubCopilot" => "Mô hình GitHub Copilot", - "settings.provider.geminiCli" => "Mô hình Google Gemini", "settings.provider.antigravity" => "Mô hình Antigravity", "settings.provider.grokBuild" => "Mô hình Grok Build", "settings.system.title" => "Hệ thống", diff --git a/crates/op-i18n/src/i18n/zh_cn.rs b/crates/op-i18n/src/i18n/zh_cn.rs index b8dd16870..bf5b0ff94 100644 --- a/crates/op-i18n/src/i18n/zh_cn.rs +++ b/crates/op-i18n/src/i18n/zh_cn.rs @@ -433,8 +433,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ LLM 提供商", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot 模型", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini 模型", "agents.mcpServer" => "MCP 服务器", "agents.mcpServerStart" => "启动", "agents.mcpServerStop" => "停止", @@ -639,7 +637,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI 模型", "settings.provider.openCode" => "75+ LLM 提供商", "settings.provider.githubCopilot" => "GitHub Copilot 模型", - "settings.provider.geminiCli" => "Google Gemini 模型", "settings.provider.antigravity" => "Antigravity 模型", "settings.provider.grokBuild" => "Grok Build 模型", "settings.system.title" => "系统", diff --git a/crates/op-i18n/src/i18n/zh_tw.rs b/crates/op-i18n/src/i18n/zh_tw.rs index 28135488a..1081438db 100644 --- a/crates/op-i18n/src/i18n/zh_tw.rs +++ b/crates/op-i18n/src/i18n/zh_tw.rs @@ -412,8 +412,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "agents.opencodeDesc" => "75+ LLM 供應商", "agents.copilot" => "GitHub Copilot", "agents.copilotDesc" => "GitHub Copilot 模型", - "agents.geminiCli" => "Gemini CLI", - "agents.geminiDesc" => "Google Gemini 模型", "agents.mcpServer" => "MCP 伺服器", "agents.mcpServerStart" => "啟動", "agents.mcpServerStop" => "停止", @@ -608,7 +606,6 @@ pub fn lookup(key: &str) -> Option<&'static str> { "settings.provider.codexCli" => "OpenAI 模型", "settings.provider.openCode" => "75+ LLM 供應商", "settings.provider.githubCopilot" => "GitHub Copilot 模型", - "settings.provider.geminiCli" => "Google Gemini 模型", "settings.provider.antigravity" => "Antigravity 模型", "settings.provider.grokBuild" => "Grok Build 模型", "settings.system.title" => "系統", diff --git a/tools/check-version-sync.sh b/tools/check-version-sync.sh index cd590ee63..5dd33e586 100755 --- a/tools/check-version-sync.sh +++ b/tools/check-version-sync.sh @@ -362,9 +362,9 @@ validate_cli_bundle_version_template() { bundle=crates/op-cli/assets/skill-bundle.json sentinel=__OPENPENCIL_VERSION__ sentinel_count=$(rg --fixed-strings --count-matches -- "$sentinel" "$bundle" || true) - if [[ "${sentinel_count:-0}" != 6 ]]; then + if [[ "${sentinel_count:-0}" != 5 ]]; then report_missing "$bundle" \ - "expected exactly 6 version sentinels ${sentinel} (found ${sentinel_count:-0})" + "expected exactly 5 version sentinels ${sentinel} (found ${sentinel_count:-0})" fi reject_matches fixed "$bundle" "$current_version" \ 'embedded CLI bundle must not contain the canonical version literal' diff --git a/tools/check-version-sync.test.sh b/tools/check-version-sync.test.sh index 4772d68a5..a5db346f9 100755 --- a/tools/check-version-sync.test.sh +++ b/tools/check-version-sync.test.sh @@ -218,7 +218,7 @@ new_repo() { printf '%s\n' '{"name":"fixture-packages"}' > "$repo/packages/package.json" cat > "$repo/crates/op-cli/assets/skill-bundle.json" <<'JSON' -{"one":"__OPENPENCIL_VERSION__","two":"__OPENPENCIL_VERSION__","three":"__OPENPENCIL_VERSION__","four":"__OPENPENCIL_VERSION__","five":"__OPENPENCIL_VERSION__","six":"__OPENPENCIL_VERSION__"} +{"one":"__OPENPENCIL_VERSION__","two":"__OPENPENCIL_VERSION__","three":"__OPENPENCIL_VERSION__","four":"__OPENPENCIL_VERSION__","five":"__OPENPENCIL_VERSION__"} JSON cat > "$repo/crates/op-editor-core/src/state.rs" <<'RUST' version: env!("CARGO_PKG_VERSION").to_owned(), @@ -690,15 +690,15 @@ assert_no_success_output 'mismatched release tag' pass 'mismatched v* release tags are rejected outside the release workflow too' repo=$(new_repo cli_bundle_wrong_sentinel_count 0.8.1) -sed -i.bak 's/,"six":"__OPENPENCIL_VERSION__"//' \ +sed -i.bak 's/,"five":"__OPENPENCIL_VERSION__"//' \ "$repo/crates/op-cli/assets/skill-bundle.json" rm "$repo/crates/op-cli/assets/skill-bundle.json.bak" run_guard "$repo" assert_status 1 'CLI bundle sentinel count' -assert_contains 'crates/op-cli/assets/skill-bundle.json:1: error: expected exactly 6 version sentinels' \ +assert_contains 'crates/op-cli/assets/skill-bundle.json:1: error: expected exactly 5 version sentinels' \ 'CLI bundle sentinel count' assert_no_success_output 'CLI bundle sentinel count' -pass 'embedded CLI bundle retains exactly six version sentinels' +pass 'embedded CLI bundle retains exactly five version sentinels' repo=$(new_repo cli_bundle_without_sentinels 0.8.1) sed -i.bak 's/__OPENPENCIL_VERSION__/__MISSING_VERSION__/g' \ @@ -706,7 +706,7 @@ sed -i.bak 's/__OPENPENCIL_VERSION__/__MISSING_VERSION__/g' \ rm "$repo/crates/op-cli/assets/skill-bundle.json.bak" run_guard "$repo" assert_status 1 'CLI bundle missing sentinels' -assert_contains 'crates/op-cli/assets/skill-bundle.json:1: error: expected exactly 6 version sentinels' \ +assert_contains 'crates/op-cli/assets/skill-bundle.json:1: error: expected exactly 5 version sentinels' \ 'CLI bundle missing sentinels' assert_contains '(found 0)' 'CLI bundle missing sentinels' assert_no_success_output 'CLI bundle missing sentinels' diff --git a/tools/merge-settings-i18n.py b/tools/merge-settings-i18n.py index 7aa2ddf0c..c3460a13e 100644 --- a/tools/merge-settings-i18n.py +++ b/tools/merge-settings-i18n.py @@ -33,7 +33,7 @@ KEYS = [ "settings.images.clientSecretPlaceholder", "settings.images.registerLink", "settings.images.test", "settings.images.generation", "settings.images.add", "settings.images.empty", "settings.provider.claudeCode", "settings.provider.codexCli", - "settings.provider.openCode", "settings.provider.githubCopilot", "settings.provider.geminiCli", + "settings.provider.openCode", "settings.provider.githubCopilot", "settings.system.title", "settings.system.autoUpdate", "settings.system.upToDate", "settings.system.upToDateDescription", "settings.system.checking", "settings.system.checkingDescription", "settings.system.updateAvailable", @@ -86,7 +86,6 @@ EN = { "settings.provider.codexCli": "OpenAI models", "settings.provider.openCode": "75+ LLM providers", "settings.provider.githubCopilot": "GitHub Copilot models", - "settings.provider.geminiCli": "Google Gemini models", "settings.system.title": "System", "settings.system.autoUpdate": "Auto-update", "settings.system.upToDate": "Up to date", @@ -139,7 +138,6 @@ ZH_CN = { "settings.provider.codexCli": "OpenAI 模型", "settings.provider.openCode": "75+ LLM 提供商", "settings.provider.githubCopilot": "GitHub Copilot 模型", - "settings.provider.geminiCli": "Google Gemini 模型", "settings.system.title": "系统", "settings.system.autoUpdate": "自动更新", "settings.system.upToDate": "已是最新", @@ -192,7 +190,6 @@ ZH_TW = { "settings.provider.codexCli": "OpenAI 模型", "settings.provider.openCode": "75+ LLM 供應商", "settings.provider.githubCopilot": "GitHub Copilot 模型", - "settings.provider.geminiCli": "Google Gemini 模型", "settings.system.title": "系統", "settings.system.autoUpdate": "自動更新", "settings.system.upToDate": "已是最新", @@ -247,7 +244,6 @@ JA = { "settings.provider.codexCli": "OpenAI モデル", "settings.provider.openCode": "75+ の LLM プロバイダー", "settings.provider.githubCopilot": "GitHub Copilot モデル", - "settings.provider.geminiCli": "Google Gemini モデル", "settings.system.title": "システム", "settings.system.autoUpdate": "自動更新", "settings.system.upToDate": "最新です", @@ -302,7 +298,6 @@ KO = { "settings.provider.codexCli": "OpenAI 모델", "settings.provider.openCode": "75개 이상의 LLM 제공자", "settings.provider.githubCopilot": "GitHub Copilot 모델", - "settings.provider.geminiCli": "Google Gemini 모델", "settings.system.title": "시스템", "settings.system.autoUpdate": "자동 업데이트", "settings.system.upToDate": "최신 상태", @@ -356,7 +351,6 @@ FR = { "settings.provider.codexCli": "Modèles OpenAI", "settings.provider.openCode": "Plus de 75 fournisseurs de LLM", "settings.provider.githubCopilot": "Modèles GitHub Copilot", - "settings.provider.geminiCli": "Modèles Google Gemini", "settings.system.title": "Système", "settings.system.autoUpdate": "Mise à jour automatique", "settings.system.upToDate": "À jour", @@ -411,7 +405,6 @@ ES = { "settings.provider.codexCli": "Modelos OpenAI", "settings.provider.openCode": "Más de 75 proveedores de LLM", "settings.provider.githubCopilot": "Modelos GitHub Copilot", - "settings.provider.geminiCli": "Modelos Google Gemini", "settings.system.title": "Sistema", "settings.system.autoUpdate": "Actualización automática", "settings.system.upToDate": "Actualizado", @@ -466,7 +459,6 @@ DE = { "settings.provider.codexCli": "OpenAI-Modelle", "settings.provider.openCode": "Über 75 LLM-Anbieter", "settings.provider.githubCopilot": "GitHub-Copilot-Modelle", - "settings.provider.geminiCli": "Google-Gemini-Modelle", "settings.system.title": "System", "settings.system.autoUpdate": "Automatische Updates", "settings.system.upToDate": "Aktuell", @@ -521,7 +513,6 @@ PT = { "settings.provider.codexCli": "Modelos OpenAI", "settings.provider.openCode": "Mais de 75 provedores de LLM", "settings.provider.githubCopilot": "Modelos GitHub Copilot", - "settings.provider.geminiCli": "Modelos Google Gemini", "settings.system.title": "Sistema", "settings.system.autoUpdate": "Atualização automática", "settings.system.upToDate": "Atualizado", @@ -576,7 +567,6 @@ RU = { "settings.provider.codexCli": "Модели OpenAI", "settings.provider.openCode": "Более 75 провайдеров LLM", "settings.provider.githubCopilot": "Модели GitHub Copilot", - "settings.provider.geminiCli": "Модели Google Gemini", "settings.system.title": "Система", "settings.system.autoUpdate": "Автообновление", "settings.system.upToDate": "Актуально", @@ -631,7 +621,6 @@ HI = { "settings.provider.codexCli": "OpenAI मॉडल", "settings.provider.openCode": "75+ LLM प्रदाता", "settings.provider.githubCopilot": "GitHub Copilot मॉडल", - "settings.provider.geminiCli": "Google Gemini मॉडल", "settings.system.title": "सिस्टम", "settings.system.autoUpdate": "स्वतः अपडेट", "settings.system.upToDate": "नवीनतम", @@ -686,7 +675,6 @@ TR = { "settings.provider.codexCli": "OpenAI modelleri", "settings.provider.openCode": "75'ten fazla LLM sağlayıcısı", "settings.provider.githubCopilot": "GitHub Copilot modelleri", - "settings.provider.geminiCli": "Google Gemini modelleri", "settings.system.title": "Sistem", "settings.system.autoUpdate": "Otomatik güncelleme", "settings.system.upToDate": "Güncel", @@ -740,7 +728,6 @@ TH = { "settings.provider.codexCli": "โมเดล OpenAI", "settings.provider.openCode": "ผู้ให้บริการ LLM มากกว่า 75 ราย", "settings.provider.githubCopilot": "โมเดล GitHub Copilot", - "settings.provider.geminiCli": "โมเดล Google Gemini", "settings.system.title": "ระบบ", "settings.system.autoUpdate": "อัปเดตอัตโนมัติ", "settings.system.upToDate": "เป็นเวอร์ชันล่าสุด", @@ -795,7 +782,6 @@ VI = { "settings.provider.codexCli": "Mô hình OpenAI", "settings.provider.openCode": "Hơn 75 nhà cung cấp LLM", "settings.provider.githubCopilot": "Mô hình GitHub Copilot", - "settings.provider.geminiCli": "Mô hình Google Gemini", "settings.system.title": "Hệ thống", "settings.system.autoUpdate": "Tự động cập nhật", "settings.system.upToDate": "Đã cập nhật", @@ -850,7 +836,6 @@ ID = { "settings.provider.codexCli": "Model OpenAI", "settings.provider.openCode": "75+ penyedia LLM", "settings.provider.githubCopilot": "Model GitHub Copilot", - "settings.provider.geminiCli": "Model Google Gemini", "settings.system.title": "Sistem", "settings.system.autoUpdate": "Pembaruan otomatis", "settings.system.upToDate": "Terbaru",