From 9052dcb97c325a34042fe333c4c337cd552f8176 Mon Sep 17 00:00:00 2001 From: Rafael-Silva-Oliveira Date: Tue, 11 Aug 2026 00:46:49 +0200 Subject: [PATCH] feat(scm): generate commit messages from the Source Control panel Adds a Zoo Code button to the Source Control title bar that summarizes the current changes into a commit message and writes it into the commit input box. - Collects staged changes first, falling back to the whole working tree when nothing is staged so the button still works before staging. `git status --short` is used on the fallback path so untracked files stay visible. - Registers COMMIT_MESSAGE as a support prompt, so the default Conventional Commits template is editable from Settings > Prompts with a reset button, reusing the existing customSupportPrompts plumbing. - Adds a `commitMessageApiConfigId` setting in Settings > Providers to pick a small, fast profile for this one task, mirroring `enhancementApiConfigId`. Falls back to the active profile when unset or when the saved profile has since been deleted. `packages/build` had to widen `commandsSchema.icon` to accept a themed {light, dark} pair; it previously allowed only a codicon string, which would have failed the nightly manifest build. Co-Authored-By: Claude Opus 5 --- packages/build/src/types.ts | 3 +- packages/types/src/global-settings.ts | 1 + packages/types/src/vscode-extension-host.ts | 1 + packages/types/src/vscode.ts | 2 + src/activate/registerCommands.ts | 4 + src/core/webview/ClineProvider.ts | 3 + src/i18n/locales/ca/common.json | 4 + src/i18n/locales/de/common.json | 4 + src/i18n/locales/en/common.json | 4 + src/i18n/locales/es/common.json | 4 + src/i18n/locales/fr/common.json | 4 + src/i18n/locales/hi/common.json | 4 + src/i18n/locales/id/common.json | 4 + src/i18n/locales/it/common.json | 4 + src/i18n/locales/ja/common.json | 4 + src/i18n/locales/ko/common.json | 4 + src/i18n/locales/nl/common.json | 4 + src/i18n/locales/pl/common.json | 4 + src/i18n/locales/pt-BR/common.json | 4 + src/i18n/locales/ru/common.json | 4 + src/i18n/locales/tr/common.json | 4 + src/i18n/locales/vi/common.json | 4 + src/i18n/locales/zh-CN/common.json | 4 + src/i18n/locales/zh-TW/common.json | 4 + src/package.json | 16 ++ src/package.nls.ca.json | 1 + src/package.nls.de.json | 1 + src/package.nls.es.json | 1 + src/package.nls.fr.json | 1 + src/package.nls.hi.json | 1 + src/package.nls.id.json | 1 + src/package.nls.it.json | 1 + src/package.nls.ja.json | 1 + src/package.nls.json | 1 + src/package.nls.ko.json | 1 + src/package.nls.nl.json | 1 + src/package.nls.pl.json | 1 + src/package.nls.pt-BR.json | 1 + src/package.nls.ru.json | 1 + src/package.nls.tr.json | 1 + src/package.nls.vi.json | 1 + src/package.nls.zh-CN.json | 1 + src/package.nls.zh-TW.json | 1 + .../__tests__/generateCommitMessage.spec.ts | 167 ++++++++++++++++++ src/services/commit-message/index.ts | 137 ++++++++++++++ src/shared/support-prompt.ts | 14 ++ src/utils/__tests__/git.spec.ts | 116 ++++++++++++ src/utils/git.ts | 54 ++++++ .../settings/CommitMessageModelSelect.tsx | 60 +++++++ .../src/components/settings/SettingsView.tsx | 8 + .../CommitMessageModelSelect.spec.tsx | 92 ++++++++++ .../settings/__tests__/SettingsView.spec.tsx | 24 +++ webview-ui/src/i18n/locales/ca/prompts.json | 4 + webview-ui/src/i18n/locales/ca/settings.json | 5 + webview-ui/src/i18n/locales/de/prompts.json | 4 + webview-ui/src/i18n/locales/de/settings.json | 5 + webview-ui/src/i18n/locales/en/prompts.json | 4 + webview-ui/src/i18n/locales/en/settings.json | 5 + webview-ui/src/i18n/locales/es/prompts.json | 4 + webview-ui/src/i18n/locales/es/settings.json | 5 + webview-ui/src/i18n/locales/fr/prompts.json | 4 + webview-ui/src/i18n/locales/fr/settings.json | 5 + webview-ui/src/i18n/locales/hi/prompts.json | 4 + webview-ui/src/i18n/locales/hi/settings.json | 5 + webview-ui/src/i18n/locales/id/prompts.json | 4 + webview-ui/src/i18n/locales/id/settings.json | 5 + webview-ui/src/i18n/locales/it/prompts.json | 4 + webview-ui/src/i18n/locales/it/settings.json | 5 + webview-ui/src/i18n/locales/ja/prompts.json | 4 + webview-ui/src/i18n/locales/ja/settings.json | 5 + webview-ui/src/i18n/locales/ko/prompts.json | 4 + webview-ui/src/i18n/locales/ko/settings.json | 5 + webview-ui/src/i18n/locales/nl/prompts.json | 4 + webview-ui/src/i18n/locales/nl/settings.json | 5 + webview-ui/src/i18n/locales/pl/prompts.json | 4 + webview-ui/src/i18n/locales/pl/settings.json | 5 + .../src/i18n/locales/pt-BR/prompts.json | 4 + .../src/i18n/locales/pt-BR/settings.json | 5 + webview-ui/src/i18n/locales/ru/prompts.json | 4 + webview-ui/src/i18n/locales/ru/settings.json | 5 + webview-ui/src/i18n/locales/tr/prompts.json | 4 + webview-ui/src/i18n/locales/tr/settings.json | 5 + webview-ui/src/i18n/locales/vi/prompts.json | 4 + webview-ui/src/i18n/locales/vi/settings.json | 5 + .../src/i18n/locales/zh-CN/prompts.json | 4 + .../src/i18n/locales/zh-CN/settings.json | 5 + .../src/i18n/locales/zh-TW/prompts.json | 4 + .../src/i18n/locales/zh-TW/settings.json | 5 + 88 files changed, 953 insertions(+), 1 deletion(-) create mode 100644 src/services/commit-message/__tests__/generateCommitMessage.spec.ts create mode 100644 src/services/commit-message/index.ts create mode 100644 webview-ui/src/components/settings/CommitMessageModelSelect.tsx create mode 100644 webview-ui/src/components/settings/__tests__/CommitMessageModelSelect.spec.tsx diff --git a/packages/build/src/types.ts b/packages/build/src/types.ts index 18db4f2e7c..86acd40452 100644 --- a/packages/build/src/types.ts +++ b/packages/build/src/types.ts @@ -31,7 +31,8 @@ const commandsSchema = z.array( command: z.string(), title: z.string(), category: z.string().optional(), - icon: z.string().optional(), + // Either a codicon reference (e.g. `$(edit)`) or a pair of theme-specific image paths. + icon: z.union([z.string(), z.object({ light: z.string(), dark: z.string() })]).optional(), }), ) diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index dc3ea072fd..3190d79ff6 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -235,6 +235,7 @@ export const globalSettingsSchema = z.object({ customSupportPrompts: customSupportPromptsSchema.optional(), enhancementApiConfigId: z.string().optional(), includeTaskHistoryInEnhance: z.boolean().optional(), + commitMessageApiConfigId: z.string().optional(), historyPreviewCollapsed: z.boolean().optional(), reasoningBlockCollapsed: z.boolean().optional(), /** diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 63d5be87a8..3f923ad5f2 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -304,6 +304,7 @@ export type ExtensionState = Pick< | "customModePrompts" | "customSupportPrompts" | "enhancementApiConfigId" + | "commitMessageApiConfigId" | "customCondensingPrompt" | "codebaseIndexConfig" | "codebaseIndexModels" diff --git a/packages/types/src/vscode.ts b/packages/types/src/vscode.ts index fd4e31116d..d928b0a873 100644 --- a/packages/types/src/vscode.ts +++ b/packages/types/src/vscode.ts @@ -47,6 +47,8 @@ export const commandIds = [ "focusPanel", "toggleAutoApprove", + "generateCommitMessage", + "showRipgrepDiagnostic", ] as const diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index 692aabfd68..56bdc2902c 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -14,6 +14,7 @@ import { CodeIndexManager } from "../services/code-index/manager" import { importSettingsWithFeedback } from "../core/config/importExport" import { MdmService } from "../services/mdm/MdmService" import { registerRipgrepDiagnosticCommand } from "../services/ripgrep/diagnostic" +import { generateCommitMessage } from "../services/commit-message" import { t } from "../i18n" /** @@ -219,6 +220,9 @@ const getCommandsMap = ({ outputChannel.appendLine(`[toggleAutoApprove] postMessageToWebview failed: ${error}`) } }, + // Uses `provider` rather than the visible instance so the Source Control button still works + // while the Zoo Code sidebar is closed. + generateCommitMessage: (sourceControl?: vscode.SourceControl) => generateCommitMessage(provider, sourceControl), }) export const openClineInNewTab = async ({ context, outputChannel }: Omit) => { diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 2263257cd6..bb8ce3eb75 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2461,6 +2461,7 @@ export class ClineProvider customModePrompts, customSupportPrompts, enhancementApiConfigId, + commitMessageApiConfigId, autoApprovalEnabled, customModes, experiments, @@ -2619,6 +2620,7 @@ export class ClineProvider customModePrompts: customModePrompts ?? {}, customSupportPrompts: customSupportPrompts ?? {}, enhancementApiConfigId, + commitMessageApiConfigId, autoApprovalEnabled: autoApprovalEnabled ?? false, customModes, experiments: experiments ?? experimentDefault, @@ -2852,6 +2854,7 @@ export class ClineProvider customModePrompts: stateValues.customModePrompts ?? {}, customSupportPrompts: stateValues.customSupportPrompts ?? {}, enhancementApiConfigId: stateValues.enhancementApiConfigId, + commitMessageApiConfigId: stateValues.commitMessageApiConfigId, experiments: stateValues.experiments ?? experimentDefault, autoApprovalEnabled: stateValues.autoApprovalEnabled ?? false, customModes, diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 24ae3f310c..0eb977f0b0 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -44,6 +44,8 @@ "update_support_prompt": "Ha fallat l'actualització del missatge de suport", "reset_support_prompt": "Ha fallat el restabliment del missatge de suport", "enhance_prompt": "Ha fallat la millora del missatge", + "commit_message_no_repository": "No s'ha trobat cap repositori Git al plafó de control de codi font.", + "commit_message_failed": "No s'ha pogut generar el missatge de comissió: {{error}}", "get_system_prompt": "Ha fallat l'obtenció del missatge del sistema", "search_commits": "Ha fallat la cerca de commits", "save_api_config": "Ha fallat el desament de la configuració de l'API", @@ -164,6 +166,8 @@ }, "info": { "no_changes": "No s'han trobat canvis.", + "commit_message_generating": "Generant el missatge de comissió...", + "commit_message_no_changes": "No hi ha canvis per confirmar.", "clipboard_copy": "Missatge del sistema copiat correctament al portapapers", "history_cleanup": "S'han netejat {{count}} tasques amb fitxers que falten de l'historial.", "custom_storage_path_set": "Ruta d'emmagatzematge personalitzada establerta: {{path}}", diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index 54fa0b3c22..ec820a4c86 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Fehler beim Aktualisieren der Support-Nachricht", "reset_support_prompt": "Fehler beim Zurücksetzen der Support-Nachricht", "enhance_prompt": "Fehler beim Verbessern der Nachricht", + "commit_message_no_repository": "Kein Git-Repository in der Quellcodeverwaltung gefunden.", + "commit_message_failed": "Commit-Nachricht konnte nicht generiert werden: {{error}}", "get_system_prompt": "Fehler beim Abrufen der Systemnachricht", "search_commits": "Fehler beim Suchen von Commits", "save_api_config": "Fehler beim Speichern der API-Konfiguration", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Keine Änderungen gefunden.", + "commit_message_generating": "Commit-Nachricht wird generiert...", + "commit_message_no_changes": "Keine Änderungen zum Committen.", "clipboard_copy": "Systemnachricht erfolgreich in die Zwischenablage kopiert", "history_cleanup": "{{count}} Aufgabe(n) mit fehlenden Dateien aus dem Verlauf bereinigt.", "custom_storage_path_set": "Benutzerdefinierter Speicherpfad festgelegt: {{path}}", diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 516a3d4f88..05ad4031c3 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Failed to update support prompt", "reset_support_prompt": "Failed to reset support prompt", "enhance_prompt": "Failed to enhance prompt", + "commit_message_no_repository": "No Git repository found in the Source Control panel.", + "commit_message_failed": "Failed to generate commit message: {{error}}", "get_system_prompt": "Failed to get system prompt", "search_commits": "Failed to search commits", "save_api_config": "Failed to save api configuration", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "No changes found.", + "commit_message_generating": "Generating commit message...", + "commit_message_no_changes": "No changes to commit.", "clipboard_copy": "System prompt successfully copied to clipboard", "history_cleanup": "Cleaned up {{count}} task(s) with missing files from history.", "custom_storage_path_set": "Custom storage path set: {{path}}", diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 71dc994516..c43749bba0 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Error al actualizar el mensaje de soporte", "reset_support_prompt": "Error al restablecer el mensaje de soporte", "enhance_prompt": "Error al mejorar el mensaje", + "commit_message_no_repository": "No se encontró ningún repositorio Git en el panel de control de código fuente.", + "commit_message_failed": "No se pudo generar el mensaje de confirmación: {{error}}", "get_system_prompt": "Error al obtener el mensaje del sistema", "search_commits": "Error al buscar commits", "save_api_config": "Error al guardar la configuración de API", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "No se encontraron cambios.", + "commit_message_generating": "Generando mensaje de confirmación...", + "commit_message_no_changes": "No hay cambios para confirmar.", "clipboard_copy": "Mensaje del sistema copiado correctamente al portapapeles", "history_cleanup": "Se limpiaron {{count}} tarea(s) con archivos faltantes del historial.", "custom_storage_path_set": "Ruta de almacenamiento personalizada establecida: {{path}}", diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 87009ee988..0ee42a43e7 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Erreur lors de la mise à jour du prompt de support", "reset_support_prompt": "Erreur lors de la réinitialisation du prompt de support", "enhance_prompt": "Erreur lors de l'amélioration du prompt", + "commit_message_no_repository": "Aucun dépôt Git trouvé dans le panneau de contrôle de code source.", + "commit_message_failed": "Échec de la génération du message de commit : {{error}}", "get_system_prompt": "Erreur lors de l'obtention du prompt système", "search_commits": "Erreur lors de la recherche des commits", "save_api_config": "Erreur lors de l'enregistrement de la configuration API", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Aucun changement trouvé.", + "commit_message_generating": "Génération du message de commit...", + "commit_message_no_changes": "Aucune modification à valider.", "clipboard_copy": "Prompt système copié dans le presse-papiers", "history_cleanup": "{{count}} tâche(s) avec des fichiers introuvables ont été supprimés de l'historique.", "custom_storage_path_set": "Chemin de stockage personnalisé défini : {{path}}", diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index f4bd1c3055..58350f6bd6 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "सपोर्ट प्रॉम्प्ट अपडेट करने में विफल", "reset_support_prompt": "सपोर्ट प्रॉम्प्ट रीसेट करने में विफल", "enhance_prompt": "प्रॉम्प्ट को बेहतर बनाने में विफल", + "commit_message_no_repository": "स्रोत नियंत्रण पैनल में कोई Git रिपॉजिटरी नहीं मिली।", + "commit_message_failed": "कमिट संदेश जनरेट करने में विफल: {{error}}", "get_system_prompt": "सिस्टम प्रॉम्प्ट प्राप्त करने में विफल", "search_commits": "कमिट्स खोजने में विफल", "save_api_config": "API कॉन्फ़िगरेशन सहेजने में विफल", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "कोई परिवर्तन नहीं मिला।", + "commit_message_generating": "कमिट संदेश जनरेट किया जा रहा है...", + "commit_message_no_changes": "कमिट करने के लिए कोई परिवर्तन नहीं है।", "clipboard_copy": "सिस्टम प्रॉम्प्ट क्लिपबोर्ड पर सफलतापूर्वक कॉपी किया गया", "history_cleanup": "इतिहास से गायब फाइलों वाले {{count}} टास्क साफ किए गए।", "custom_storage_path_set": "कस्टम स्टोरेज पाथ सेट किया गया: {{path}}", diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index bcee321af5..e2f3149416 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Gagal memperbarui support prompt", "reset_support_prompt": "Gagal mereset support prompt", "enhance_prompt": "Gagal meningkatkan prompt", + "commit_message_no_repository": "Tidak ada repositori Git yang ditemukan di panel Source Control.", + "commit_message_failed": "Gagal menghasilkan pesan commit: {{error}}", "get_system_prompt": "Gagal mendapatkan system prompt", "search_commits": "Gagal mencari commit", "save_api_config": "Gagal menyimpan konfigurasi api", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Tidak ada perubahan ditemukan.", + "commit_message_generating": "Menghasilkan pesan commit...", + "commit_message_no_changes": "Tidak ada perubahan untuk di-commit.", "clipboard_copy": "System prompt berhasil disalin ke clipboard", "history_cleanup": "Membersihkan {{count}} tugas dengan file yang hilang dari riwayat.", "custom_storage_path_set": "Path penyimpanan kustom diatur: {{path}}", diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 395be16b84..41649e749b 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Errore durante l'aggiornamento del messaggio di supporto", "reset_support_prompt": "Errore durante il ripristino del messaggio di supporto", "enhance_prompt": "Errore durante il miglioramento del messaggio", + "commit_message_no_repository": "Nessun repository Git trovato nel pannello Controllo del codice sorgente.", + "commit_message_failed": "Impossibile generare il messaggio di commit: {{error}}", "get_system_prompt": "Errore durante l'ottenimento del messaggio di sistema", "search_commits": "Errore durante la ricerca dei commit", "save_api_config": "Errore durante il salvataggio della configurazione API", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Nessuna modifica trovata.", + "commit_message_generating": "Generazione del messaggio di commit...", + "commit_message_no_changes": "Nessuna modifica da confermare.", "clipboard_copy": "Messaggio di sistema copiato con successo negli appunti", "history_cleanup": "Pulite {{count}} attività con file mancanti dalla cronologia.", "custom_storage_path_set": "Percorso di archiviazione personalizzato impostato: {{path}}", diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 7dccfcd837..3f0809e27b 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "サポートメッセージの更新に失敗しました", "reset_support_prompt": "サポートメッセージのリセットに失敗しました", "enhance_prompt": "メッセージの強化に失敗しました", + "commit_message_no_repository": "ソース管理パネルに Git リポジトリが見つかりません。", + "commit_message_failed": "コミットメッセージの生成に失敗しました: {{error}}", "get_system_prompt": "システムメッセージの取得に失敗しました", "search_commits": "コミットの検索に失敗しました", "save_api_config": "API設定の保存に失敗しました", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "変更は見つかりませんでした。", + "commit_message_generating": "コミットメッセージを生成しています...", + "commit_message_no_changes": "コミットする変更がありません。", "clipboard_copy": "システムメッセージがクリップボードに正常にコピーされました", "history_cleanup": "履歴から不足ファイルのある{{count}}個のタスクをクリーンアップしました。", "custom_storage_path_set": "カスタムストレージパスが設定されました:{{path}}", diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index 0ca65be687..d2edfa8967 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "지원 프롬프트 업데이트에 실패했습니다", "reset_support_prompt": "지원 프롬프트 재설정에 실패했습니다", "enhance_prompt": "프롬프트 향상에 실패했습니다", + "commit_message_no_repository": "소스 제어 패널에서 Git 저장소를 찾을 수 없습니다.", + "commit_message_failed": "커밋 메시지 생성에 실패했습니다: {{error}}", "get_system_prompt": "시스템 프롬프트 가져오기에 실패했습니다", "search_commits": "커밋 검색에 실패했습니다", "save_api_config": "API 구성 저장에 실패했습니다", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "변경 사항이 없습니다.", + "commit_message_generating": "커밋 메시지를 생성하는 중...", + "commit_message_no_changes": "커밋할 변경 사항이 없습니다.", "clipboard_copy": "시스템 프롬프트가 클립보드에 성공적으로 복사되었습니다", "history_cleanup": "이력에서 파일이 누락된 {{count}}개의 작업을 정리했습니다.", "custom_storage_path_set": "사용자 지정 저장 경로 설정됨: {{path}}", diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index a38415edfd..c74c1a3619 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Bijwerken van ondersteuningsprompt mislukt", "reset_support_prompt": "Resetten van ondersteuningsprompt mislukt", "enhance_prompt": "Verbeteren van prompt mislukt", + "commit_message_no_repository": "Geen Git-repository gevonden in het paneel Broncodebeheer.", + "commit_message_failed": "Genereren van het commitbericht is mislukt: {{error}}", "get_system_prompt": "Ophalen van systeemprompt mislukt", "search_commits": "Zoeken naar commits mislukt", "save_api_config": "Opslaan van API-configuratie mislukt", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Geen wijzigingen gevonden.", + "commit_message_generating": "Commitbericht genereren...", + "commit_message_no_changes": "Geen wijzigingen om vast te leggen.", "clipboard_copy": "Systeemprompt succesvol gekopieerd naar klembord", "history_cleanup": "{{count}} taak/taken met ontbrekende bestanden uit geschiedenis verwijderd.", "custom_storage_path_set": "Aangepast opslagpad ingesteld: {{path}}", diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index ff898e8987..a8b8bb4116 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Nie udało się zaktualizować komunikatu wsparcia", "reset_support_prompt": "Nie udało się zresetować komunikatu wsparcia", "enhance_prompt": "Nie udało się ulepszyć komunikatu", + "commit_message_no_repository": "Nie znaleziono repozytorium Git w panelu kontroli źródła.", + "commit_message_failed": "Nie udało się wygenerować komunikatu zatwierdzenia: {{error}}", "get_system_prompt": "Nie udało się pobrać komunikatu systemowego", "search_commits": "Nie udało się wyszukać commitów", "save_api_config": "Nie udało się zapisać konfiguracji API", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Nie znaleziono zmian.", + "commit_message_generating": "Generowanie komunikatu zatwierdzenia...", + "commit_message_no_changes": "Brak zmian do zatwierdzenia.", "clipboard_copy": "Komunikat systemowy został pomyślnie skopiowany do schowka", "history_cleanup": "Wyczyszczono {{count}} zadań z brakującymi plikami z historii.", "custom_storage_path_set": "Ustawiono niestandardową ścieżkę przechowywania: {{path}}", diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index d3c31ed2dd..0b065f23a9 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -44,6 +44,8 @@ "update_support_prompt": "Falha ao atualizar o prompt de suporte", "reset_support_prompt": "Falha ao redefinir o prompt de suporte", "enhance_prompt": "Falha ao aprimorar o prompt", + "commit_message_no_repository": "Nenhum repositório Git encontrado no painel de Controle do Código-Fonte.", + "commit_message_failed": "Falha ao gerar a mensagem de commit: {{error}}", "get_system_prompt": "Falha ao obter o prompt do sistema", "search_commits": "Falha ao pesquisar commits", "save_api_config": "Falha ao salvar a configuração da API", @@ -164,6 +166,8 @@ }, "info": { "no_changes": "Nenhuma alteração encontrada.", + "commit_message_generating": "Gerando mensagem de commit...", + "commit_message_no_changes": "Nenhuma alteração para confirmar.", "clipboard_copy": "Prompt do sistema copiado com sucesso para a área de transferência", "history_cleanup": "{{count}} tarefa(s) com arquivos ausentes foram limpas do histórico.", "custom_storage_path_set": "Caminho de armazenamento personalizado definido: {{path}}", diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 08d2e2aa2c..9e711c0442 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Не удалось обновить промпт поддержки", "reset_support_prompt": "Не удалось сбросить промпт поддержки", "enhance_prompt": "Не удалось улучшить промпт", + "commit_message_no_repository": "Репозиторий Git не найден на панели системы управления версиями.", + "commit_message_failed": "Не удалось сгенерировать сообщение коммита: {{error}}", "get_system_prompt": "Не удалось получить системный промпт", "search_commits": "Не удалось выполнить поиск коммитов", "save_api_config": "Не удалось сохранить конфигурацию API", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Изменения не найдены.", + "commit_message_generating": "Генерация сообщения коммита...", + "commit_message_no_changes": "Нет изменений для коммита.", "clipboard_copy": "Системный промпт успешно скопирован в буфер обмена", "history_cleanup": "Очищено {{count}} задач(и) с отсутствующими файлами из истории.", "custom_storage_path_set": "Установлен пользовательский путь хранения: {{path}}", diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 716ccbc6de..242cf19465 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Destek istemi güncellenemedi", "reset_support_prompt": "Destek istemi sıfırlanamadı", "enhance_prompt": "İstem geliştirilemedi", + "commit_message_no_repository": "Kaynak Denetimi panelinde Git deposu bulunamadı.", + "commit_message_failed": "Commit mesajı oluşturulamadı: {{error}}", "get_system_prompt": "Sistem istemi alınamadı", "search_commits": "Taahhütler aranamadı", "save_api_config": "API yapılandırması kaydedilemedi", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Değişiklik bulunamadı.", + "commit_message_generating": "Commit mesajı oluşturuluyor...", + "commit_message_no_changes": "Commit edilecek değişiklik yok.", "clipboard_copy": "Sistem istemi panoya başarıyla kopyalandı", "history_cleanup": "Geçmişten eksik dosyaları olan {{count}} görev temizlendi.", "custom_storage_path_set": "Özel depolama yolu ayarlandı: {{path}}", diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 69c6343c31..89c7864312 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "Không thể cập nhật lời nhắc hỗ trợ", "reset_support_prompt": "Không thể đặt lại lời nhắc hỗ trợ", "enhance_prompt": "Không thể nâng cao lời nhắc", + "commit_message_no_repository": "Không tìm thấy kho Git nào trong bảng Source Control.", + "commit_message_failed": "Không thể tạo thông điệp commit: {{error}}", "get_system_prompt": "Không thể lấy lời nhắc hệ thống", "search_commits": "Không thể tìm kiếm các commit", "save_api_config": "Không thể lưu cấu hình API", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "Không tìm thấy thay đổi nào.", + "commit_message_generating": "Đang tạo thông điệp commit...", + "commit_message_no_changes": "Không có thay đổi nào để commit.", "clipboard_copy": "Lời nhắc hệ thống đã được sao chép thành công vào clipboard", "history_cleanup": "Đã dọn dẹp {{count}} nhiệm vụ có tệp bị thiếu khỏi lịch sử.", "custom_storage_path_set": "Đã thiết lập đường dẫn lưu trữ tùy chỉnh: {{path}}", diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 3600f0aa7c..5eafad2278 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -45,6 +45,8 @@ "update_support_prompt": "更新支持消息失败", "reset_support_prompt": "重置支持消息失败", "enhance_prompt": "增强消息失败", + "commit_message_no_repository": "在源代码管理面板中未找到 Git 仓库。", + "commit_message_failed": "生成提交信息失败:{{error}}", "get_system_prompt": "获取系统消息失败", "search_commits": "搜索提交失败", "save_api_config": "保存API配置失败", @@ -165,6 +167,8 @@ }, "info": { "no_changes": "未找到更改。", + "commit_message_generating": "正在生成提交信息...", + "commit_message_no_changes": "没有可提交的更改。", "clipboard_copy": "系统消息已成功复制到剪贴板", "history_cleanup": "已从历史记录中清理{{count}}个缺少文件的任务。", "custom_storage_path_set": "自定义存储路径已设置:{{path}}", diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index c635769891..9a17407147 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -40,6 +40,8 @@ "update_support_prompt": "更新支援訊息失敗", "reset_support_prompt": "重設支援訊息失敗", "enhance_prompt": "增強訊息失敗", + "commit_message_no_repository": "在原始檔控制面板中找不到 Git 存放庫。", + "commit_message_failed": "產生提交訊息失敗:{{error}}", "get_system_prompt": "取得系統訊息失敗", "search_commits": "搜尋提交失敗", "save_api_config": "儲存 API 設定失敗", @@ -160,6 +162,8 @@ }, "info": { "no_changes": "沒有找到更改。", + "commit_message_generating": "正在產生提交訊息...", + "commit_message_no_changes": "沒有可提交的變更。", "clipboard_copy": "系統訊息已成功複製到剪貼簿", "history_cleanup": "已從歷史記錄中清理{{count}}個缺少檔案的工作。", "custom_storage_path_set": "自訂儲存路徑已設定:{{path}}", diff --git a/src/package.json b/src/package.json index 9be6390cbc..0f25f06277 100644 --- a/src/package.json +++ b/src/package.json @@ -169,6 +169,15 @@ "command": "zoo-code.toggleAutoApprove", "title": "%command.toggleAutoApprove.title%", "category": "%configuration.title%" + }, + { + "command": "zoo-code.generateCommitMessage", + "title": "%command.generateCommitMessage.title%", + "category": "%configuration.title%", + "icon": { + "light": "assets/icons/panel_light.png", + "dark": "assets/icons/panel_dark.png" + } } ], "menus": { @@ -265,6 +274,13 @@ "group": "overflow@2", "when": "activeWebviewPanelId == zoo-code.TabPanelProvider" } + ], + "scm/title": [ + { + "command": "zoo-code.generateCommitMessage", + "group": "navigation", + "when": "scmProvider == git" + } ] }, "keybindings": [ diff --git a/src/package.nls.ca.json b/src/package.nls.ca.json index 6ddaf181b4..674d6736f6 100644 --- a/src/package.nls.ca.json +++ b/src/package.nls.ca.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Acceptar Entrada/Suggeriment", "command.showRipgrepDiagnostic.title": "Mostra el diagnòstic de Ripgrep", "command.toggleAutoApprove.title": "Alternar Auto-Aprovació", + "command.generateCommitMessage.title": "Genera missatge de comissió", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.de.json b/src/package.nls.de.json index 4c8eccb293..54282d9faa 100644 --- a/src/package.nls.de.json +++ b/src/package.nls.de.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Eingabe/Vorschlag Akzeptieren", "command.showRipgrepDiagnostic.title": "Ripgrep-Diagnose anzeigen", "command.toggleAutoApprove.title": "Auto-Genehmigung Umschalten", + "command.generateCommitMessage.title": "Commit-Nachricht generieren", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.es.json b/src/package.nls.es.json index 11a705880b..c39b19d02b 100644 --- a/src/package.nls.es.json +++ b/src/package.nls.es.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Aceptar Entrada/Sugerencia", "command.showRipgrepDiagnostic.title": "Mostrar diagnóstico de Ripgrep", "command.toggleAutoApprove.title": "Alternar Auto-Aprobación", + "command.generateCommitMessage.title": "Generar mensaje de confirmación", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.fr.json b/src/package.nls.fr.json index 573350bc9a..577494f4aa 100644 --- a/src/package.nls.fr.json +++ b/src/package.nls.fr.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Accepter l'Entrée/Suggestion", "command.showRipgrepDiagnostic.title": "Afficher le diagnostic Ripgrep", "command.toggleAutoApprove.title": "Basculer Auto-Approbation", + "command.generateCommitMessage.title": "Générer un message de commit", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.hi.json b/src/package.nls.hi.json index 8135af2ab3..ccb7ba34ad 100644 --- a/src/package.nls.hi.json +++ b/src/package.nls.hi.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "इनपुट/सुझाव स्वीकारें", "command.showRipgrepDiagnostic.title": "Ripgrep डायग्नोस्टिक दिखाएं", "command.toggleAutoApprove.title": "ऑटो-अनुमोदन टॉगल करें", + "command.generateCommitMessage.title": "कमिट संदेश जनरेट करें", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.id.json b/src/package.nls.id.json index c5740ad00b..824ec67c8a 100644 --- a/src/package.nls.id.json +++ b/src/package.nls.id.json @@ -25,6 +25,7 @@ "command.acceptInput.title": "Terima Input/Saran", "command.showRipgrepDiagnostic.title": "Tampilkan Diagnostik Ripgrep", "command.toggleAutoApprove.title": "Alihkan Persetujuan Otomatis", + "command.generateCommitMessage.title": "Hasilkan Pesan Commit", "configuration.title": "Zoo Code", "commands.allowedCommands.description": "Perintah yang dapat dijalankan secara otomatis ketika 'Selalu setujui operasi eksekusi' diaktifkan", "commands.deniedCommands.description": "Awalan perintah yang akan otomatis ditolak tanpa meminta persetujuan. Jika terjadi konflik dengan perintah yang diizinkan, pencocokan awalan terpanjang akan diprioritaskan. Tambahkan * untuk menolak semua perintah.", diff --git a/src/package.nls.it.json b/src/package.nls.it.json index ebf2167a99..c2895f28f5 100644 --- a/src/package.nls.it.json +++ b/src/package.nls.it.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Accetta Input/Suggerimento", "command.showRipgrepDiagnostic.title": "Mostra diagnostica Ripgrep", "command.toggleAutoApprove.title": "Attiva/Disattiva Auto-Approvazione", + "command.generateCommitMessage.title": "Genera messaggio di commit", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.ja.json b/src/package.nls.ja.json index f9daa4bb93..36cd71f585 100644 --- a/src/package.nls.ja.json +++ b/src/package.nls.ja.json @@ -25,6 +25,7 @@ "command.acceptInput.title": "入力/提案を承認", "command.showRipgrepDiagnostic.title": "Ripgrep 診断を表示", "command.toggleAutoApprove.title": "自動承認を切替", + "command.generateCommitMessage.title": "コミットメッセージを生成", "configuration.title": "Zoo Code", "commands.allowedCommands.description": "'常に実行操作を承認する'が有効な場合に自動実行できるコマンド", "commands.deniedCommands.description": "承認を求めずに自動的に拒否されるコマンドプレフィックス。許可されたコマンドとの競合がある場合、最長プレフィックスマッチが優先されます。すべてのコマンドを拒否するには * を追加してください。", diff --git a/src/package.nls.json b/src/package.nls.json index 4fac644eab..79fe7b06bf 100644 --- a/src/package.nls.json +++ b/src/package.nls.json @@ -25,6 +25,7 @@ "command.acceptInput.title": "Accept Input/Suggestion", "command.showRipgrepDiagnostic.title": "Show Ripgrep Diagnostic", "command.toggleAutoApprove.title": "Toggle Auto-Approve", + "command.generateCommitMessage.title": "Generate Commit Message", "configuration.title": "Zoo Code", "commands.allowedCommands.description": "Commands that can be auto-executed when 'Always approve execute operations' is enabled", "commands.deniedCommands.description": "Command prefixes that will be automatically denied without asking for approval. In case of conflicts with allowed commands, the longest prefix match takes precedence. Add * to deny all commands.", diff --git a/src/package.nls.ko.json b/src/package.nls.ko.json index a743902280..a661b87faf 100644 --- a/src/package.nls.ko.json +++ b/src/package.nls.ko.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "입력/제안 수락", "command.showRipgrepDiagnostic.title": "Ripgrep 진단 표시", "command.toggleAutoApprove.title": "자동 승인 전환", + "command.generateCommitMessage.title": "커밋 메시지 생성", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.nl.json b/src/package.nls.nl.json index 72bc15f89a..86571b0aff 100644 --- a/src/package.nls.nl.json +++ b/src/package.nls.nl.json @@ -25,6 +25,7 @@ "command.acceptInput.title": "Invoer/Suggestie Accepteren", "command.showRipgrepDiagnostic.title": "Ripgrep-diagnose weergeven", "command.toggleAutoApprove.title": "Auto-Goedkeuring Schakelen", + "command.generateCommitMessage.title": "Commitbericht genereren", "configuration.title": "Zoo Code", "commands.allowedCommands.description": "Commando's die automatisch kunnen worden uitgevoerd wanneer 'Altijd goedkeuren uitvoerbewerkingen' is ingeschakeld", "commands.deniedCommands.description": "Commando-prefixen die automatisch worden geweigerd zonder om goedkeuring te vragen. Bij conflicten met toegestane commando's heeft de langste prefix-match voorrang. Voeg * toe om alle commando's te weigeren.", diff --git a/src/package.nls.pl.json b/src/package.nls.pl.json index 92fb97778b..eeccdd4a28 100644 --- a/src/package.nls.pl.json +++ b/src/package.nls.pl.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Akceptuj Wprowadzanie/Sugestię", "command.showRipgrepDiagnostic.title": "Pokaż diagnostykę Ripgrep", "command.toggleAutoApprove.title": "Przełącz Auto-Zatwierdzanie", + "command.generateCommitMessage.title": "Wygeneruj komunikat zatwierdzenia", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.pt-BR.json b/src/package.nls.pt-BR.json index 872af10e80..7d98ab8db7 100644 --- a/src/package.nls.pt-BR.json +++ b/src/package.nls.pt-BR.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Aceitar Entrada/Sugestão", "command.showRipgrepDiagnostic.title": "Mostrar diagnóstico do Ripgrep", "command.toggleAutoApprove.title": "Alternar Auto-Aprovação", + "command.generateCommitMessage.title": "Gerar mensagem de commit", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.ru.json b/src/package.nls.ru.json index cb38655945..3ac88352f6 100644 --- a/src/package.nls.ru.json +++ b/src/package.nls.ru.json @@ -25,6 +25,7 @@ "command.acceptInput.title": "Принять ввод/предложение", "command.showRipgrepDiagnostic.title": "Показать диагностику Ripgrep", "command.toggleAutoApprove.title": "Переключить Авто-Подтверждение", + "command.generateCommitMessage.title": "Сгенерировать сообщение коммита", "configuration.title": "Zoo Code", "commands.allowedCommands.description": "Команды, которые могут быть автоматически выполнены, когда включена опция 'Всегда подтверждать операции выполнения'", "commands.deniedCommands.description": "Префиксы команд, которые будут автоматически отклонены без запроса подтверждения. В случае конфликтов с разрешенными командами приоритет имеет самое длинное совпадение префикса. Добавьте * чтобы отклонить все команды.", diff --git a/src/package.nls.tr.json b/src/package.nls.tr.json index 7d995723ce..884614a582 100644 --- a/src/package.nls.tr.json +++ b/src/package.nls.tr.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Girişi/Öneriyi Kabul Et", "command.showRipgrepDiagnostic.title": "Ripgrep Tanılamasını Göster", "command.toggleAutoApprove.title": "Otomatik Onayı Değiştir", + "command.generateCommitMessage.title": "Commit Mesajı Oluştur", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.vi.json b/src/package.nls.vi.json index b50e4db508..59ae364025 100644 --- a/src/package.nls.vi.json +++ b/src/package.nls.vi.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "Chấp Nhận Đầu Vào/Gợi Ý", "command.showRipgrepDiagnostic.title": "Hiển thị chẩn đoán Ripgrep", "command.toggleAutoApprove.title": "Bật/Tắt Tự Động Phê Duyệt", + "command.generateCommitMessage.title": "Tạo thông điệp commit", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.zh-CN.json b/src/package.nls.zh-CN.json index 0686d03a14..4e6489cba3 100644 --- a/src/package.nls.zh-CN.json +++ b/src/package.nls.zh-CN.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "接受输入/建议", "command.showRipgrepDiagnostic.title": "显示 Ripgrep 诊断", "command.toggleAutoApprove.title": "切换自动批准", + "command.generateCommitMessage.title": "生成提交信息", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/package.nls.zh-TW.json b/src/package.nls.zh-TW.json index 8005e0de7f..aae17029a3 100644 --- a/src/package.nls.zh-TW.json +++ b/src/package.nls.zh-TW.json @@ -16,6 +16,7 @@ "command.acceptInput.title": "接受輸入/建議", "command.showRipgrepDiagnostic.title": "顯示 Ripgrep 診斷", "command.toggleAutoApprove.title": "切換自動批准", + "command.generateCommitMessage.title": "產生提交訊息", "views.activitybar.title": "Zoo Code", "views.contextMenu.label": "Zoo Code", "views.terminalMenu.label": "Zoo Code", diff --git a/src/services/commit-message/__tests__/generateCommitMessage.spec.ts b/src/services/commit-message/__tests__/generateCommitMessage.spec.ts new file mode 100644 index 0000000000..3637acb02a --- /dev/null +++ b/src/services/commit-message/__tests__/generateCommitMessage.spec.ts @@ -0,0 +1,167 @@ +import * as vscode from "vscode" + +import type { ProviderSettings } from "@roo-code/types" + +import { generateCommitMessage } from "../index" +import * as gitModule from "../../../utils/git" +import * as singleCompletionHandlerModule from "../../../utils/single-completion-handler" +import type { ClineProvider } from "../../../core/webview/ClineProvider" + +vi.mock("vscode", () => ({ + extensions: { getExtension: vi.fn() }, + window: { + showErrorMessage: vi.fn(), + showInformationMessage: vi.fn(), + // Run the task immediately so assertions don't have to await a real progress UI. + withProgress: vi.fn((_options: unknown, task: () => Promise) => task()), + }, + ProgressLocation: { SourceControl: 1, Window: 10, Notification: 15 }, + Uri: { file: (fsPath: string) => ({ fsPath }) }, +})) + +vi.mock("../../../utils/git") +vi.mock("../../../utils/single-completion-handler") +vi.mock("../../../i18n", () => ({ t: (key: string) => key })) + +describe("generateCommitMessage", () => { + const apiConfiguration: ProviderSettings = { apiProvider: "openai", apiKey: "key", apiModelId: "gpt-4" } + + const listApiConfigMeta = [ + { id: "config1", name: "Config 1" }, + { id: "config2", name: "Config 2" }, + ] + + const commitProfile = { + name: "Commit Config", + apiProvider: "anthropic" as const, + apiKey: "commit-key", + apiModelId: "claude-3", + } + + let inputBox: { value: string } + let getProfile: ReturnType + + const makeProvider = (commitMessageApiConfigId?: string) => + ({ + getState: vi.fn().mockResolvedValue({ + apiConfiguration, + listApiConfigMeta, + customSupportPrompts: {}, + commitMessageApiConfigId, + }), + providerSettingsManager: { getProfile }, + }) as unknown as ClineProvider + + beforeEach(() => { + vi.clearAllMocks() + + inputBox = { value: "" } + getProfile = vi.fn().mockResolvedValue(commitProfile) + + vi.mocked(vscode.extensions.getExtension).mockReturnValue({ + isActive: true, + exports: { + getAPI: () => ({ repositories: [{ rootUri: { fsPath: "/repo" }, inputBox }] }), + }, + } as never) + + vi.mocked(gitModule.getCommitContext).mockResolvedValue("Staged changes:\n\n+new line") + vi.mocked(singleCompletionHandlerModule.singleCompletionHandler).mockResolvedValue("feat: add a thing") + }) + + it("writes the generated message into the commit input box", async () => { + await generateCommitMessage(makeProvider()) + + expect(inputBox.value).toBe("feat: add a thing") + expect(singleCompletionHandlerModule.singleCompletionHandler).toHaveBeenCalledWith( + apiConfiguration, + expect.stringContaining("Staged changes:"), + ) + }) + + it("strips code fences and surrounding quotes from the model output", async () => { + vi.mocked(singleCompletionHandlerModule.singleCompletionHandler).mockResolvedValue( + '```\n"fix: correct the off-by-one"\n```', + ) + + await generateCommitMessage(makeProvider()) + + expect(inputBox.value).toBe("fix: correct the off-by-one") + }) + + it("uses the dedicated profile when one is configured", async () => { + await generateCommitMessage(makeProvider("config2")) + + expect(getProfile).toHaveBeenCalledWith({ id: "config2" }) + expect(singleCompletionHandlerModule.singleCompletionHandler).toHaveBeenCalledWith( + { apiProvider: "anthropic", apiKey: "commit-key", apiModelId: "claude-3" }, + expect.any(String), + ) + }) + + it("falls back to the active configuration when the configured profile no longer exists", async () => { + await generateCommitMessage(makeProvider("deleted-config")) + + expect(getProfile).not.toHaveBeenCalled() + expect(singleCompletionHandlerModule.singleCompletionHandler).toHaveBeenCalledWith( + apiConfiguration, + expect.any(String), + ) + }) + + it("picks the repository matching the clicked source control", async () => { + const otherInputBox = { value: "" } + + vi.mocked(vscode.extensions.getExtension).mockReturnValue({ + isActive: true, + exports: { + getAPI: () => ({ + repositories: [ + { rootUri: { fsPath: "/other" }, inputBox: otherInputBox }, + { rootUri: { fsPath: "/repo" }, inputBox }, + ], + }), + }, + } as never) + + await generateCommitMessage(makeProvider(), { rootUri: { fsPath: "/repo" } } as vscode.SourceControl) + + expect(inputBox.value).toBe("feat: add a thing") + expect(otherInputBox.value).toBe("") + }) + + it("reports no changes and leaves the input box untouched", async () => { + vi.mocked(gitModule.getCommitContext).mockResolvedValue(null) + + await generateCommitMessage(makeProvider()) + + expect(inputBox.value).toBe("") + expect(singleCompletionHandlerModule.singleCompletionHandler).not.toHaveBeenCalled() + expect(vscode.window.showInformationMessage).toHaveBeenCalledWith("common:info.commit_message_no_changes") + }) + + it("reports an error when the git extension is unavailable", async () => { + vi.mocked(vscode.extensions.getExtension).mockReturnValue(undefined) + + await generateCommitMessage(makeProvider()) + + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("common:errors.commit_message_no_repository") + }) + + it("reports progress somewhere the title is actually rendered", async () => { + await generateCommitMessage(makeProvider()) + + // `ProgressLocation.SourceControl` silently drops the title, so a regression back to it + // would leave the user with an unlabelled spinner. + const [options] = vi.mocked(vscode.window.withProgress).mock.calls[0] + expect(options.location).toBe(vscode.ProgressLocation.Window) + expect(options.title).toBeTruthy() + }) + + it("surfaces generation failures instead of throwing", async () => { + vi.mocked(singleCompletionHandlerModule.singleCompletionHandler).mockRejectedValue(new Error("boom")) + + await expect(generateCommitMessage(makeProvider())).resolves.toBeUndefined() + expect(vscode.window.showErrorMessage).toHaveBeenCalledWith("common:errors.commit_message_failed") + }) +}) diff --git a/src/services/commit-message/index.ts b/src/services/commit-message/index.ts new file mode 100644 index 0000000000..9a0f854e71 --- /dev/null +++ b/src/services/commit-message/index.ts @@ -0,0 +1,137 @@ +import * as vscode from "vscode" + +import type { ProviderSettings } from "@roo-code/types" + +import { t } from "../../i18n" +import { supportPrompt } from "../../shared/support-prompt" +import { getCommitContext } from "../../utils/git" +import { singleCompletionHandler } from "../../utils/single-completion-handler" +import type { ClineProvider } from "../../core/webview/ClineProvider" + +/** + * The slice of the built-in Git extension's API that we depend on. Declared structurally so we + * don't have to vendor `git.d.ts` for three properties. + */ +interface GitRepository { + rootUri: vscode.Uri + inputBox: { value: string } +} + +interface GitApi { + repositories: GitRepository[] +} + +interface GitExtensionExports { + getAPI(version: 1): GitApi +} + +/** + * Resolves the repository whose commit input box should be filled. + * + * The `scm/title` menu passes the `SourceControl` that was clicked, which lets us pick the right + * repository in a multi-root workspace. When that isn't available we fall back to the first one. + */ +async function findRepository(sourceControl?: vscode.SourceControl): Promise { + const extension = vscode.extensions.getExtension("vscode.git") + + if (!extension) { + return undefined + } + + if (!extension.isActive) { + await extension.activate() + } + + const repositories = extension.exports?.getAPI(1).repositories ?? [] + const clickedPath = sourceControl?.rootUri?.fsPath + + if (clickedPath) { + const match = repositories.find((repo) => repo.rootUri.fsPath === clickedPath) + + if (match) { + return match + } + } + + return repositories[0] +} + +/** + * Models tend to wrap their answer in code fences or quotes despite being told not to. + */ +function cleanCommitMessage(message: string): string { + return message + .replace(/```[a-z]*\n?|```/g, "") + .trim() + .replace(/^["'`]|["'`]$/g, "") + .trim() +} + +/** + * Generates a commit message from the current changes and writes it into the Source Control input + * box. Prefers the profile chosen in Settings → Providers → Commit Message Model, falling back to + * the currently active profile. + */ +export async function generateCommitMessage( + provider: ClineProvider, + sourceControl?: vscode.SourceControl, +): Promise { + try { + const repository = await findRepository(sourceControl) + + if (!repository) { + vscode.window.showErrorMessage(t("common:errors.commit_message_no_repository")) + return + } + + const gitContext = await getCommitContext(repository.rootUri.fsPath) + + if (!gitContext) { + vscode.window.showInformationMessage(t("common:info.commit_message_no_changes")) + return + } + + const { apiConfiguration, listApiConfigMeta, customSupportPrompts, commitMessageApiConfigId } = + await provider.getState() + + // Fall back to the active configuration when no dedicated profile is set, or when the saved + // one has since been deleted (`getProfile` throws on an unknown id). + let configToUse: ProviderSettings = apiConfiguration + + if (commitMessageApiConfigId && listApiConfigMeta?.find(({ id }) => id === commitMessageApiConfigId)) { + const { name: _, ...providerSettings } = await provider.providerSettingsManager.getProfile({ + id: commitMessageApiConfigId, + }) + + if (providerSettings.apiProvider) { + configToUse = providerSettings + } + } + + const prompt = supportPrompt.create("COMMIT_MESSAGE", { gitContext }, customSupportPrompts) + + // `ProgressLocation.Window` shows the title in the status bar. `SourceControl` only spins + // the SCM icon and drops the title entirely. + // + // No cancel button: only `ProgressLocation.Notification` renders one, and a toast on every + // commit would be intrusive. Cancellation would be inert anyway - `completePrompt` accepts + // an `abortSignal`, but nearly every provider (Ollama included) ignores the argument, so + // the underlying request cannot actually be interrupted today. + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Window, + title: t("common:info.commit_message_generating"), + }, + async () => { + const message = await singleCompletionHandler(configToUse, prompt) + repository.inputBox.value = cleanCommitMessage(message) + }, + ) + } catch (error) { + vscode.window.showErrorMessage( + t("common:errors.commit_message_failed", { + error: error instanceof Error ? error.message : String(error), + }), + ) + } +} diff --git a/src/shared/support-prompt.ts b/src/shared/support-prompt.ts index da14c4367f..21f6fad901 100644 --- a/src/shared/support-prompt.ts +++ b/src/shared/support-prompt.ts @@ -44,6 +44,7 @@ type SupportPromptType = | "TERMINAL_FIX" | "TERMINAL_EXPLAIN" | "NEW_TASK" + | "COMMIT_MESSAGE" const supportPromptConfigs: Record = { ENHANCE: { @@ -240,6 +241,19 @@ Please provide: NEW_TASK: { template: `\${userInput}`, }, + COMMIT_MESSAGE: { + template: `Write a git commit message for the following changes. + +Follow the Conventional Commits specification: \`type(scope): description\`, where type is one of feat, fix, docs, style, refactor, perf, test, build, ci, chore, or revert. Keep the description under 72 characters and in the imperative mood. + +Account for every changed file. The subject line describes the change as a whole, so do not let the largest file speak for the rest. When the changes touch more than one file or concern, follow the subject with a blank line and one \`- \` bullet per distinct change, naming the file or area it affects. Use a subject line on its own only when it genuinely covers everything that changed. + +If the changes are unrelated to one another, say so plainly rather than inventing a single scope that hides some of them. + +Reply with ONLY the commit message - no explanation, no markdown code fences, no surrounding quotes. + +\${gitContext}`, + }, } as const export const supportPrompt = { diff --git a/src/utils/__tests__/git.spec.ts b/src/utils/__tests__/git.spec.ts index 95040a3d01..0d585703a4 100644 --- a/src/utils/__tests__/git.spec.ts +++ b/src/utils/__tests__/git.spec.ts @@ -13,6 +13,7 @@ import { getWorkspaceGitInfo, convertGitUrlToHttps, getGitStatus, + getCommitContext, } from "../git" import { truncateOutput } from "../../integrations/misc/extract-text" @@ -351,6 +352,121 @@ describe("git utils", () => { }) }) + describe("getCommitContext", () => { + const mockDiff = "@@ -1,1 +1,2 @@\n-old line\n+new line" + + type ExecResult = { stdout: string; stderr: string } + + const mockExec = (responses: Map) => { + const implementation = ( + command: string, + _options: unknown, + callback: (error: Error | null, result?: ExecResult) => void, + ) => { + const response = responses.get(command) + + if (response) { + callback(null, response) + } else { + callback(new Error("Unexpected command")) + } + + // `exec` returns a ChildProcess that none of these tests inspect. + return {} as ReturnType + } + + vitest.mocked(exec).mockImplementation(implementation as unknown as typeof exec) + } + + const gitAvailable: Array<[string, { stdout: string; stderr: string }]> = [ + ["git --version", { stdout: "git version 2.39.2", stderr: "" }], + ["git rev-parse --git-dir", { stdout: ".git", stderr: "" }], + ] + + it("should use staged changes when something is staged", async () => { + mockExec( + new Map([ + ...gitAvailable, + ["git diff --cached --stat", { stdout: " src/file1.ts | 2 +-", stderr: "" }], + ["git diff --cached --unified=1", { stdout: mockDiff, stderr: "" }], + ]), + ) + + const result = await getCommitContext(cwd) + expect(result).toContain("Staged changes:") + expect(result).toContain("src/file1.ts") + expect(result).toContain("+new line") + }) + + // These tests mock `exec`, so they cannot catch a diff flag that real git rejects. `exec` + // runs through cmd.exe on Windows, which does not strip the single quotes that + // `:(exclude)` pathspecs need - keep the argument string free of shell metacharacters. + it("should build diff arguments that need no shell quoting", async () => { + const commands: string[] = [] + + vitest.mocked(exec).mockImplementation((( + command: string, + _options: unknown, + callback: (error: Error | null, result?: ExecResult) => void, + ) => { + commands.push(command) + const stdout = command.includes("--stat") ? " src/file1.ts | 2 +-" : mockDiff + callback(null, { stdout, stderr: "" }) + return {} as ReturnType + }) as unknown as typeof exec) + + await getCommitContext(cwd) + + const diffCommands = commands.filter((c) => c.startsWith("git diff")) + expect(diffCommands.length).toBeGreaterThan(0) + + for (const command of diffCommands) { + expect(command).not.toMatch(/['"()]/) + } + }) + + it("should fall back to the working tree when nothing is staged", async () => { + mockExec( + new Map([ + ...gitAvailable, + ["git diff --cached --stat", { stdout: "", stderr: "" }], + ["git status --short", { stdout: " M src/file1.ts\n?? src/untracked.ts", stderr: "" }], + ["git diff HEAD --unified=1", { stdout: mockDiff, stderr: "" }], + ]), + ) + + const result = await getCommitContext(cwd) + expect(result).toContain("Unstaged changes:") + // `git status --short` is used here specifically so untracked files are visible. + expect(result).toContain("src/untracked.ts") + expect(result).toContain("+new line") + }) + + it("should return null when the tree is clean", async () => { + mockExec( + new Map([ + ...gitAvailable, + ["git diff --cached --stat", { stdout: "", stderr: "" }], + ["git status --short", { stdout: "", stderr: "" }], + ]), + ) + + expect(await getCommitContext(cwd)).toBeNull() + }) + + it("should return null when git is not installed", async () => { + mockExec(new Map()) + + expect(await getCommitContext(cwd)).toBeNull() + }) + + it("should return null when not in a git repository", async () => { + mockExec(new Map([gitAvailable[0]])) + + expect(await getCommitContext(cwd)).toBeNull() + }) + }) + describe("getWorkingState", () => { const mockStatus = " M src/file1.ts\n?? src/file2.ts" const mockDiff = "@@ -1,1 +1,2 @@\n-old line\n+new line" diff --git a/src/utils/git.ts b/src/utils/git.ts index 04c028c3d1..65152dd2d7 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -12,6 +12,17 @@ const execAsync = promisify(exec) const GIT_OUTPUT_LINE_LIMIT = 500 +// Node's default `exec` buffer is 1MB, which real-world diffs routinely exceed. +const GIT_DIFF_MAX_BUFFER = 10 * 1024 * 1024 + +// A commit message needs to know what changed, not every line of how. One line of surrounding +// context per hunk is enough to tell the model where an edit landed, and shrinking the prompt is +// the one latency factor we control without affecting the model's output. +// +// Deliberately no `:(exclude)` pathspecs here: `exec` goes through cmd.exe on Windows, which does +// not strip the single quotes those require. Oversized diffs are handled by `truncateOutput`. +const COMMIT_DIFF_ARGS = "--unified=1" + /** * Extracts git repository information from the workspace's .git directory * @param workspaceRoot The root path of the workspace @@ -346,6 +357,49 @@ export async function getWorkingState(cwd: string): Promise { } } +/** + * Collects the changes to describe in a commit message. + * + * Prefers staged changes, since that is what a commit will actually contain. When nothing is + * staged, falls back to the whole working tree so the caller still has something to summarize. + * + * @param cwd The repository root to inspect + * @returns A summary + diff suitable for a prompt, or null if there is nothing to commit + */ +export async function getCommitContext(cwd: string): Promise { + const isInstalled = await checkGitInstalled() + if (!isInstalled) { + return null + } + + const isRepo = await checkGitRepo(cwd) + if (!isRepo) { + return null + } + + const options = { cwd, maxBuffer: GIT_DIFF_MAX_BUFFER } + + const { stdout: stagedSummary } = await execAsync("git diff --cached --stat", options) + + if (stagedSummary.trim()) { + const { stdout: stagedDiff } = await execAsync(`git diff --cached ${COMMIT_DIFF_ARGS}`, options) + const output = `Staged changes:\n\n${stagedSummary.trim()}\n\n${stagedDiff.trim()}` + return truncateOutput(output, GIT_OUTPUT_LINE_LIMIT) + } + + // Nothing staged - describe the working tree instead. `git status --short` is used rather than + // `--stat` here because it also lists untracked files, which no diff would show. + const { stdout: status } = await execAsync("git status --short", options) + + if (!status.trim()) { + return null + } + + const { stdout: diff } = await execAsync(`git diff HEAD ${COMMIT_DIFF_ARGS}`, options) + const output = `Unstaged changes:\n\n${status.trim()}\n\n${diff.trim()}`.trim() + return truncateOutput(output, GIT_OUTPUT_LINE_LIMIT) +} + /** * Gets git status output with configurable file limit * @param cwd The working directory to check git status in diff --git a/webview-ui/src/components/settings/CommitMessageModelSelect.tsx b/webview-ui/src/components/settings/CommitMessageModelSelect.tsx new file mode 100644 index 0000000000..fcd49455ce --- /dev/null +++ b/webview-ui/src/components/settings/CommitMessageModelSelect.tsx @@ -0,0 +1,60 @@ +import type { ProviderSettingsEntry } from "@roo-code/types" + +import { useAppTranslation } from "@src/i18n/TranslationContext" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@src/components/ui" + +import { SearchableSetting } from "./SearchableSetting" +import { SetCachedStateField } from "./types" + +// Sentinel for "no dedicated profile" - Select cannot hold an empty string as a value. +const USE_CURRENT_CONFIG = "-" + +interface CommitMessageModelSelectProps { + listApiConfigMeta: ProviderSettingsEntry[] + commitMessageApiConfigId?: string + setCachedStateField: SetCachedStateField<"commitMessageApiConfigId"> +} + +/** + * Picks the API configuration profile used to generate Git commit messages from the Source Control + * panel. Leaving it unset uses whichever profile is currently active. + */ +export const CommitMessageModelSelect = ({ + listApiConfigMeta, + commitMessageApiConfigId, + setCachedStateField, +}: CommitMessageModelSelectProps) => { + const { t } = useAppTranslation() + + return ( + + + +
+ {t("settings:providers.commitMessageModel.description")} +
+
+ ) +} diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 952c5615af..e8e4710105 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -68,6 +68,7 @@ import { SetCachedStateField, SetExperimentEnabled } from "./types" import { SectionHeader } from "./SectionHeader" import ApiConfigManager from "./ApiConfigManager" import ApiOptions from "./ApiOptions" +import { CommitMessageModelSelect } from "./CommitMessageModelSelect" import { AutoApproveSettings } from "./AutoApproveSettings" import { CheckpointSettings } from "./CheckpointSettings" import { NotificationSettings } from "./NotificationSettings" @@ -217,6 +218,7 @@ const SettingsView = forwardRef(({ onDone, t autoCloseZooOpenedFiles, autoCloseZooOpenedFilesAfterUserEdited, autoCloseZooOpenedNewFiles, + commitMessageApiConfigId, } = cachedState const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration]) @@ -448,6 +450,7 @@ const SettingsView = forwardRef(({ onDone, t openRouterImageGenerationSelectedModel, experiments, customSupportPrompts, + commitMessageApiConfigId, }, }) @@ -800,6 +803,11 @@ const SettingsView = forwardRef(({ onDone, t errorMessage={errorMessage} setErrorMessage={setErrorMessage} /> + )} diff --git a/webview-ui/src/components/settings/__tests__/CommitMessageModelSelect.spec.tsx b/webview-ui/src/components/settings/__tests__/CommitMessageModelSelect.spec.tsx new file mode 100644 index 0000000000..3c73ac0ccc --- /dev/null +++ b/webview-ui/src/components/settings/__tests__/CommitMessageModelSelect.spec.tsx @@ -0,0 +1,92 @@ +// npx vitest src/components/settings/__tests__/CommitMessageModelSelect.spec.tsx + +import { render, screen, fireEvent } from "@/utils/test-utils" + +import { CommitMessageModelSelect } from "../CommitMessageModelSelect" + +vi.mock("@src/i18n/TranslationContext", () => ({ + useAppTranslation: () => ({ t: (key: string) => key }), +})) + +vi.mock("@src/components/ui", () => ({ + Select: ({ children, value, onValueChange, ...props }: any) => ( +
+ {/* Hidden trigger lets tests drive selection deterministically: + set data-next-value on the button, then click it. */} +
+ ), + SelectTrigger: ({ children, ...props }: any) =>
{children}
, + SelectValue: ({ children, ...props }: any) =>
{children}
, + SelectContent: ({ children, ...props }: any) =>
{children}
, + SelectItem: ({ children, ...props }: any) =>
{children}
, +})) + +describe("CommitMessageModelSelect", () => { + const listApiConfigMeta = [ + { id: "config1", name: "Config 1" }, + { id: "config2", name: "Config 2" }, + ] + + const renderSelect = (commitMessageApiConfigId?: string) => { + const setCachedStateField = vi.fn() + + render( + , + ) + + return { setCachedStateField } + } + + const selectValue = (value: string) => { + const trigger = screen.getByTestId("commit-message-model-change") + trigger.setAttribute("data-next-value", value) + fireEvent.click(trigger) + } + + it("lists every available profile alongside the fallback option", () => { + renderSelect() + + expect(screen.getByTestId("config1-option")).toHaveTextContent("Config 1") + expect(screen.getByTestId("config2-option")).toHaveTextContent("Config 2") + expect(screen.getByText("settings:providers.commitMessageModel.useCurrentConfig")).toBeInTheDocument() + }) + + it("shows the sentinel when no profile is selected", () => { + renderSelect() + + expect(screen.getByRole("combobox")).toHaveAttribute("data-value", "-") + }) + + it("shows the saved profile when one is selected", () => { + renderSelect("config2") + + expect(screen.getByRole("combobox")).toHaveAttribute("data-value", "config2") + }) + + it("stores the selected profile id", () => { + const { setCachedStateField } = renderSelect() + + selectValue("config2") + + expect(setCachedStateField).toHaveBeenCalledWith("commitMessageApiConfigId", "config2") + }) + + it("stores an empty string when the fallback option is chosen", () => { + const { setCachedStateField } = renderSelect("config2") + + selectValue("-") + + expect(setCachedStateField).toHaveBeenCalledWith("commitMessageApiConfigId", "") + }) +}) diff --git a/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx b/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx index a3aa131902..701fcc7575 100644 --- a/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx @@ -373,6 +373,30 @@ describe("SettingsView - Sound Settings", () => { ) }) + it("includes the commit message model in the saved settings", async () => { + const { activateTab, getSettingsContent } = renderSettingsView({ + commitMessageApiConfigId: "config2", + settingsImportedAt: new Date().toISOString(), + }) + + // Any edit will do - this asserts the field survives the cachedState round trip rather than + // being dropped from the `updateSettings` payload. + activateTab("notifications") + fireEvent.click(await within(getSettingsContent()).findByTestId("sound-enabled-checkbox")) + fireEvent.click(screen.getByTestId("save-button")) + + await waitFor(() => + expect(vscode.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: "updateSettings", + updatedSettings: expect.objectContaining({ + commitMessageApiConfigId: "config2", + }), + }), + ), + ) + }) + it("toggles sound setting and sends message to VSCode", () => { // Render once and get the activateTab helper const { activateTab, getSettingsContent } = renderSettingsView() diff --git a/webview-ui/src/i18n/locales/ca/prompts.json b/webview-ui/src/i18n/locales/ca/prompts.json index 8df3376f83..32059cb0ec 100644 --- a/webview-ui/src/i18n/locales/ca/prompts.json +++ b/webview-ui/src/i18n/locales/ca/prompts.json @@ -104,6 +104,10 @@ "label": "Millorar prompt", "description": "Utilitzeu la millora de prompts per obtenir suggeriments o millores personalitzades per a les vostres entrades. Això assegura que Zoo entengui la vostra intenció i proporcioni les millors respostes possibles. Disponible a través de la icona ✨ al xat." }, + "COMMIT_MESSAGE": { + "label": "Missatge de comissió", + "description": "Resumeix els teus canvis en un missatge de comissió. Disponible mitjançant la icona de Zoo Code al plafó de control de codi font, que escriu el resultat directament al camp del missatge de comissió." + }, "CONDENSE": { "label": "Condensació de context", "description": "Configureu com es condensa el context de la conversa per gestionar els límits de testimonis. Aquest indicador s'utilitza tant per a les operacions de condensació de context manuals com automàtiques." diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 73827b1ec1..ea213b56ad 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Documentació de {{provider}}", + "commitMessageModel": { + "label": "Model per als missatges de comissió", + "description": "Perfil utilitzat per generar missatges de comissió des del plafó de control de codi font. Normalment n'hi ha prou amb un model petit i ràpid. Deixa-ho sense seleccionar per fer servir el perfil actiu.", + "useCurrentConfig": "Utilitza la configuració d'API seleccionada actualment" + }, "configProfile": "Perfil de configuració", "description": "Deseu diferents configuracions d'API per canviar ràpidament entre proveïdors i configuracions.", "apiProvider": "Proveïdor d'API", diff --git a/webview-ui/src/i18n/locales/de/prompts.json b/webview-ui/src/i18n/locales/de/prompts.json index 28f7cbec5f..c2504ac164 100644 --- a/webview-ui/src/i18n/locales/de/prompts.json +++ b/webview-ui/src/i18n/locales/de/prompts.json @@ -104,6 +104,10 @@ "label": "Prompt verbessern", "description": "Verwenden Sie die Prompt-Verbesserung, um maßgeschneiderte Vorschläge oder Verbesserungen für Ihre Eingaben zu erhalten. Dies stellt sicher, dass Zoo Ihre Absicht versteht und die bestmöglichen Antworten liefert. Verfügbar über das ✨-Symbol im Chat." }, + "COMMIT_MESSAGE": { + "label": "Commit-Nachricht", + "description": "Fasst deine Änderungen zu einer Commit-Nachricht zusammen. Verfügbar über das Zoo-Code-Symbol in der Quellcodeverwaltung, das das Ergebnis direkt in das Commit-Eingabefeld schreibt." + }, "CONDENSE": { "label": "Kontextverdichtung", "description": "Konfigurieren Sie, wie der Konversationskontext verdichtet wird, um Token-Limits zu verwalten. Dieser Prompt wird sowohl für manuelle als auch für automatische Kontextverdichtungsvorgänge verwendet." diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 8078037525..8bd7d45932 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}}-Dokumentation", + "commitMessageModel": { + "label": "Modell für Commit-Nachrichten", + "description": "Profil zum Generieren von Commit-Nachrichten aus der Quellcodeverwaltung. Ein kleines, schnelles Modell reicht in der Regel aus. Nicht ausgewählt lassen, um das aktuell aktive Profil zu verwenden.", + "useCurrentConfig": "Aktuell ausgewählte API-Konfiguration verwenden" + }, "configProfile": "Konfigurationsprofil", "description": "Speichern Sie verschiedene API-Konfigurationen, um schnell zwischen Anbietern und Einstellungen zu wechseln.", "apiProvider": "API-Anbieter", diff --git a/webview-ui/src/i18n/locales/en/prompts.json b/webview-ui/src/i18n/locales/en/prompts.json index 1494d31ba8..2ad176fe61 100644 --- a/webview-ui/src/i18n/locales/en/prompts.json +++ b/webview-ui/src/i18n/locales/en/prompts.json @@ -103,6 +103,10 @@ "label": "Enhance Prompt", "description": "Use prompt enhancement to get tailored suggestions or improvements for your inputs. This ensures Zoo understands your intent and provides the best possible responses. Available via the ✨ icon in chat." }, + "COMMIT_MESSAGE": { + "label": "Commit Message", + "description": "Summarizes your changes into a commit message. Available via the Zoo Code icon in the Source Control panel, which writes the result straight into the commit input box." + }, "CONDENSE": { "label": "Context Condensing", "description": "Configure how conversation context is condensed to manage token limits. This prompt is used for both manual and automatic context condensing operations." diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 14a7476a75..419d9a692e 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -436,6 +436,11 @@ }, "providers": { "providerDocumentation": "{{provider}} documentation", + "commitMessageModel": { + "label": "Commit Message Model", + "description": "Profile used to generate commit messages from the Source Control panel. A small, fast model is usually enough. Leave unselected to use the currently active profile.", + "useCurrentConfig": "Use currently selected API configuration" + }, "configProfile": "Configuration Profile", "description": "Save different API configurations to quickly switch between providers and settings.", "apiProvider": "API Provider", diff --git a/webview-ui/src/i18n/locales/es/prompts.json b/webview-ui/src/i18n/locales/es/prompts.json index 626fb3284e..11655605dd 100644 --- a/webview-ui/src/i18n/locales/es/prompts.json +++ b/webview-ui/src/i18n/locales/es/prompts.json @@ -104,6 +104,10 @@ "label": "Mejorar solicitud", "description": "Utiliza la mejora de solicitudes para obtener sugerencias o mejoras personalizadas para tus entradas. Esto asegura que Zoo entienda tu intención y proporcione las mejores respuestas posibles. Disponible a través del icono ✨ en el chat." }, + "COMMIT_MESSAGE": { + "label": "Mensaje de confirmación", + "description": "Resume tus cambios en un mensaje de confirmación. Disponible mediante el icono de Zoo Code en el panel de control de código fuente, que escribe el resultado directamente en el campo del mensaje de confirmación." + }, "CONDENSE": { "label": "Condensación de contexto", "description": "Configura cómo se condensa el contexto de la conversación para gestionar los límites de tokens. Este prompt se utiliza tanto para operaciones de condensación de contexto manuales como automáticas." diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index e629e43b50..1b3c86352c 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Documentación de {{provider}}", + "commitMessageModel": { + "label": "Modelo para mensajes de confirmación", + "description": "Perfil utilizado para generar mensajes de confirmación desde el panel de control de código fuente. Normalmente basta con un modelo pequeño y rápido. Déjalo sin seleccionar para usar el perfil activo.", + "useCurrentConfig": "Usar la configuración de API seleccionada actualmente" + }, "configProfile": "Perfil de configuración", "description": "Guarde diferentes configuraciones de API para cambiar rápidamente entre proveedores y ajustes.", "apiProvider": "Proveedor de API", diff --git a/webview-ui/src/i18n/locales/fr/prompts.json b/webview-ui/src/i18n/locales/fr/prompts.json index bd5967f7f0..4f39f7c05c 100644 --- a/webview-ui/src/i18n/locales/fr/prompts.json +++ b/webview-ui/src/i18n/locales/fr/prompts.json @@ -104,6 +104,10 @@ "label": "Améliorer le prompt", "description": "Utilisez l'amélioration de prompt pour obtenir des suggestions ou des améliorations personnalisées pour vos entrées. Cela garantit que Zoo comprend votre intention et fournit les meilleures réponses possibles. Disponible via l'icône ✨ dans le chat." }, + "COMMIT_MESSAGE": { + "label": "Message de commit", + "description": "Résume vos modifications en un message de commit. Disponible via l'icône Zoo Code dans le panneau de contrôle de code source, qui écrit le résultat directement dans le champ du message de commit." + }, "CONDENSE": { "label": "Condensation du contexte", "description": "Configurez la manière dont le contexte de la conversation est condensé pour gérer les limites de jetons. Ce prompt est utilisé pour les opérations de condensation de contexte manuelles et automatiques." diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 6048e2274c..02dc6d0297 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Documentation {{provider}}", + "commitMessageModel": { + "label": "Modèle pour les messages de commit", + "description": "Profil utilisé pour générer les messages de commit depuis le panneau de contrôle de code source. Un petit modèle rapide suffit généralement. Laissez vide pour utiliser le profil actif.", + "useCurrentConfig": "Utiliser la configuration d'API actuellement sélectionnée" + }, "configProfile": "Profil de configuration", "description": "Enregistrez différentes configurations d'API pour basculer rapidement entre les fournisseurs et les paramètres.", "apiProvider": "Fournisseur d'API", diff --git a/webview-ui/src/i18n/locales/hi/prompts.json b/webview-ui/src/i18n/locales/hi/prompts.json index 6d3cb85d05..0656d24263 100644 --- a/webview-ui/src/i18n/locales/hi/prompts.json +++ b/webview-ui/src/i18n/locales/hi/prompts.json @@ -104,6 +104,10 @@ "label": "प्रॉम्प्ट बढ़ाएँ", "description": "अपने इनपुट के लिए अनुकूलित सुझाव या सुधार प्राप्त करने के लिए प्रॉम्प्ट वृद्धि का उपयोग करें। यह सुनिश्चित करता है कि Zoo आपके इरादे को समझता है और सर्वोत्तम संभव प्रतिक्रियाएँ प्रदान करता है। चैट में ✨ आइकन के माध्यम से उपलब्ध है।" }, + "COMMIT_MESSAGE": { + "label": "कमिट संदेश", + "description": "आपके परिवर्तनों को एक कमिट संदेश में सारांशित करता है। स्रोत नियंत्रण पैनल में Zoo Code आइकन के माध्यम से उपलब्ध है, जो परिणाम को सीधे कमिट इनपुट बॉक्स में लिखता है।" + }, "CONDENSE": { "label": "संदर्भ संघनन", "description": "टोकन सीमाओं का प्रबंधन करने के लिए बातचीत के संदर्भ को कैसे संघनित किया जाता है, इसे कॉन्फ़iger करें। इस प्रॉम्प्ट का उपयोग मैनुअल और स्वचालित दोनों संदर्भ संघनन संचालन के लिए किया जाता है।" diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 28d0b8699b..1fe7812645 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}} दस्तावेज़ीकरण", + "commitMessageModel": { + "label": "कमिट संदेश मॉडल", + "description": "स्रोत नियंत्रण पैनल से कमिट संदेश जनरेट करने के लिए उपयोग की जाने वाली प्रोफ़ाइल। आमतौर पर एक छोटा, तेज़ मॉडल पर्याप्त होता है। वर्तमान सक्रिय प्रोफ़ाइल का उपयोग करने के लिए इसे अचयनित छोड़ दें।", + "useCurrentConfig": "वर्तमान में चयनित API कॉन्फ़िगरेशन का उपयोग करें" + }, "configProfile": "कॉन्फिगरेशन प्रोफाइल", "description": "विभिन्न API कॉन्फ़िगरेशन सहेजें ताकि प्रदाताओं और सेटिंग्स के बीच त्वरित रूप से स्विच कर सकें।", "apiProvider": "API प्रदाता", diff --git a/webview-ui/src/i18n/locales/id/prompts.json b/webview-ui/src/i18n/locales/id/prompts.json index 395ca69cb4..7dc859f4ba 100644 --- a/webview-ui/src/i18n/locales/id/prompts.json +++ b/webview-ui/src/i18n/locales/id/prompts.json @@ -104,6 +104,10 @@ "label": "Tingkatkan Prompt", "description": "Gunakan peningkatan prompt untuk mendapatkan saran atau perbaikan yang disesuaikan untuk input Anda. Ini memastikan Zoo memahami maksud Anda dan memberikan respons terbaik. Tersedia melalui ikon ✨ di chat." }, + "COMMIT_MESSAGE": { + "label": "Pesan Commit", + "description": "Merangkum perubahan Anda menjadi pesan commit. Tersedia melalui ikon Zoo Code di panel Source Control, yang menulis hasilnya langsung ke kotak input commit." + }, "CONDENSE": { "label": "Peringkasan Konteks", "description": "Konfigurasikan bagaimana konteks percakapan diringkas untuk mengelola batas token. Prompt ini digunakan untuk operasi peringkasan konteks manual dan otomatis." diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index bf049395c4..ced6b68679 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Dokumentasi {{provider}}", + "commitMessageModel": { + "label": "Model Pesan Commit", + "description": "Profil yang digunakan untuk menghasilkan pesan commit dari panel Source Control. Model kecil dan cepat biasanya sudah cukup. Biarkan tidak dipilih untuk menggunakan profil yang sedang aktif.", + "useCurrentConfig": "Gunakan konfigurasi API yang dipilih saat ini" + }, "configProfile": "Profil Konfigurasi", "description": "Simpan konfigurasi API yang berbeda untuk beralih dengan cepat antara provider dan pengaturan.", "apiProvider": "Provider API", diff --git a/webview-ui/src/i18n/locales/it/prompts.json b/webview-ui/src/i18n/locales/it/prompts.json index fd5c9518e8..acdf9df61f 100644 --- a/webview-ui/src/i18n/locales/it/prompts.json +++ b/webview-ui/src/i18n/locales/it/prompts.json @@ -104,6 +104,10 @@ "label": "Migliora prompt", "description": "Utilizza il miglioramento dei prompt per ottenere suggerimenti o miglioramenti personalizzati per i tuoi input. Questo assicura che Zoo comprenda la tua intenzione e fornisca le migliori risposte possibili. Disponibile tramite l'icona ✨ nella chat." }, + "COMMIT_MESSAGE": { + "label": "Messaggio di commit", + "description": "Riassume le tue modifiche in un messaggio di commit. Disponibile tramite l'icona Zoo Code nel pannello Controllo del codice sorgente, che scrive il risultato direttamente nel campo del messaggio di commit." + }, "CONDENSE": { "label": "Condensazione del contesto", "description": "Configura come viene condensato il contesto della conversazione per gestire i limiti dei token. Questo prompt viene utilizzato sia per le operazioni di condensazione del contesto manuali che automatiche." diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 577a74a77a..c74cbc2406 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Documentazione {{provider}}", + "commitMessageModel": { + "label": "Modello per i messaggi di commit", + "description": "Profilo utilizzato per generare i messaggi di commit dal pannello Controllo del codice sorgente. Di solito è sufficiente un modello piccolo e veloce. Lascia deselezionato per usare il profilo attivo.", + "useCurrentConfig": "Usa la configurazione API attualmente selezionata" + }, "configProfile": "Profilo di configurazione", "description": "Salva diverse configurazioni API per passare rapidamente tra fornitori e impostazioni.", "apiProvider": "Fornitore API", diff --git a/webview-ui/src/i18n/locales/ja/prompts.json b/webview-ui/src/i18n/locales/ja/prompts.json index eb1b1af251..a59efd506d 100644 --- a/webview-ui/src/i18n/locales/ja/prompts.json +++ b/webview-ui/src/i18n/locales/ja/prompts.json @@ -104,6 +104,10 @@ "label": "プロンプトを強化", "description": "プロンプト強化を使用して、入力に合わせたカスタマイズされた提案や改善を得ることができます。これにより、Zooがあなたの意図を理解し、最適な回答を提供できます。チャットの✨アイコンから利用できます。" }, + "COMMIT_MESSAGE": { + "label": "コミットメッセージ", + "description": "変更内容をコミットメッセージに要約します。ソース管理パネルの Zoo Code アイコンから利用でき、結果はコミット入力欄に直接書き込まれます。" + }, "CONDENSE": { "label": "コンテキスト圧縮", "description": "トークン制限を管理するために会話のコンテキストを圧縮する方法を設定します。このプロンプトは、手動および自動のコンテキスト圧縮操作の両方に使用されます。" diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 1113ac32a6..1eb5dab59d 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}}のドキュメント", + "commitMessageModel": { + "label": "コミットメッセージ用モデル", + "description": "ソース管理パネルからコミットメッセージを生成するために使用するプロファイル。通常は小さく高速なモデルで十分です。未選択のままにすると、現在アクティブなプロファイルが使用されます。", + "useCurrentConfig": "現在選択されている API 構成を使用" + }, "configProfile": "設定プロファイル", "description": "異なるAPI設定を保存して、プロバイダーと設定をすばやく切り替えることができます。", "apiProvider": "APIプロバイダー", diff --git a/webview-ui/src/i18n/locales/ko/prompts.json b/webview-ui/src/i18n/locales/ko/prompts.json index 90ac4d0905..46e120b22f 100644 --- a/webview-ui/src/i18n/locales/ko/prompts.json +++ b/webview-ui/src/i18n/locales/ko/prompts.json @@ -104,6 +104,10 @@ "label": "프롬프트 향상", "description": "입력에 맞춤화된 제안이나 개선을 얻기 위해 프롬프트 향상을 사용하세요. 이를 통해 Zoo가 의도를 이해하고 최상의 응답을 제공할 수 있습니다. 채팅에서 ✨ 아이콘을 통해 이용 가능합니다." }, + "COMMIT_MESSAGE": { + "label": "커밋 메시지", + "description": "변경 사항을 커밋 메시지로 요약합니다. 소스 제어 패널의 Zoo Code 아이콘으로 사용할 수 있으며, 결과를 커밋 입력란에 바로 작성합니다." + }, "CONDENSE": { "label": "컨텍스트 압축", "description": "토큰 제한을 관리하기 위해 대화 컨텍스트를 압축하는 방법을 구성합니다. 이 프롬프트는 수동 및 자동 컨텍스트 압축 작업 모두에 사용됩니다." diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 27e8493bd4..0114f48aec 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}} 문서", + "commitMessageModel": { + "label": "커밋 메시지 모델", + "description": "소스 제어 패널에서 커밋 메시지를 생성하는 데 사용하는 프로필입니다. 보통 작고 빠른 모델이면 충분합니다. 선택하지 않으면 현재 활성 프로필을 사용합니다.", + "useCurrentConfig": "현재 선택된 API 구성 사용" + }, "configProfile": "구성 프로필", "description": "다양한 API 구성을 저장하여 제공자와 설정 간에 빠르게 전환할 수 있습니다.", "apiProvider": "API 제공자", diff --git a/webview-ui/src/i18n/locales/nl/prompts.json b/webview-ui/src/i18n/locales/nl/prompts.json index 3a0a7d5445..b0adca2e3b 100644 --- a/webview-ui/src/i18n/locales/nl/prompts.json +++ b/webview-ui/src/i18n/locales/nl/prompts.json @@ -104,6 +104,10 @@ "label": "Prompt verbeteren", "description": "Gebruik promptverbetering om op maat gemaakte suggesties of verbeteringen voor je invoer te krijgen. Zo begrijpt Zoo je intentie en krijg je de best mogelijke antwoorden. Beschikbaar via het ✨-icoon in de chat." }, + "COMMIT_MESSAGE": { + "label": "Commitbericht", + "description": "Vat je wijzigingen samen in een commitbericht. Beschikbaar via het Zoo Code-pictogram in het paneel Broncodebeheer, dat het resultaat rechtstreeks in het commitveld schrijft." + }, "CONDENSE": { "label": "Contextcondensatie", "description": "Configureer hoe de gesprekscontext wordt gecondenseerd om tokenlimieten te beheren.Deze prompt wordt gebruikt voor zowel handmatige als automatische contextcondensatiebewerkingen." diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 394cdd48f2..f25ece61b6 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}} documentatie", + "commitMessageModel": { + "label": "Model voor commitberichten", + "description": "Profiel dat wordt gebruikt om commitberichten te genereren vanuit het paneel Broncodebeheer. Een klein, snel model volstaat meestal. Laat leeg om het actieve profiel te gebruiken.", + "useCurrentConfig": "Momenteel geselecteerde API-configuratie gebruiken" + }, "configProfile": "Configuratieprofiel", "description": "Sla verschillende API-configuraties op om snel te wisselen tussen providers en instellingen.", "apiProvider": "API-provider", diff --git a/webview-ui/src/i18n/locales/pl/prompts.json b/webview-ui/src/i18n/locales/pl/prompts.json index 02d72ff510..d0782ac11d 100644 --- a/webview-ui/src/i18n/locales/pl/prompts.json +++ b/webview-ui/src/i18n/locales/pl/prompts.json @@ -104,6 +104,10 @@ "label": "Ulepsz podpowiedź", "description": "Użyj ulepszenia podpowiedzi, aby uzyskać dostosowane sugestie lub ulepszenia dla swoich danych wejściowych. Zapewnia to, że Zoo rozumie Twoje intencje i dostarcza najlepsze możliwe odpowiedzi. Dostępne za pośrednictwem ikony ✨ w czacie." }, + "COMMIT_MESSAGE": { + "label": "Komunikat zatwierdzenia", + "description": "Podsumowuje Twoje zmiany w komunikacie zatwierdzenia. Dostępne przez ikonę Zoo Code w panelu kontroli źródła, która zapisuje wynik bezpośrednio w polu komunikatu zatwierdzenia." + }, "CONDENSE": { "label": "Kondensacja kontekstu", "description": "Skonfiguruj, w jaki sposób kontekst rozmowy jest kondensowany w celu zarządzania limitami tokenów. Ten monit jest używany zarówno do ręcznych, jak i automatycznych operacji kondensacji kontekstu." diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 864e4ffde1..47e3a6c7d9 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Dokumentacja {{provider}}", + "commitMessageModel": { + "label": "Model komunikatów zatwierdzenia", + "description": "Profil używany do generowania komunikatów zatwierdzenia z panelu kontroli źródła. Zwykle wystarczy mały, szybki model. Pozostaw niewybrane, aby użyć aktywnego profilu.", + "useCurrentConfig": "Użyj aktualnie wybranej konfiguracji API" + }, "configProfile": "Profil konfiguracji", "description": "Zapisz różne konfiguracje API, aby szybko przełączać się między dostawcami i ustawieniami.", "apiProvider": "Dostawca API", diff --git a/webview-ui/src/i18n/locales/pt-BR/prompts.json b/webview-ui/src/i18n/locales/pt-BR/prompts.json index 3ccc978bd8..35d06b1899 100644 --- a/webview-ui/src/i18n/locales/pt-BR/prompts.json +++ b/webview-ui/src/i18n/locales/pt-BR/prompts.json @@ -104,6 +104,10 @@ "label": "Aprimorar Prompt", "description": "Use o aprimoramento de prompt para obter sugestões ou melhorias personalizadas para suas entradas. Isso garante que o Zoo entenda sua intenção e forneça as melhores respostas possíveis. Disponível através do ícone ✨ no chat." }, + "COMMIT_MESSAGE": { + "label": "Mensagem de commit", + "description": "Resume suas alterações em uma mensagem de commit. Disponível pelo ícone do Zoo Code no painel de Controle do Código-Fonte, que escreve o resultado diretamente no campo da mensagem de commit." + }, "CONDENSE": { "label": "Condensação de Contexto", "description": "Configure como o contexto da conversa é condensado para gerenciar os limites de token. Este prompt é usado para operações de condensação de contexto manuais e automáticas." diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index a1948a0218..b95f73583f 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Documentação do {{provider}}", + "commitMessageModel": { + "label": "Modelo para mensagens de commit", + "description": "Perfil usado para gerar mensagens de commit a partir do painel de Controle do Código-Fonte. Um modelo pequeno e rápido costuma ser suficiente. Deixe sem seleção para usar o perfil ativo.", + "useCurrentConfig": "Usar a configuração de API selecionada no momento" + }, "configProfile": "Perfil de configuração", "description": "Salve diferentes configurações de API para alternar rapidamente entre provedores e configurações.", "apiProvider": "Provedor de API", diff --git a/webview-ui/src/i18n/locales/ru/prompts.json b/webview-ui/src/i18n/locales/ru/prompts.json index 1863bebf9d..2c4051c961 100644 --- a/webview-ui/src/i18n/locales/ru/prompts.json +++ b/webview-ui/src/i18n/locales/ru/prompts.json @@ -104,6 +104,10 @@ "label": "Улучшить промпт", "description": "Используйте улучшение промпта для получения индивидуальных предложений или улучшений ваших запросов. Это гарантирует, что Zoo правильно поймет ваш запрос и даст лучший ответ. Доступно через ✨ в чате." }, + "COMMIT_MESSAGE": { + "label": "Сообщение коммита", + "description": "Кратко описывает ваши изменения в виде сообщения коммита. Доступно через значок Zoo Code на панели системы управления версиями, который записывает результат прямо в поле сообщения коммита." + }, "CONDENSE": { "label": "Сжатие контекста", "description": "Настройте, как сжимается контекст беседы для управления лимитами токенов. Этот запрос используется как для ручных, так и для автоматических операций сжатия контекста." diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index f36fe62539..95d43efb37 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Документация {{provider}}", + "commitMessageModel": { + "label": "Модель для сообщений коммитов", + "description": "Профиль, используемый для генерации сообщений коммитов с панели системы управления версиями. Обычно достаточно небольшой быстрой модели. Оставьте пустым, чтобы использовать активный профиль.", + "useCurrentConfig": "Использовать текущую выбранную конфигурацию API" + }, "configProfile": "Профиль конфигурации", "description": "Сохраняйте различные конфигурации API для быстрого переключения между провайдерами и настройками.", "apiProvider": "Провайдер API", diff --git a/webview-ui/src/i18n/locales/tr/prompts.json b/webview-ui/src/i18n/locales/tr/prompts.json index e0288355c2..6656e1f61b 100644 --- a/webview-ui/src/i18n/locales/tr/prompts.json +++ b/webview-ui/src/i18n/locales/tr/prompts.json @@ -104,6 +104,10 @@ "label": "Promptu Geliştir", "description": "Girdileriniz için özel öneriler veya iyileştirmeler almak için prompt geliştirmeyi kullanın. Bu, Zoo'nun niyetinizi anlamasını ve mümkün olan en iyi yanıtları sağlamasını garanti eder. Sohbetteki ✨ simgesi aracılığıyla kullanılabilir." }, + "COMMIT_MESSAGE": { + "label": "Commit Mesajı", + "description": "Değişikliklerinizi bir commit mesajında özetler. Kaynak Denetimi panelindeki Zoo Code simgesiyle kullanılabilir ve sonucu doğrudan commit giriş kutusuna yazar." + }, "CONDENSE": { "label": "Bağlam Yoğunlaştırma", "description": "Jeton sınırlarını yönetmek için konuşma bağlamının nasıl yoğunlaştırılacağını yapılandırın. Bu istem, hem manuel hem de otomatik bağlam yoğunlaştırma işlemleri için kullanılır." diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 9099677679..e0e24dcde8 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}} Dokümantasyonu", + "commitMessageModel": { + "label": "Commit Mesajı Modeli", + "description": "Kaynak Denetimi panelinden commit mesajları oluşturmak için kullanılan profil. Genellikle küçük ve hızlı bir model yeterlidir. Etkin profili kullanmak için seçimsiz bırakın.", + "useCurrentConfig": "Şu anda seçili API yapılandırmasını kullan" + }, "configProfile": "Yapılandırma Profili", "description": "Sağlayıcılar ve ayarlar arasında hızlıca geçiş yapmak için farklı API yapılandırmalarını kaydedin.", "apiProvider": "API Sağlayıcı", diff --git a/webview-ui/src/i18n/locales/vi/prompts.json b/webview-ui/src/i18n/locales/vi/prompts.json index ab5dbb899c..ee601b7ceb 100644 --- a/webview-ui/src/i18n/locales/vi/prompts.json +++ b/webview-ui/src/i18n/locales/vi/prompts.json @@ -104,6 +104,10 @@ "label": "Nâng cao lời nhắc", "description": "Sử dụng nâng cao lời nhắc để nhận đề xuất hoặc cải tiến phù hợp cho đầu vào của bạn. Điều này đảm bảo Zoo hiểu ý định của bạn và cung cấp phản hồi tốt nhất có thể. Có sẵn thông qua biểu tượng ✨ trong chat." }, + "COMMIT_MESSAGE": { + "label": "Thông điệp commit", + "description": "Tóm tắt các thay đổi của bạn thành một thông điệp commit. Có sẵn qua biểu tượng Zoo Code trong bảng Source Control, ghi kết quả trực tiếp vào ô nhập commit." + }, "CONDENSE": { "label": "Cô đọng ngữ cảnh", "description": "Định cấu hình cách cô đọng ngữ cảnh cuộc trò chuyện để quản lý giới hạn token. Lời nhắc này được sử dụng cho cả hoạt động cô đọng ngữ cảnh thủ công và tự động." diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index c66b236165..13f5426e6c 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "Tài liệu {{provider}}", + "commitMessageModel": { + "label": "Mô hình tạo thông điệp commit", + "description": "Hồ sơ dùng để tạo thông điệp commit từ bảng Source Control. Một mô hình nhỏ và nhanh thường là đủ. Để trống để dùng hồ sơ đang hoạt động.", + "useCurrentConfig": "Dùng cấu hình API đang được chọn" + }, "configProfile": "Hồ sơ cấu hình", "description": "Lưu các cấu hình API khác nhau để nhanh chóng chuyển đổi giữa các nhà cung cấp và cài đặt.", "apiProvider": "Nhà cung cấp API", diff --git a/webview-ui/src/i18n/locales/zh-CN/prompts.json b/webview-ui/src/i18n/locales/zh-CN/prompts.json index 9d3f9ee9cf..991a0e6165 100644 --- a/webview-ui/src/i18n/locales/zh-CN/prompts.json +++ b/webview-ui/src/i18n/locales/zh-CN/prompts.json @@ -104,6 +104,10 @@ "label": "增强提示词", "description": "优化提示获取更好回答(点击✨使用)" }, + "COMMIT_MESSAGE": { + "label": "提交信息", + "description": "将你的更改总结为一条提交信息。可通过源代码管理面板中的 Zoo Code 图标使用,结果会直接写入提交输入框。" + }, "CONDENSE": { "label": "上下文压缩", "description": "配置如何压缩对话上下文以管理令牌限制。此提示用于手动和自动上下文压缩操作。" diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 22742e0e0e..1b0d394a07 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -356,6 +356,11 @@ }, "providers": { "providerDocumentation": "{{provider}} 文档", + "commitMessageModel": { + "label": "提交信息模型", + "description": "用于从源代码管理面板生成提交信息的配置文件。通常小而快的模型就足够了。留空则使用当前激活的配置文件。", + "useCurrentConfig": "使用当前选择的 API 配置" + }, "configProfile": "配置文件", "description": "保存多组API配置便于快速切换", "apiProvider": "API提供商", diff --git a/webview-ui/src/i18n/locales/zh-TW/prompts.json b/webview-ui/src/i18n/locales/zh-TW/prompts.json index 962a4bf42e..4130f95fd0 100644 --- a/webview-ui/src/i18n/locales/zh-TW/prompts.json +++ b/webview-ui/src/i18n/locales/zh-TW/prompts.json @@ -103,6 +103,10 @@ "label": "強化提示詞", "description": "使用提示詞強化功能,為您的輸入取得量身打造的建議或改進。這能確保 Zoo 理解您的意圖並提供最佳回應。可透過聊天室中的 ✨ 圖示使用。" }, + "COMMIT_MESSAGE": { + "label": "提交訊息", + "description": "將你的變更摘要成一則提交訊息。可透過原始檔控制面板中的 Zoo Code 圖示使用,結果會直接寫入提交輸入框。" + }, "CONDENSE": { "label": "上下文壓縮", "description": "設定對話內容的壓縮方式以管理 Token 限制。此提示用於手動和自動的上下文壓縮作業。" diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 4255a2e697..8cb8efcc2f 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -383,6 +383,11 @@ }, "providers": { "providerDocumentation": "{{provider}} 說明文件", + "commitMessageModel": { + "label": "提交訊息模型", + "description": "用於從原始檔控制面板產生提交訊息的設定檔。通常小而快的模型就足夠了。留空則使用目前啟用的設定檔。", + "useCurrentConfig": "使用目前選取的 API 設定" + }, "configProfile": "設定檔", "description": "儲存不同的 API 設定以快速切換供應商和設定。", "apiProvider": "API 供應商",