From 37e49b5171913a9188eaba6ca826f9270af0433e Mon Sep 17 00:00:00 2001 From: Idddd <956020859@qq.com> Date: Thu, 4 Jun 2026 16:26:48 +0800 Subject: [PATCH 1/4] Revert "fix: login SSO HTTP client also reads TLS disable setting" This reverts commit e6ad46f705be27980a899696a8ddcc8969203a31. --- .../src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt index c44b42d..a05edb0 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt @@ -156,11 +156,10 @@ class AuthManager(private val project: Project) { } private fun executeLogin(config: TemplateRequestConfig, username: String, password: String): String { - val disableTls = LlmSettingsLoader.load(project).httpDisableTlsVerification return try { runBlocking { TemplateRequestExecutor( - HttpClients.shared(disableTlsVerification = disableTls, timeoutSeconds = 60) + HttpClients.shared(disableTlsVerification = false, timeoutSeconds = 60) ).execute( config = config, variables = mapOf( From a04eb525df28e6cdb8047a4d7897f586ee8b736f Mon Sep 17 00:00:00 2001 From: Idddd <956020859@qq.com> Date: Thu, 4 Jun 2026 16:26:54 +0800 Subject: [PATCH 2/4] Revert "fix: default disable TLS verification, auto-pull on check update, strip prompt metadata before LLM use" This reverts commit 46812c088f20742897488c5a520cc188278941d3. --- .../org/openprojectx/ai/plugin/llm/LlmSettings.kt | 2 +- .../openprojectx/ai/plugin/AiTestSettingsModel.kt | 2 +- .../ai/plugin/ContextBoxToolWindowFactory.kt | 10 +++++++--- .../openprojectx/ai/plugin/LlmSettingsLoader.kt | 15 ++------------- .../ai/plugin/PromptProfileResolver.kt | 3 +-- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt b/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt index a187fe4..dd91f2e 100644 --- a/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt +++ b/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt @@ -8,7 +8,7 @@ data class LlmSettings( val endpoint: String? = null, val template: TemplateRequestConfig? = null, val auth: LlmAuthConfig? = null, - val httpDisableTlsVerification: Boolean = true, + val httpDisableTlsVerification: Boolean = false, val maxTokens: Int = 8192 ) diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt index e61e340..45a139a 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt @@ -7,7 +7,7 @@ data class AiTestSettingsModel( val llmTimeoutSeconds: String = "60", val llmApiKey: String = "", val llmApiKeyEnv: String = "", - val httpDisableTlsVerification: Boolean = true, + val httpDisableTlsVerification: Boolean = false, val showLogTab: Boolean = true, val llmTemplateEnabled: Boolean = false, val llmTemplateMethod: String = "POST", diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt index 0182ad8..1be1efc 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt @@ -1060,10 +1060,12 @@ class ContextBoxToolWindowFactory : ToolWindowFactory, DumbAware { Notifications.error(project, "Prompt Manager", status.message) return } + val message = promptUpdateMessage(status) if (status.hasUpdates) { - performPullUpdate() + val choice = Messages.showYesNoDialog(project, "$message\n\nUpdate prompts now?", "Prompt Manager", "Update", "Later", null) + if (choice == Messages.YES) performPullUpdate() else Notifications.info(project, "Prompt Manager", message) } else { - Notifications.info(project, "Prompt Manager", promptUpdateMessage(status)) + Notifications.info(project, "Prompt Manager", message) } } @@ -1584,7 +1586,9 @@ class ContextBoxToolWindowFactory : ToolWindowFactory, DumbAware { return } if (status.hasUpdates) { - performPullSkillUpdate() + val choice = Messages.showYesNoDialog(project, + "${status.message}\n\nUpdate skills now?", "Skill Manager", "Update", "Later", null) + if (choice == Messages.YES) performPullSkillUpdate() else Notifications.info(project, "Skill Manager", status.message) } else { Notifications.info(project, "Skill Manager", status.message) } diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt index 6a13a12..ab95be6 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt @@ -505,7 +505,7 @@ object LlmSettingsLoader { llmTimeoutSeconds = llm.string("timeoutSeconds").ifBlank { "60" }, llmApiKey = llm.string("apiKey"), llmApiKeyEnv = llm.string("apiKeyEnv"), - httpDisableTlsVerification = http?.get("disableTlsVerification") as? Boolean ?: true, + httpDisableTlsVerification = http?.get("disableTlsVerification") as? Boolean ?: false, showLogTab = ui["showLogTab"] as? Boolean ?: true, llmTemplateEnabled = template != null, llmTemplateMethod = template.string("method").ifBlank { "POST" }, @@ -762,7 +762,7 @@ object LlmSettingsLoader { } val httpMap = llm["http"] as? Map<*, *> - val disableTlsVerification = httpMap?.get("disableTlsVerification") as? Boolean ?: true + val disableTlsVerification = httpMap?.get("disableTlsVerification") as? Boolean ?: false val maxTokens = when (val v = llm["maxTokens"]) { is Number -> v.toInt() @@ -1072,17 +1072,6 @@ object LlmSettingsLoader { } } - fun stripPromptMetadata(content: String): String { - val lines = content.trim().lines() - val metadataKeys = setOf("name", "type", "time", "updatedAt", "pulledAt") - val bodyStart = lines.indexOfFirst { line -> - val key = line.substringBefore(":").trim().lowercase() - key !in metadataKeys && line.isNotBlank() - } - if (bodyStart < 0) return content - return lines.drop(bodyStart).joinToString("\n").trim() - } - private fun extractSkillBody(content: String): String { val lines = content.trim().lines() val metadataKeys = setOf("name", "type", "time", "updatedAt", "pulledAt", "description") diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt index bb15b7a..7c670b3 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt @@ -4,11 +4,10 @@ object PromptProfileResolver { fun resolve(profileSet: PromptProfileSet, fallbackTemplate: String): String { val selectedName = profileSet.selected.trim().ifBlank { PromptProfileSet.DEFAULT_NAME } - val raw = profileSet.items[selectedName] + return profileSet.items[selectedName] ?.takeIf { it.isNotBlank() } ?: profileSet.items[PromptProfileSet.DEFAULT_NAME] ?.takeIf { it.isNotBlank() } ?: fallbackTemplate - return LlmSettingsLoader.stripPromptMetadata(raw) } } From a7294e80667e142ebed884a590d1a08527c2a8de Mon Sep 17 00:00:00 2001 From: Idddd <956020859@qq.com> Date: Thu, 4 Jun 2026 16:28:06 +0800 Subject: [PATCH 3/4] Reapply "fix: default disable TLS verification, auto-pull on check update, strip prompt metadata before LLM use" This reverts commit a04eb525df28e6cdb8047a4d7897f586ee8b736f. --- .../org/openprojectx/ai/plugin/llm/LlmSettings.kt | 2 +- .../openprojectx/ai/plugin/AiTestSettingsModel.kt | 2 +- .../ai/plugin/ContextBoxToolWindowFactory.kt | 10 +++------- .../openprojectx/ai/plugin/LlmSettingsLoader.kt | 15 +++++++++++++-- .../ai/plugin/PromptProfileResolver.kt | 3 ++- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt b/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt index dd91f2e..a187fe4 100644 --- a/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt +++ b/llm-client/src/main/kotlin/org/openprojectx/ai/plugin/llm/LlmSettings.kt @@ -8,7 +8,7 @@ data class LlmSettings( val endpoint: String? = null, val template: TemplateRequestConfig? = null, val auth: LlmAuthConfig? = null, - val httpDisableTlsVerification: Boolean = false, + val httpDisableTlsVerification: Boolean = true, val maxTokens: Int = 8192 ) diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt index 45a139a..e61e340 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AiTestSettingsModel.kt @@ -7,7 +7,7 @@ data class AiTestSettingsModel( val llmTimeoutSeconds: String = "60", val llmApiKey: String = "", val llmApiKeyEnv: String = "", - val httpDisableTlsVerification: Boolean = false, + val httpDisableTlsVerification: Boolean = true, val showLogTab: Boolean = true, val llmTemplateEnabled: Boolean = false, val llmTemplateMethod: String = "POST", diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt index 1be1efc..0182ad8 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/ContextBoxToolWindowFactory.kt @@ -1060,12 +1060,10 @@ class ContextBoxToolWindowFactory : ToolWindowFactory, DumbAware { Notifications.error(project, "Prompt Manager", status.message) return } - val message = promptUpdateMessage(status) if (status.hasUpdates) { - val choice = Messages.showYesNoDialog(project, "$message\n\nUpdate prompts now?", "Prompt Manager", "Update", "Later", null) - if (choice == Messages.YES) performPullUpdate() else Notifications.info(project, "Prompt Manager", message) + performPullUpdate() } else { - Notifications.info(project, "Prompt Manager", message) + Notifications.info(project, "Prompt Manager", promptUpdateMessage(status)) } } @@ -1586,9 +1584,7 @@ class ContextBoxToolWindowFactory : ToolWindowFactory, DumbAware { return } if (status.hasUpdates) { - val choice = Messages.showYesNoDialog(project, - "${status.message}\n\nUpdate skills now?", "Skill Manager", "Update", "Later", null) - if (choice == Messages.YES) performPullSkillUpdate() else Notifications.info(project, "Skill Manager", status.message) + performPullSkillUpdate() } else { Notifications.info(project, "Skill Manager", status.message) } diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt index ab95be6..6a13a12 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/LlmSettingsLoader.kt @@ -505,7 +505,7 @@ object LlmSettingsLoader { llmTimeoutSeconds = llm.string("timeoutSeconds").ifBlank { "60" }, llmApiKey = llm.string("apiKey"), llmApiKeyEnv = llm.string("apiKeyEnv"), - httpDisableTlsVerification = http?.get("disableTlsVerification") as? Boolean ?: false, + httpDisableTlsVerification = http?.get("disableTlsVerification") as? Boolean ?: true, showLogTab = ui["showLogTab"] as? Boolean ?: true, llmTemplateEnabled = template != null, llmTemplateMethod = template.string("method").ifBlank { "POST" }, @@ -762,7 +762,7 @@ object LlmSettingsLoader { } val httpMap = llm["http"] as? Map<*, *> - val disableTlsVerification = httpMap?.get("disableTlsVerification") as? Boolean ?: false + val disableTlsVerification = httpMap?.get("disableTlsVerification") as? Boolean ?: true val maxTokens = when (val v = llm["maxTokens"]) { is Number -> v.toInt() @@ -1072,6 +1072,17 @@ object LlmSettingsLoader { } } + fun stripPromptMetadata(content: String): String { + val lines = content.trim().lines() + val metadataKeys = setOf("name", "type", "time", "updatedAt", "pulledAt") + val bodyStart = lines.indexOfFirst { line -> + val key = line.substringBefore(":").trim().lowercase() + key !in metadataKeys && line.isNotBlank() + } + if (bodyStart < 0) return content + return lines.drop(bodyStart).joinToString("\n").trim() + } + private fun extractSkillBody(content: String): String { val lines = content.trim().lines() val metadataKeys = setOf("name", "type", "time", "updatedAt", "pulledAt", "description") diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt index 7c670b3..bb15b7a 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/PromptProfileResolver.kt @@ -4,10 +4,11 @@ object PromptProfileResolver { fun resolve(profileSet: PromptProfileSet, fallbackTemplate: String): String { val selectedName = profileSet.selected.trim().ifBlank { PromptProfileSet.DEFAULT_NAME } - return profileSet.items[selectedName] + val raw = profileSet.items[selectedName] ?.takeIf { it.isNotBlank() } ?: profileSet.items[PromptProfileSet.DEFAULT_NAME] ?.takeIf { it.isNotBlank() } ?: fallbackTemplate + return LlmSettingsLoader.stripPromptMetadata(raw) } } From 46cf10d39613b5877d120e8566df369908d8bee9 Mon Sep 17 00:00:00 2001 From: Idddd <956020859@qq.com> Date: Thu, 4 Jun 2026 16:38:25 +0800 Subject: [PATCH 4/4] fix: remove shared SSO token, store tokens per-service Previously all services (LLM, SonarQube, Bitbucket) shared a single SSO token, but tokens from the same SSO endpoint are service-specific and not interchangeable, causing 401 errors across services. - Remove shared SSO token key, each service now stores its own token - Login credentials (username/password) remain shared - Login HTTP client now reads httpDisableTlsVerification from settings Co-Authored-By: Claude Opus 4.7 --- .../org/openprojectx/ai/plugin/AuthManager.kt | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt index a05edb0..55aa7d0 100644 --- a/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt +++ b/plugin-idea/src/main/kotlin/org/openprojectx/ai/plugin/AuthManager.kt @@ -19,7 +19,6 @@ class AuthManager(private val project: Project) { companion object { fun getInstance(project: Project): AuthManager = project.service() - private const val SSO_TOKEN_KEY = "OpenProjectX.AI.SSO.Token" private const val SSO_CREDENTIALS_KEY = "OpenProjectX.AI.SSO.Credentials" private fun serviceTokenKey(service: String) = "OpenProjectX.AI.SSO.$service.Token" } @@ -36,12 +35,7 @@ class AuthManager(private val project: Project) { // 1. Service-specific token from PasswordSafe readToken(serviceTokenKey(service))?.let { return it } - // 2. Shared SSO token from PasswordSafe - if (independentLogin == null) { - readToken(SSO_TOKEN_KEY)?.let { return it } - } - - // 3. Independent username/password configured → login with independent or shared template + // 2. Independent username/password configured → login with independent or shared template if (!independentUsername.isNullOrBlank() && !independentPassword.isNullOrBlank()) { val loginConfig = independentLogin ?: loadSharedLoginConfig() ?: error("No login template configured. Set llm.auth.login in .ai-test.yaml") @@ -57,7 +51,7 @@ class AuthManager(private val project: Project) { ?: error("No login template configured. Set llm.auth.login in .ai-test.yaml") val token = executeLogin(loginConfig, savedCreds.first, savedCreds.second) if (token.isNotBlank()) { - saveToken(SSO_TOKEN_KEY, token) + saveToken(serviceTokenKey(service), token) return token } } @@ -73,12 +67,8 @@ class AuthManager(private val project: Project) { independentUsername: String? = null, independentPassword: String? = null ): String { - // Clear service token + // Clear service-specific token clearToken(serviceTokenKey(service)) - // Also clear shared SSO token (it's the same source) - if (independentLogin == null) { - clearToken(SSO_TOKEN_KEY) - } // Independent credentials → retry with those if (!independentUsername.isNullOrBlank() && !independentPassword.isNullOrBlank()) { @@ -96,7 +86,7 @@ class AuthManager(private val project: Project) { ?: error("No login template configured") val token = executeLogin(loginConfig, savedCreds.first, savedCreds.second) if (token.isNotBlank()) { - saveToken(SSO_TOKEN_KEY, token) + saveToken(serviceTokenKey(service), token) return token } } @@ -120,8 +110,7 @@ class AuthManager(private val project: Project) { error("SSO login returned empty token for $service$hint. Check logs for details.") } - val targetKey = if (independentLogin != null) serviceTokenKey(service) else SSO_TOKEN_KEY - saveToken(targetKey, token) + saveToken(serviceTokenKey(service), token) if (credentials.remember) { saveCredentials(SSO_CREDENTIALS_KEY, credentials.username, credentials.password) } @@ -156,10 +145,11 @@ class AuthManager(private val project: Project) { } private fun executeLogin(config: TemplateRequestConfig, username: String, password: String): String { + val disableTls = LlmSettingsLoader.load(project).httpDisableTlsVerification return try { runBlocking { TemplateRequestExecutor( - HttpClients.shared(disableTlsVerification = false, timeoutSeconds = 60) + HttpClients.shared(disableTlsVerification = disableTls, timeoutSeconds = 60) ).execute( config = config, variables = mapOf(