fix(jetbrains): show git install banner

This commit is contained in:
kirillk
2026-08-14 16:33:38 -04:00
parent 430306e37d
commit 3f676e588b
25 changed files with 223 additions and 6 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
"@kilocode/kilo-jetbrains": patch
---
Show synchronized Agent Manager and worktree editor banners when GitHub CLI PR status checks need installation or authorization.
Show synchronized Agent Manager and worktree editor banners when Git or GitHub CLI PR status checks need installation or authorization.
@@ -168,6 +168,7 @@ class KiloWorktreeRpcApiImpl : KiloWorktreeRpcApi {
when (prError(out.stderr)) {
GhAvailability.UNAUTH -> status = GhAvailability.UNAUTH
GhAvailability.MISSING -> status = GhAvailability.MISSING
GhAvailability.GIT_MISSING -> status = GhAvailability.GIT_MISSING
GhAvailability.OK -> Unit
}
return@parallel null
@@ -192,6 +193,7 @@ class KiloWorktreeRpcApiImpl : KiloWorktreeRpcApi {
val base = Path.of(directory).normalize()
val ref = parsePrUrl(url) ?: return@withContext CreateWorktreeResultDto(error = "Enter a valid GitHub pull request URL")
when (ghAvailable(base)) {
GhAvailability.GIT_MISSING -> return@withContext CreateWorktreeResultDto(error = "Git is not installed")
GhAvailability.MISSING -> return@withContext CreateWorktreeResultDto(error = "GitHub CLI (gh) is not installed")
GhAvailability.UNAUTH -> return@withContext CreateWorktreeResultDto(error = "GitHub CLI (gh) is not authorized")
GhAvailability.OK -> Unit
@@ -425,6 +427,13 @@ class KiloWorktreeRpcApiImpl : KiloWorktreeRpcApi {
}
val start = System.currentTimeMillis()
LOG.info("gh probe start reason=$reason dir=$root")
val git = runGit(root, "--version")
if (!git.ok) {
val value = GhAvailability.GIT_MISSING
ghCache = Timed(System.currentTimeMillis(), value)
LOG.info("gh probe result reason=$reason value=$value exit=${git.exit} ms=${System.currentTimeMillis() - start} stderr=${snippet(git.stderr)}")
return@synchronized value
}
val res = runGh(root, "auth", "status")
val value = if (res.ok) GhAvailability.OK else classifyGhError(res.stderr.ifBlank { res.stdout })
ghCache = Timed(System.currentTimeMillis(), value)
@@ -49,12 +49,14 @@ internal class GhBanner(
private fun sync(next: GhAvailability) {
clear()
text(when (next) {
GhAvailability.GIT_MISSING -> KiloBundle.message("worktree.git.missing.content")
GhAvailability.MISSING -> KiloBundle.message("worktree.gh.missing.content")
GhAvailability.UNAUTH -> KiloBundle.message("worktree.gh.unauth.content")
GhAvailability.OK -> ""
})
createActionLabel(when (next) {
GhAvailability.MISSING -> KiloBundle.message("worktree.gh.install")
GhAvailability.GIT_MISSING -> KiloBundle.message("worktree.gh.learnMore")
GhAvailability.MISSING -> KiloBundle.message("worktree.gh.learnMore")
GhAvailability.UNAUTH -> KiloBundle.message("worktree.gh.authorize")
GhAvailability.OK -> ""
}) { runAction() }
@@ -67,6 +69,10 @@ internal class GhBanner(
}
private fun runAction() {
if (state == GhAvailability.GIT_MISSING) {
BrowserUtil.browse("https://git-scm.com/downloads")
return
}
if (state == GhAvailability.MISSING) {
BrowserUtil.browse("https://cli.github.com/")
return
@@ -184,17 +184,27 @@ class GhStatusCoordinator(
GhAvailability.OK -> NORMAL
GhAvailability.UNAUTH -> FAST
GhAvailability.MISSING -> SLOW
GhAvailability.GIT_MISSING -> SLOW
}
@RequiresEdt
private fun notify(project: Project?, value: GhAvailability) {
val target = project ?: ProjectManager.getInstance().openProjects.firstOrNull { !it.isDefault }
if (value == GhAvailability.GIT_MISSING) {
KiloNotifications.suggestion(
target,
KiloBundle.message("worktree.git.missing.title"),
KiloBundle.message("worktree.git.missing.content"),
KiloBundle.message("worktree.gh.learnMore"),
) { BrowserUtil.browse("https://git-scm.com/downloads") }
return
}
if (value == GhAvailability.MISSING) {
KiloNotifications.suggestion(
target,
KiloBundle.message("worktree.gh.missing.title"),
KiloBundle.message("worktree.gh.missing.content"),
KiloBundle.message("worktree.gh.install"),
KiloBundle.message("worktree.gh.learnMore"),
) { BrowserUtil.browse("https://cli.github.com/") }
return
}
@@ -394,6 +394,8 @@ worktree.pr.tooltip.open=Click to open the pull request in your browser.
worktree.gh.missing.title=GitHub CLI not found
worktree.gh.missing.content=Install gh to show pull request badges for worktrees.
worktree.gh.install=Install
worktree.git.missing.title=Git not found
worktree.git.missing.content=Install Git to show worktree stats and pull request badges.
worktree.gh.unauth.title=GitHub CLI not authorized
worktree.gh.unauth.content=Authorize gh to show pull request badges for worktrees.
worktree.gh.authorize=Authorize
@@ -137,6 +137,16 @@ history.error.local.delete=فشل حذف الجلسة
history.error.local.rename=فشل إعادة تسمية الجلسة
history.error.cloud.delete=لا يمكن حذف جلسات السحابة بعد
worktree.gh.missing.title=لم يتم العثور على GitHub CLI
worktree.gh.missing.content=ثبّت gh لعرض شارات طلبات السحب لفروع العمل.
worktree.gh.install=تثبيت
worktree.git.missing.title=لم يتم العثور على Git
worktree.git.missing.content=ثبّت Git لعرض إحصاءات فروع العمل وشارات طلبات السحب.
worktree.gh.unauth.title=GitHub CLI غير مخوّل
worktree.gh.unauth.content=خوّل gh لعرض شارات طلبات السحب لفروع العمل.
worktree.gh.authorize=تخويل
worktree.gh.learnMore=معرفة المزيد
action.Kilo.Settings.text=الإعدادات
action.Kilo.Settings.description=إعدادات Kilo Code
action.Kilo.NewSession.text=جلسة جديدة
@@ -137,6 +137,16 @@ history.error.local.delete=Brisanje sesije neuspješno
history.error.local.rename=Preimenovanje sesije neuspješno
history.error.cloud.delete=Sesije iz oblaka još uvijek nije moguće brisati
worktree.gh.missing.title=GitHub CLI nije pronađen
worktree.gh.missing.content=Instalirajte gh za prikaz oznaka pull requestova za radna stabla.
worktree.gh.install=Instaliraj
worktree.git.missing.title=Git nije pronađen
worktree.git.missing.content=Instalirajte Git za prikaz statistike radnih stabala i oznaka pull requestova.
worktree.gh.unauth.title=GitHub CLI nije autorizovan
worktree.gh.unauth.content=Autorizujte gh za prikaz oznaka pull requestova za radna stabla.
worktree.gh.authorize=Autorizuj
worktree.gh.learnMore=Saznaj više
action.Kilo.Settings.text=Postavke
action.Kilo.Settings.description=Postavke Kilo Code
action.Kilo.NewSession.text=Nova sesija
@@ -137,6 +137,16 @@ history.error.local.delete=Kunne ikke slette session
history.error.local.rename=Kunne ikke omdøbe session
history.error.cloud.delete=Skysessioner kan endnu ikke slettes
worktree.gh.missing.title=GitHub CLI blev ikke fundet
worktree.gh.missing.content=Installer gh for at vise pull request-badges for worktrees.
worktree.gh.install=Installer
worktree.git.missing.title=Git blev ikke fundet
worktree.git.missing.content=Installer Git for at vise worktree-statistik og pull request-badges.
worktree.gh.unauth.title=GitHub CLI er ikke autoriseret
worktree.gh.unauth.content=Autoriser gh for at vise pull request-badges for worktrees.
worktree.gh.authorize=Autoriser
worktree.gh.learnMore=Få mere at vide
action.Kilo.Settings.text=Indstillinger
action.Kilo.Settings.description=Kilo Code-indstillinger
action.Kilo.NewSession.text=Ny session
@@ -137,6 +137,16 @@ history.error.local.delete=Sitzung konnte nicht gelöscht werden
history.error.local.rename=Sitzung konnte nicht umbenannt werden
history.error.cloud.delete=Cloud-Sitzungen können noch nicht gelöscht werden
worktree.gh.missing.title=GitHub CLI nicht gefunden
worktree.gh.missing.content=Installiere gh, um Pull-Request-Badges für Worktrees anzuzeigen.
worktree.gh.install=Installieren
worktree.git.missing.title=Git nicht gefunden
worktree.git.missing.content=Installiere Git, um Worktree-Statistiken und Pull-Request-Badges anzuzeigen.
worktree.gh.unauth.title=GitHub CLI ist nicht autorisiert
worktree.gh.unauth.content=Autorisiere gh, um Pull-Request-Badges für Worktrees anzuzeigen.
worktree.gh.authorize=Autorisieren
worktree.gh.learnMore=Mehr erfahren
action.Kilo.Settings.text=Einstellungen
action.Kilo.Settings.description=Kilo Code Einstellungen
action.Kilo.NewSession.text=Neue Sitzung
@@ -137,6 +137,16 @@ history.error.local.delete=Error al eliminar la sesión
history.error.local.rename=Error al renombrar la sesión
history.error.cloud.delete=Las sesiones en la nube no se pueden eliminar aún
worktree.gh.missing.title=No se encontró GitHub CLI
worktree.gh.missing.content=Instala gh para mostrar insignias de pull request para los worktrees.
worktree.gh.install=Instalar
worktree.git.missing.title=No se encontró Git
worktree.git.missing.content=Instala Git para mostrar estadísticas de worktrees e insignias de pull request.
worktree.gh.unauth.title=GitHub CLI no está autorizado
worktree.gh.unauth.content=Autoriza gh para mostrar insignias de pull request para los worktrees.
worktree.gh.authorize=Autorizar
worktree.gh.learnMore=Más información
action.Kilo.Settings.text=Configuración
action.Kilo.Settings.description=Configuración de Kilo Code
action.Kilo.NewSession.text=Nueva sesión
@@ -137,6 +137,16 @@ history.error.local.delete=Échec de la suppression de la session
history.error.local.rename=Échec du renommage de la session
history.error.cloud.delete=Les sessions cloud ne peuvent pas encore être supprimées
worktree.gh.missing.title=GitHub CLI introuvable
worktree.gh.missing.content=Installez gh pour afficher les badges de pull request des worktrees.
worktree.gh.install=Installer
worktree.git.missing.title=Git introuvable
worktree.git.missing.content=Installez Git pour afficher les statistiques des worktrees et les badges de pull request.
worktree.gh.unauth.title=GitHub CLI nest pas autorisé
worktree.gh.unauth.content=Autorisez gh pour afficher les badges de pull request des worktrees.
worktree.gh.authorize=Autoriser
worktree.gh.learnMore=En savoir plus
action.Kilo.Settings.text=Paramètres
action.Kilo.Settings.description=Paramètres de Kilo Code
action.Kilo.NewSession.text=Nouvelle session
@@ -137,6 +137,16 @@ history.error.local.delete=セッションの削除に失敗しました
history.error.local.rename=セッションの変名に失敗しました
history.error.cloud.delete=クラウドセッションはまだ削除できません
worktree.gh.missing.title=GitHub CLI が見つかりません
worktree.gh.missing.content=worktree のプルリクエストバッジを表示するには gh をインストールしてください。
worktree.gh.install=インストール
worktree.git.missing.title=Git が見つかりません
worktree.git.missing.content=worktree の統計情報とプルリクエストバッジを表示するには Git をインストールしてください。
worktree.gh.unauth.title=GitHub CLI が認証されていません
worktree.gh.unauth.content=worktree のプルリクエストバッジを表示するには gh を認証してください。
worktree.gh.authorize=認証
worktree.gh.learnMore=詳細
action.Kilo.Settings.text=設定
action.Kilo.Settings.description=Kilo Codeの設定
action.Kilo.NewSession.text=新しいセッション
@@ -137,6 +137,16 @@ history.error.local.delete=세션을 삭제하지 못했습니다
history.error.local.rename=세션의 이름을 바꾸지 못했습니다
history.error.cloud.delete=클라우드 세션은 아직 삭제할 수 없습니다
worktree.gh.missing.title=GitHub CLI를 찾을 수 없음
worktree.gh.missing.content=워크트리의 pull request 배지를 표시하려면 gh를 설치하세요.
worktree.gh.install=설치
worktree.git.missing.title=Git을 찾을 수 없음
worktree.git.missing.content=워크트리 통계와 pull request 배지를 표시하려면 Git을 설치하세요.
worktree.gh.unauth.title=GitHub CLI가 인증되지 않음
worktree.gh.unauth.content=워크트리의 pull request 배지를 표시하려면 gh를 인증하세요.
worktree.gh.authorize=인증
worktree.gh.learnMore=자세히 알아보기
action.Kilo.Settings.text=설정
action.Kilo.Settings.description=Kilo Code 설정
action.Kilo.NewSession.text=새 세션
@@ -137,6 +137,16 @@ history.error.local.delete=Verwijderen van sessie mislukt
history.error.local.rename=Hernoemen van sessie mislukt
history.error.cloud.delete=Cloudsessies kunnen nog niet worden verwijderd
worktree.gh.missing.title=GitHub CLI niet gevonden
worktree.gh.missing.content=Installeer gh om pull request-badges voor worktrees te tonen.
worktree.gh.install=Installeren
worktree.git.missing.title=Git niet gevonden
worktree.git.missing.content=Installeer Git om worktree-statistieken en pull request-badges te tonen.
worktree.gh.unauth.title=GitHub CLI is niet geautoriseerd
worktree.gh.unauth.content=Autoriseer gh om pull request-badges voor worktrees te tonen.
worktree.gh.authorize=Autoriseren
worktree.gh.learnMore=Meer informatie
action.Kilo.Settings.text=Instellingen
action.Kilo.Settings.description=Kilo Code-instellingen
action.Kilo.NewSession.text=Nieuwe sessie
@@ -142,6 +142,16 @@ history.error.local.delete=Kunne ikke slette økt
history.error.local.rename=Kunne ikke gi økten nytt navn
history.error.cloud.delete=Sky-økter kan ikke slettes ennå
worktree.gh.missing.title=GitHub CLI ble ikke funnet
worktree.gh.missing.content=Installer gh for å vise pull request-merker for worktrees.
worktree.gh.install=Installer
worktree.git.missing.title=Git ble ikke funnet
worktree.git.missing.content=Installer Git for å vise worktree-statistikk og pull request-merker.
worktree.gh.unauth.title=GitHub CLI er ikke autorisert
worktree.gh.unauth.content=Autoriser gh for å vise pull request-merker for worktrees.
worktree.gh.authorize=Autoriser
worktree.gh.learnMore=Finn ut mer
action.Kilo.Settings.text=Innstillinger
action.Kilo.Settings.description=Kilo Code-innstillinger
action.Kilo.NewSession.text=Ny økt
@@ -142,6 +142,16 @@ history.error.local.delete=Nie udało się usunąć sesji
history.error.local.rename=Nie udało się zmienić nazwy sesji
history.error.cloud.delete=Sesji w chmurze nie można jeszcze usuwać
worktree.gh.missing.title=Nie znaleziono GitHub CLI
worktree.gh.missing.content=Zainstaluj gh, aby wyświetlać odznaki pull requestów dla worktree.
worktree.gh.install=Zainstaluj
worktree.git.missing.title=Nie znaleziono Git
worktree.git.missing.content=Zainstaluj Git, aby wyświetlać statystyki worktree i odznaki pull requestów.
worktree.gh.unauth.title=GitHub CLI nie jest autoryzowany
worktree.gh.unauth.content=Autoryzuj gh, aby wyświetlać odznaki pull requestów dla worktree.
worktree.gh.authorize=Autoryzuj
worktree.gh.learnMore=Dowiedz się więcej
action.Kilo.Settings.text=Ustawienia
action.Kilo.Settings.description=Ustawienia Kilo Code
action.Kilo.NewSession.text=Nowa sesja
@@ -142,6 +142,16 @@ history.error.local.delete=Falha ao excluir a sessão
history.error.local.rename=Falha ao renomear a sessão
history.error.cloud.delete=As sessões na nuvem ainda não podem ser excluídas
worktree.gh.missing.title=GitHub CLI não encontrado
worktree.gh.missing.content=Instale o gh para mostrar emblemas de pull request para worktrees.
worktree.gh.install=Instalar
worktree.git.missing.title=Git não encontrado
worktree.git.missing.content=Instale o Git para mostrar estatísticas de worktrees e emblemas de pull request.
worktree.gh.unauth.title=GitHub CLI não autorizado
worktree.gh.unauth.content=Autorize o gh para mostrar emblemas de pull request para worktrees.
worktree.gh.authorize=Autorizar
worktree.gh.learnMore=Saiba mais
action.Kilo.Settings.text=Configurações
action.Kilo.Settings.description=Configurações do Kilo Code
action.Kilo.NewSession.text=Nova sessão
@@ -142,6 +142,16 @@ history.error.local.delete=Ошибка удаления сессии
history.error.local.rename=Ошибка переименования сессии
history.error.cloud.delete=Облачные сессии пока нельзя удалить
worktree.gh.missing.title=GitHub CLI не найден
worktree.gh.missing.content=Установите gh, чтобы показывать значки pull request для worktree.
worktree.gh.install=Установить
worktree.git.missing.title=Git не найден
worktree.git.missing.content=Установите Git, чтобы показывать статистику worktree и значки pull request.
worktree.gh.unauth.title=GitHub CLI не авторизован
worktree.gh.unauth.content=Авторизуйте gh, чтобы показывать значки pull request для worktree.
worktree.gh.authorize=Авторизовать
worktree.gh.learnMore=Подробнее
action.Kilo.Settings.text=Настройки
action.Kilo.Settings.description=Настройки Kilo Code
action.Kilo.NewSession.text=Новая сессия
@@ -142,6 +142,16 @@ history.error.local.delete=ไม่สามารถลบเซสชัน
history.error.local.rename=ไม่สามารถเปลี่ยนชื่อเซสชัน
history.error.cloud.delete=ยังไม่สามารถลบเซสชันคลาวด์ได้
worktree.gh.missing.title=ไม่พบ GitHub CLI
worktree.gh.missing.content=ติดตั้ง gh เพื่อแสดงป้าย pull request สำหรับ worktree
worktree.gh.install=ติดตั้ง
worktree.git.missing.title=ไม่พบ Git
worktree.git.missing.content=ติดตั้ง Git เพื่อแสดงสถิติ worktree และป้าย pull request
worktree.gh.unauth.title=GitHub CLI ยังไม่ได้รับอนุญาต
worktree.gh.unauth.content=อนุญาต gh เพื่อแสดงป้าย pull request สำหรับ worktree
worktree.gh.authorize=อนุญาต
worktree.gh.learnMore=เรียนรู้เพิ่มเติม
action.Kilo.Settings.text=การตั้งค่า
action.Kilo.Settings.description=การตั้งค่า Kilo Code
action.Kilo.NewSession.text=เซสชันใหม่
@@ -142,6 +142,16 @@ history.error.local.delete=Oturum silinemedi
history.error.local.rename=Oturum yeniden adlandırılamadı
history.error.cloud.delete=Bulut oturumları henüz silinemiyor
worktree.gh.missing.title=GitHub CLI bulunamadı
worktree.gh.missing.content=Worktree pull request rozetlerini göstermek için gh yükleyin.
worktree.gh.install=Yükle
worktree.git.missing.title=Git bulunamadı
worktree.git.missing.content=Worktree istatistiklerini ve pull request rozetlerini göstermek için Git yükleyin.
worktree.gh.unauth.title=GitHub CLI yetkilendirilmemiş
worktree.gh.unauth.content=Worktree pull request rozetlerini göstermek için gh yetkilendirin.
worktree.gh.authorize=Yetkilendir
worktree.gh.learnMore=Daha fazla bilgi
action.Kilo.Settings.text=Ayarlar
action.Kilo.Settings.description=Kilo Code ayarları
action.Kilo.NewSession.text=Yeni oturum
@@ -137,6 +137,16 @@ history.error.local.delete=Помилка видалення сесії
history.error.local.rename=Помилка перейменування сесії
history.error.cloud.delete=Хмарні сесії поки не можна видалити
worktree.gh.missing.title=GitHub CLI не знайдено
worktree.gh.missing.content=Установіть gh, щоб показувати значки pull request для worktree.
worktree.gh.install=Установити
worktree.git.missing.title=Git не знайдено
worktree.git.missing.content=Установіть Git, щоб показувати статистику worktree і значки pull request.
worktree.gh.unauth.title=GitHub CLI не авторизовано
worktree.gh.unauth.content=Авторизуйте gh, щоб показувати значки pull request для worktree.
worktree.gh.authorize=Авторизувати
worktree.gh.learnMore=Докладніше
action.Kilo.Settings.text=Налаштування
action.Kilo.Settings.description=Налаштування Kilo Code
action.Kilo.NewSession.text=Нова сесія
@@ -137,6 +137,16 @@ history.error.local.delete=删除会话失败
history.error.local.rename=重命名会话失败
history.error.cloud.delete=云端会话暂无法删除
worktree.gh.missing.title=未找到 GitHub CLI
worktree.gh.missing.content=安装 gh 以显示 worktree 的 pull request 徽章。
worktree.gh.install=安装
worktree.git.missing.title=未找到 Git
worktree.git.missing.content=安装 Git 以显示 worktree 统计信息和 pull request 徽章。
worktree.gh.unauth.title=GitHub CLI 未授权
worktree.gh.unauth.content=授权 gh 以显示 worktree 的 pull request 徽章。
worktree.gh.authorize=授权
worktree.gh.learnMore=了解更多
action.Kilo.Settings.text=设置
action.Kilo.Settings.description=Kilo Code 设置
action.Kilo.NewSession.text=新建会话
@@ -137,6 +137,16 @@ history.error.local.delete=刪除工作階段失敗
history.error.local.rename=重命名工作階段失敗
history.error.cloud.delete=雲端工作階段暫時無法刪除
worktree.gh.missing.title=找不到 GitHub CLI
worktree.gh.missing.content=安裝 gh 以顯示 worktree 的 pull request 徽章。
worktree.gh.install=安裝
worktree.git.missing.title=找不到 Git
worktree.git.missing.content=安裝 Git 以顯示 worktree 統計資料和 pull request 徽章。
worktree.gh.unauth.title=GitHub CLI 未授權
worktree.gh.unauth.content=授權 gh 以顯示 worktree 的 pull request 徽章。
worktree.gh.authorize=授權
worktree.gh.learnMore=瞭解更多
action.Kilo.Settings.text=設定
action.Kilo.Settings.description=Kilo Code 設定
action.Kilo.NewSession.text=新建工作階段
@@ -47,8 +47,18 @@ class GhBannerTest : BasePlatformTestCase() {
assertTrue(edt { banner.isVisible })
assertEquals("Install gh to show pull request badges for worktrees.", edt { banner.text })
assertNotNull(edt { links(banner).singleOrNull { it.text == "Install" } })
assertNull(edt { links(banner).singleOrNull { it.text == "Learn more" && it.isVisible } })
assertNotNull(edt { links(banner).singleOrNull { it.text == "Learn more" } })
}
fun `test banner shows git install guidance`() {
edt { service.report(project, GhAvailability.GIT_MISSING) }
pump()
val banner = edt { GhBanner(project, testRootDisposable) }
assertTrue(edt { banner.isVisible })
assertEquals("Install Git to show worktree stats and pull request badges.", edt { banner.text })
assertNotNull(edt { links(banner).singleOrNull { it.text == "Learn more" } })
}
fun `test banner hides immediately when coordinator reports ok`() {
@@ -42,7 +42,7 @@ data class WorktreePrDto(
)
@Serializable
enum class GhAvailability { OK, MISSING, UNAUTH }
enum class GhAvailability { OK, MISSING, UNAUTH, GIT_MISSING }
@Serializable
data class WorktreePrListDto(