diff --git a/.changeset/shy-numbers-joke.md b/.changeset/shy-numbers-joke.md new file mode 100644 index 00000000000..f3cf3c27c6d --- /dev/null +++ b/.changeset/shy-numbers-joke.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Jetbrains - Fix Autocomplete diff --git a/jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/actors/MainThreadStatusBarShape.kt b/jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/actors/MainThreadStatusBarShape.kt index e2078e328e3..dcf1d4ebfdc 100644 --- a/jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/actors/MainThreadStatusBarShape.kt +++ b/jetbrains/plugin/src/main/kotlin/ai/kilocode/jetbrains/actors/MainThreadStatusBarShape.kt @@ -21,12 +21,12 @@ interface MainThreadStatusBarShape : Disposable { * @param entryId Entry identifier * @param name Display name * @param text Status bar text - * @param tooltip Tooltip text + * @param tooltip Tooltip text or MarkdownString object * @param showProgress Show progress indicator * @param command Command to execute on click * @param backgroundColor Background color * @param color Text color - * @param accessibilityInformation Accessibility information + * @param accessibilityInformation Accessibility information object * @param priority Display priority * @param alignment Alignment (left/right) */ @@ -36,12 +36,12 @@ interface MainThreadStatusBarShape : Disposable { entryId: String, name: String, text: String, - tooltip: String?, + tooltip: Any?, showProgress: Boolean, command: Any?, backgroundColor: Any?, color: Any?, - accessibilityInformation: Boolean?, + accessibilityInformation: Any?, priority: Double?, alignment: Any?, ) @@ -75,12 +75,12 @@ class MainThreadStatusBar( val entryId: String, val name: String, val text: String, - val tooltip: String?, + val tooltip: Any?, val showProgress: Boolean, val command: Any?, val backgroundColor: Any?, val color: Any?, - val accessibilityInformation: Boolean?, + val accessibilityInformation: Any?, val priority: Double?, val alignment: Any?, ) @@ -91,12 +91,12 @@ class MainThreadStatusBar( entryId: String, name: String, text: String, - tooltip: String?, + tooltip: Any?, showProgress: Boolean, command: Any?, backgroundColor: Any?, color: Any?, - accessibilityInformation: Boolean?, + accessibilityInformation: Any?, priority: Double?, alignment: Any?, ) { @@ -138,6 +138,17 @@ class MainThreadStatusBar( removeEntry(id) } + private fun extractTooltipText(tooltip: Any?): String? { + return when (tooltip) { + is String -> tooltip + is Map<*, *> -> { + // Handle MarkdownString object (serialized as Map) + tooltip["value"] as? String + } + else -> tooltip?.toString() + } + } + private fun updateStatusBar(project: Project, entry: StatusBarEntry) { try { // Get the status bar for the project @@ -147,7 +158,8 @@ class MainThreadStatusBar( // In JetBrains, we can't directly manipulate the status bar like in VSCode // We would need to create a custom widget or use notifications // For now, we just log the update - logger.info("Would update status bar with: ${entry.text}") + val tooltipText = extractTooltipText(entry.tooltip) + logger.info("Would update status bar with: ${entry.text}, tooltip: $tooltipText") // If showProgress is true, we could show a progress indicator if (entry.showProgress) { diff --git a/jetbrains/plugin/src/test/kotlin/ai/kilocode/jetbrains/util/ReflectUtilsStatusBarTest.kt b/jetbrains/plugin/src/test/kotlin/ai/kilocode/jetbrains/util/ReflectUtilsStatusBarTest.kt new file mode 100644 index 00000000000..28d92edc5df --- /dev/null +++ b/jetbrains/plugin/src/test/kotlin/ai/kilocode/jetbrains/util/ReflectUtilsStatusBarTest.kt @@ -0,0 +1,129 @@ +// SPDX-FileCopyrightText: 2025 Weibo, Inc. +// +// SPDX-License-Identifier: Apache-2.0 + +package ai.kilocode.jetbrains.util + +import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertEquals +import org.junit.Test +import kotlin.reflect.full.functions + +class ReflectUtilsStatusBarTest { + + class MockStatusBar { + fun setEntry( + id: Int, + extensionId: String, + entryId: String, + name: String, + text: String, + tooltip: Any?, + showProgress: Boolean, + command: Any?, + backgroundColor: Any?, + color: Any?, + accessibilityInformation: Any?, + priority: Double?, + alignment: Any?, + ): String { + return "id=$id, extensionId=$extensionId, entryId=$entryId, name=$name, text=$text, " + + "tooltip=$tooltip, showProgress=$showProgress, command=$command, " + + "backgroundColor=$backgroundColor, color=$color, " + + "accessibilityInformation=$accessibilityInformation, " + + "priority=$priority (${priority?.javaClass?.simpleName}), alignment=$alignment" + } + } + + @Test + fun `test setEntry with Double priority from JSON`() = runBlocking { + val actor = MockStatusBar() + val method = actor::class.functions.first { it.name == "setEntry" } + + // Simulate what the RPC call sends - all numbers come as Double from JSON + // Based on the error log: id, extensionId, entryId, name, text, tooltip, showProgress, command, + // backgroundColor, color, accessibilityInformation, priority, alignment + val args = listOf( + 1.0, // id (should convert to Int) + "test-extension", // extensionId + "test-entry", // entryId + "Test Name", // name + "Autocompletions provided by mistralai/codestral-2508 via Kilo Gateway.", // text + null, // tooltip + false, // showProgress + null, // command + null, // backgroundColor + null, // color + false, // accessibilityInformation (Boolean, not Boolean?) + 100.0, // priority (should stay as Double) + null // alignment + ) + + val result = doInvokeMethod(method, args, actor) + + // Priority should remain as Double, not be converted to Int + assert(result.toString().contains("priority=100.0 (Double)")) + } + + @Test + fun `test setEntry with Boolean for accessibilityInformation`() = runBlocking { + val actor = MockStatusBar() + val method = actor::class.functions.first { it.name == "setEntry" } + + // Test with accessibilityInformation as false (Boolean, not Boolean?) + val args = listOf( + 1.0, // id + "test-extension", // extensionId + "test-entry", // entryId + "Test Name", // name + "Test text", // text + null, // tooltip + false, // showProgress + null, // command + null, // backgroundColor + null, // color + false, // accessibilityInformation - now accepts Any? + 100.0, // priority + null // alignment + ) + + val result = doInvokeMethod(method, args, actor) + println(result) + } + + @Test + fun `test setEntry with MarkdownString-like tooltip object`() = runBlocking { + val actor = MockStatusBar() + val method = actor::class.functions.first { it.name == "setEntry" } + + // Simulate a MarkdownString object being passed as tooltip + val markdownTooltip = mapOf( + "value" to "Autocompletions provided by mistralai/codestral-2508 via Kilo Gateway.", + "isTrusted" to true, + "supportThemeIcons" to false, + "supportHtml" to false, + "uris" to emptyMap() + ) + + val args = listOf( + 1.0, // id + "ghost-extension", // extensionId + "ghost-status", // entryId + "Ghost Status", // name + "Ghost (5)", // text + markdownTooltip, // tooltip - MarkdownString object + false, // showProgress + null, // command + null, // backgroundColor + null, // color + null, // accessibilityInformation + 100.0, // priority + null // alignment + ) + + val result = doInvokeMethod(method, args, actor) + // Should not throw an exception + assert(result.toString().contains("priority=100.0 (Double)")) + assert(result.toString().contains("tooltip=")) + } +}