diff --git a/CHANGELOG.md b/CHANGELOG.md index e0e7d5e8b..2bde46673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - AI Chat: `@` mention detection no longer breaks when the cursor sits right after an emoji or other non-BMP character +- AI Chat: Fix Error prompt now reads "MongoDB query" and "Redis command" using the database display name, instead of the raw query language label +- Internal: tab session registry binds automatically when a coordinator falls back to creating its own registry, so unit tests no longer trip the filter-state debug assertion ## [0.39.1] - 2026-05-08 diff --git a/TablePro/Core/AI/AIPromptTemplates.swift b/TablePro/Core/AI/AIPromptTemplates.swift index 5ab2acd94..3e5c23f52 100644 --- a/TablePro/Core/AI/AIPromptTemplates.swift +++ b/TablePro/Core/AI/AIPromptTemplates.swift @@ -6,6 +6,7 @@ // import Foundation +import TableProPluginKit /// Centralized prompt templates for AI-powered editor features enum AIPromptTemplates { @@ -42,8 +43,20 @@ enum AIPromptTemplates { } @MainActor private static func queryInfo(for databaseType: DatabaseType) -> (typeName: String, language: String) { - let langName = PluginManager.shared.queryLanguageName(for: databaseType) - let lang = PluginManager.shared.editorLanguage(for: databaseType).codeBlockTag - return ("\(langName) query", lang) + let snapshot = PluginMetadataRegistry.shared.snapshot(forTypeId: databaseType.pluginTypeId) + let editorLanguage = snapshot?.editorLanguage ?? .sql + let lang = editorLanguage.codeBlockTag + let typeName: String + switch editorLanguage { + case .sql: + typeName = "\(snapshot?.queryLanguageName ?? "SQL") query" + case .bash: + typeName = "\(snapshot?.displayName ?? databaseType.rawValue) command" + case .javascript: + typeName = "\(snapshot?.displayName ?? databaseType.rawValue) query" + case .custom: + typeName = "\(snapshot?.displayName ?? databaseType.rawValue) query" + } + return (typeName, lang) } } diff --git a/TablePro/Models/Query/QueryTabManager.swift b/TablePro/Models/Query/QueryTabManager.swift index 85900a298..aab07e494 100644 --- a/TablePro/Models/Query/QueryTabManager.swift +++ b/TablePro/Models/Query/QueryTabManager.swift @@ -38,6 +38,13 @@ final class QueryTabManager { self.tabSessionRegistry = tabSessionRegistry } + func bindTabSessionRegistry(_ registry: TabSessionRegistry) { + tabSessionRegistry = registry + for tab in tabs where registry.session(for: tab.id) == nil { + registry.register(TabSession(queryTab: tab)) + } + } + private func syncTabSessionRegistry(oldTabs: [QueryTab], newTabs: [QueryTab]) { guard let registry = tabSessionRegistry else { return } let oldIds = Set(oldTabs.map(\.id)) diff --git a/TablePro/Views/Main/Extensions/MainContentCoordinator+FilterState.swift b/TablePro/Views/Main/Extensions/MainContentCoordinator+FilterState.swift index 5278f1ce4..50b6711a5 100644 --- a/TablePro/Views/Main/Extensions/MainContentCoordinator+FilterState.swift +++ b/TablePro/Views/Main/Extensions/MainContentCoordinator+FilterState.swift @@ -308,7 +308,7 @@ extension MainContentCoordinator { filterStateLog.error( "TabSession missing for selected tab \(tabId, privacy: .public); QueryTab updated but session mirror skipped" ) - assertionFailure("TabSession missing for selected tab — registry sync regression") + assertionFailure("TabSession missing for selected tab: registry sync regression") } } } diff --git a/TablePro/Views/Main/MainContentCoordinator.swift b/TablePro/Views/Main/MainContentCoordinator.swift index b73df58ea..a3a4d25cb 100644 --- a/TablePro/Views/Main/MainContentCoordinator.swift +++ b/TablePro/Views/Main/MainContentCoordinator.swift @@ -343,7 +343,9 @@ final class MainContentCoordinator { self.tabManager = tabManager self.changeManager = changeManager self.toolbarState = toolbarState - self.tabSessionRegistry = tabSessionRegistry ?? TabSessionRegistry() + let resolvedRegistry = tabSessionRegistry ?? TabSessionRegistry() + self.tabSessionRegistry = resolvedRegistry + tabManager.bindTabSessionRegistry(resolvedRegistry) self.queryExecutor = queryExecutor ?? QueryExecutor(connection: connection) let dialect = PluginManager.shared.sqlDialect(for: connection.type) self.queryBuilder = TableQueryBuilder(