diff --git a/ChatView/CMakeLists.txt b/ChatView/CMakeLists.txt
index 4cb0c29..9c449fd 100644
--- a/ChatView/CMakeLists.txt
+++ b/ChatView/CMakeLists.txt
@@ -63,6 +63,7 @@ qt_add_qml_module(QodeAssistChatView
ChatView.hpp ChatView.cpp
ChatData.hpp
FileItem.hpp FileItem.cpp
+ ChatFileManager.hpp ChatFileManager.cpp
)
target_link_libraries(QodeAssistChatView
diff --git a/ChatView/ChatFileManager.cpp b/ChatView/ChatFileManager.cpp
new file mode 100644
index 0000000..b5fa907
--- /dev/null
+++ b/ChatView/ChatFileManager.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2024-2025 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#include "ChatFileManager.hpp"
+#include "Logger.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+namespace QodeAssist::Chat {
+
+ChatFileManager::ChatFileManager(QObject *parent)
+ : QObject(parent)
+ , m_intermediateStorageDir(getIntermediateStorageDir())
+{}
+
+ChatFileManager::~ChatFileManager() = default;
+
+QStringList ChatFileManager::processDroppedFiles(const QStringList &filePaths)
+{
+ QStringList processedPaths;
+ processedPaths.reserve(filePaths.size());
+
+ for (const QString &filePath : filePaths) {
+ if (!isFileAccessible(filePath)) {
+ const QString error = tr("File is not accessible: %1").arg(filePath);
+ LOG_MESSAGE(error);
+ emit fileOperationFailed(error);
+ continue;
+ }
+
+ QString copiedPath = copyToIntermediateStorage(filePath);
+ if (!copiedPath.isEmpty()) {
+ processedPaths.append(copiedPath);
+ emit fileCopiedToStorage(filePath, copiedPath);
+ LOG_MESSAGE(QString("File copied to storage: %1 -> %2").arg(filePath, copiedPath));
+ } else {
+ const QString error = tr("Failed to copy file: %1").arg(filePath);
+ LOG_MESSAGE(error);
+ emit fileOperationFailed(error);
+ }
+ }
+
+ return processedPaths;
+}
+
+void ChatFileManager::setChatFilePath(const QString &chatFilePath)
+{
+ m_chatFilePath = chatFilePath;
+}
+
+QString ChatFileManager::chatFilePath() const
+{
+ return m_chatFilePath;
+}
+
+void ChatFileManager::clearIntermediateStorage()
+{
+ QDir dir(m_intermediateStorageDir);
+ if (!dir.exists()) {
+ return;
+ }
+
+ const QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
+ for (const QFileInfo &fileInfo : files) {
+ QFile file(fileInfo.absoluteFilePath());
+ file.setPermissions(QFile::WriteUser | QFile::ReadUser);
+ if (file.remove()) {
+ LOG_MESSAGE(QString("Removed intermediate file: %1").arg(fileInfo.fileName()));
+ } else {
+ LOG_MESSAGE(QString("Failed to remove intermediate file: %1")
+ .arg(fileInfo.fileName()));
+ }
+ }
+}
+
+bool ChatFileManager::isFileAccessible(const QString &filePath)
+{
+ QFileInfo fileInfo(filePath);
+ return fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable();
+}
+
+void ChatFileManager::cleanupGlobalIntermediateStorage()
+{
+ const QString basePath = Core::ICore::userResourcePath().toFSPathString();
+ const QString intermediatePath = QDir(basePath).filePath("qodeassist/chat_temp_files");
+
+ QDir dir(intermediatePath);
+ if (!dir.exists()) {
+ return;
+ }
+
+ const QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
+ int removedCount = 0;
+ int failedCount = 0;
+
+ for (const QFileInfo &fileInfo : files) {
+ QFile file(fileInfo.absoluteFilePath());
+ file.setPermissions(QFile::WriteUser | QFile::ReadUser);
+ if (file.remove()) {
+ removedCount++;
+ } else {
+ failedCount++;
+ }
+ }
+
+ if (removedCount > 0 || failedCount > 0) {
+ LOG_MESSAGE(QString("ChatFileManager global cleanup: removed=%1, failed=%2")
+ .arg(removedCount)
+ .arg(failedCount));
+ }
+}
+
+QString ChatFileManager::copyToIntermediateStorage(const QString &filePath)
+{
+ QFileInfo fileInfo(filePath);
+ if (!fileInfo.exists() || !fileInfo.isFile()) {
+ LOG_MESSAGE(QString("Source file does not exist or is not a file: %1").arg(filePath));
+ return QString();
+ }
+
+ if (fileInfo.size() == 0) {
+ LOG_MESSAGE(QString("Source file is empty: %1").arg(filePath));
+ }
+
+ const QString newFileName = generateIntermediateFileName(filePath);
+ const QString destinationPath = QDir(m_intermediateStorageDir).filePath(newFileName);
+
+ if (QFileInfo::exists(destinationPath)) {
+ QFile::remove(destinationPath);
+ }
+
+ if (!QFile::copy(filePath, destinationPath)) {
+ LOG_MESSAGE(QString("Failed to copy file: %1 -> %2").arg(filePath, destinationPath));
+ return QString();
+ }
+
+ QFile copiedFile(destinationPath);
+ if (!copiedFile.exists()) {
+ LOG_MESSAGE(QString("Copied file does not exist after copy: %1").arg(destinationPath));
+ return QString();
+ }
+
+ copiedFile.setPermissions(QFile::ReadUser | QFile::WriteUser);
+
+ return destinationPath;
+}
+
+QString ChatFileManager::getIntermediateStorageDir()
+{
+ const QString basePath = Core::ICore::userResourcePath().toFSPathString();
+ const QString intermediatePath = QDir(basePath).filePath("qodeassist/chat_temp_files");
+
+ QDir dir;
+ if (!dir.exists(intermediatePath) && !dir.mkpath(intermediatePath)) {
+ LOG_MESSAGE(QString("Failed to create intermediate storage directory: %1")
+ .arg(intermediatePath));
+ }
+
+ return intermediatePath;
+}
+
+QString ChatFileManager::generateIntermediateFileName(const QString &originalPath)
+{
+ const QFileInfo fileInfo(originalPath);
+ const QString extension = fileInfo.suffix();
+ QString baseName = fileInfo.completeBaseName().left(30);
+
+ static const QRegularExpression specialChars("[^a-zA-Z0-9_-]");
+ baseName.replace(specialChars, "_");
+
+ if (baseName.isEmpty()) {
+ baseName = "file";
+ }
+
+ const QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
+ const QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces).left(8);
+
+ return QString("%1_%2_%3.%4").arg(baseName, timestamp, uuid, extension);
+}
+
+} // namespace QodeAssist::Chat
+
diff --git a/ChatView/ChatFileManager.hpp b/ChatView/ChatFileManager.hpp
new file mode 100644
index 0000000..80dec71
--- /dev/null
+++ b/ChatView/ChatFileManager.hpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024-2025 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace QodeAssist::Chat {
+
+class ChatFileManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit ChatFileManager(QObject *parent = nullptr);
+ ~ChatFileManager();
+
+ QStringList processDroppedFiles(const QStringList &filePaths);
+ void setChatFilePath(const QString &chatFilePath);
+ QString chatFilePath() const;
+ void clearIntermediateStorage();
+
+ static bool isFileAccessible(const QString &filePath);
+ static void cleanupGlobalIntermediateStorage();
+
+signals:
+ void fileOperationFailed(const QString &error);
+ void fileCopiedToStorage(const QString &originalPath, const QString &newPath);
+
+private:
+ QString copyToIntermediateStorage(const QString &filePath);
+ QString getIntermediateStorageDir();
+ QString generateIntermediateFileName(const QString &originalPath);
+
+ QString m_chatFilePath;
+ QString m_intermediateStorageDir;
+};
+
+} // namespace QodeAssist::Chat
+
diff --git a/ChatView/ChatRootView.cpp b/ChatView/ChatRootView.cpp
index 22fa1a8..b182291 100644
--- a/ChatView/ChatRootView.cpp
+++ b/ChatView/ChatRootView.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
@@ -53,6 +54,7 @@ ChatRootView::ChatRootView(QQuickItem *parent)
, m_chatModel(new ChatModel(this))
, m_promptProvider(LLMCore::PromptTemplateManager::instance())
, m_clientInterface(new ClientInterface(m_chatModel, &m_promptProvider, this))
+ , m_fileManager(new ChatFileManager(this))
, m_isRequestInProgress(false)
{
m_isSyncOpenFiles = Settings::chatAssistantSettings().linkOpenFiles();
@@ -230,6 +232,11 @@ ChatRootView::ChatRootView(QQuickItem *parent)
&Utils::BaseAspect::changed,
this,
&ChatRootView::isThinkingSupportChanged);
+
+ connect(m_fileManager, &ChatFileManager::fileOperationFailed, this, [this](const QString &error) {
+ m_lastErrorMessage = error;
+ emit lastErrorMessageChanged();
+ });
}
ChatModel *ChatRootView::chatModel() const
@@ -265,6 +272,8 @@ void ChatRootView::sendMessage(const QString &message)
m_clientInterface
->sendMessage(message, m_attachmentFiles, m_linkedFiles, useTools(), useThinking());
+
+ m_fileManager->clearIntermediateStorage();
clearAttachmentFiles();
setRequestProgressStatus(true);
}
@@ -282,18 +291,23 @@ void ChatRootView::cancelRequest()
void ChatRootView::clearAttachmentFiles()
{
- if (!m_attachmentFiles.isEmpty()) {
- m_attachmentFiles.clear();
- emit attachmentFilesChanged();
+ if (m_attachmentFiles.isEmpty()) {
+ return;
}
+
+ m_attachmentFiles.clear();
+ emit attachmentFilesChanged();
+ m_fileManager->clearIntermediateStorage();
}
void ChatRootView::clearLinkedFiles()
{
- if (!m_linkedFiles.isEmpty()) {
- m_linkedFiles.clear();
- emit linkedFilesChanged();
+ if (m_linkedFiles.isEmpty()) {
+ return;
}
+
+ m_linkedFiles.clear();
+ emit linkedFilesChanged();
}
QString ChatRootView::getChatsHistoryDir() const
@@ -304,8 +318,8 @@ QString ChatRootView::getChatsHistoryDir() const
Settings::ProjectSettings projectSettings(project);
path = projectSettings.chatHistoryPath().toFSPathString();
} else {
- path = QString("%1/qodeassist/chat_history")
- .arg(Core::ICore::userResourcePath().toFSPathString());
+ QDir baseDir(Core::ICore::userResourcePath().toFSPathString());
+ path = baseDir.filePath("qodeassist/chat_history");
}
QDir dir(path);
@@ -342,6 +356,12 @@ void ChatRootView::loadHistory(const QString &filePath)
setRecentFilePath(filePath);
}
+ m_fileManager->clearIntermediateStorage();
+ m_attachmentFiles.clear();
+ m_linkedFiles.clear();
+ emit attachmentFilesChanged();
+ emit linkedFilesChanged();
+
m_currentMessageRequestId.clear();
updateInputTokensCount();
updateCurrentMessageEditsStats();
@@ -499,8 +519,10 @@ void ChatRootView::addFilesToAttachList(const QStringList &filePaths)
return;
}
+ const QStringList processedPaths = m_fileManager->processDroppedFiles(filePaths);
+
bool filesAdded = false;
- for (const QString &filePath : filePaths) {
+ for (const QString &filePath : processedPaths) {
if (!m_attachmentFiles.contains(filePath)) {
m_attachmentFiles.append(filePath);
filesAdded = true;
@@ -514,10 +536,15 @@ void ChatRootView::addFilesToAttachList(const QStringList &filePaths)
void ChatRootView::removeFileFromAttachList(int index)
{
- if (index >= 0 && index < m_attachmentFiles.size()) {
- m_attachmentFiles.removeAt(index);
- emit attachmentFilesChanged();
+ if (index < 0 || index >= m_attachmentFiles.size()) {
+ return;
}
+
+ const QString removedFile = m_attachmentFiles.at(index);
+ m_attachmentFiles.removeAt(index);
+ emit attachmentFilesChanged();
+
+ LOG_MESSAGE(QString("Removed attachment file: %1").arg(removedFile));
}
void ChatRootView::showLinkFilesDialog()
@@ -557,7 +584,6 @@ void ChatRootView::addFilesToLinkList(const QStringList &filePaths)
if (!imageFiles.isEmpty()) {
addFilesToAttachList(imageFiles);
-
m_lastInfoMessage
= tr("Images automatically moved to Attach zone (%n file(s))", "", imageFiles.size());
emit lastInfoMessageChanged();
@@ -570,10 +596,15 @@ void ChatRootView::addFilesToLinkList(const QStringList &filePaths)
void ChatRootView::removeFileFromLinkList(int index)
{
- if (index >= 0 && index < m_linkedFiles.size()) {
- m_linkedFiles.removeAt(index);
- emit linkedFilesChanged();
+ if (index < 0 || index >= m_linkedFiles.size()) {
+ return;
}
+
+ const QString removedFile = m_linkedFiles.at(index);
+ m_linkedFiles.removeAt(index);
+ emit linkedFilesChanged();
+
+ LOG_MESSAGE(QString("Removed linked file: %1").arg(removedFile));
}
void ChatRootView::showAddImageDialog()
@@ -587,19 +618,7 @@ void ChatRootView::showAddImageDialog()
}
if (dialog.exec() == QDialog::Accepted) {
- QStringList newFilePaths = dialog.selectedFiles();
- if (!newFilePaths.isEmpty()) {
- bool filesAdded = false;
- for (const QString &filePath : std::as_const(newFilePaths)) {
- if (!m_attachmentFiles.contains(filePath)) {
- m_attachmentFiles.append(filePath);
- filesAdded = true;
- }
- }
- if (filesAdded) {
- emit attachmentFilesChanged();
- }
- }
+ addFilesToAttachList(dialog.selectedFiles());
}
}
@@ -645,8 +664,8 @@ void ChatRootView::openChatHistoryFolder()
Settings::ProjectSettings projectSettings(project);
path = projectSettings.chatHistoryPath().toFSPathString();
} else {
- path = QString("%1/qodeassist/chat_history")
- .arg(Core::ICore::userResourcePath().toFSPathString());
+ QDir baseDir(Core::ICore::userResourcePath().toFSPathString());
+ path = baseDir.filePath("qodeassist/chat_history");
}
QDir dir(path);
@@ -666,7 +685,7 @@ void ChatRootView::openRulesFolder()
}
QString projectPath = project->projectDirectory().toFSPathString();
- QString rulesPath = projectPath + "/.qodeassist/rules";
+ QString rulesPath = QDir(projectPath).filePath(".qodeassist/rules");
QDir dir(rulesPath);
if (!dir.exists()) {
@@ -762,6 +781,7 @@ void ChatRootView::setRecentFilePath(const QString &filePath)
if (m_recentFilePath != filePath) {
m_recentFilePath = filePath;
m_clientInterface->setChatFilePath(filePath);
+ m_fileManager->setChatFilePath(filePath);
emit chatFileNameChanged();
}
}
diff --git a/ChatView/ChatRootView.hpp b/ChatView/ChatRootView.hpp
index 5e011e5..c7eb69f 100644
--- a/ChatView/ChatRootView.hpp
+++ b/ChatView/ChatRootView.hpp
@@ -23,6 +23,7 @@
#include "ChatModel.hpp"
#include "ClientInterface.hpp"
+#include "ChatFileManager.hpp"
#include "llmcore/PromptProviderChat.hpp"
#include
@@ -199,6 +200,7 @@ private:
ChatModel *m_chatModel;
LLMCore::PromptProviderChat m_promptProvider;
ClientInterface *m_clientInterface;
+ ChatFileManager *m_fileManager;
QString m_currentTemplate;
QString m_recentFilePath;
QStringList m_attachmentFiles;
diff --git a/ChatView/qml/RootItem.qml b/ChatView/qml/RootItem.qml
index 5382380..08d8049 100644
--- a/ChatView/qml/RootItem.qml
+++ b/ChatView/qml/RootItem.qml
@@ -60,6 +60,7 @@ ChatRootView {
SplitDropZone {
anchors.fill: parent
+ z: 99
onFilesDroppedToAttach: (urlStrings) => {
var localPaths = root.convertUrlsToLocalPaths(urlStrings)
diff --git a/ChatView/qml/controls/SplitDropZone.qml b/ChatView/qml/controls/SplitDropZone.qml
index 8b9260a..bdd7592 100644
--- a/ChatView/qml/controls/SplitDropZone.qml
+++ b/ChatView/qml/controls/SplitDropZone.qml
@@ -23,10 +23,12 @@ import QtQuick.Controls
Item {
id: root
- signal filesDroppedToAttach(var urlStrings) // Array of URL strings (file://...)
- signal filesDroppedToLink(var urlStrings) // Array of URL strings (file://...)
+ signal filesDroppedToAttach(var urlStrings)
+ signal filesDroppedToLink(var urlStrings)
property string activeZone: ""
+ property int filesCount: 0
+ property bool isDragActive: false
Item {
id: splitDropOverlay
@@ -34,12 +36,39 @@ Item {
anchors.fill: parent
visible: false
z: 999
+ opacity: 0
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
+ }
Rectangle {
anchors.fill: parent
color: Qt.rgba(palette.shadow.r, palette.shadow.g, palette.shadow.b, 0.6)
}
+ Rectangle {
+ anchors {
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ topMargin: 30
+ }
+ width: fileCountText.width + 40
+ height: 50
+ color: Qt.rgba(palette.highlight.r, palette.highlight.g, palette.highlight.b, 0.9)
+ radius: 25
+ visible: root.filesCount > 0
+
+ Text {
+ id: fileCountText
+ anchors.centerIn: parent
+ text: qsTr("%n file(s) to drop", "", root.filesCount)
+ font.pixelSize: 16
+ font.bold: true
+ color: palette.highlightedText
+ }
+ }
+
Rectangle {
id: leftZone
@@ -76,19 +105,20 @@ Item {
color: root.activeZone === "left" ? palette.highlightedText : palette.text
opacity: 0.8
}
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: qsTr("(for one-time use)")
+ font.pixelSize: 12
+ font.italic: true
+ color: root.activeZone === "left" ? palette.highlightedText : palette.text
+ opacity: 0.6
+ }
}
- Behavior on color {
- ColorAnimation { duration: 150 }
- }
-
- Behavior on border.width {
- NumberAnimation { duration: 150 }
- }
-
- Behavior on border.color {
- ColorAnimation { duration: 150 }
- }
+ Behavior on color { ColorAnimation { duration: 150 } }
+ Behavior on border.width { NumberAnimation { duration: 150 } }
+ Behavior on border.color { ColorAnimation { duration: 150 } }
}
Rectangle {
@@ -127,19 +157,20 @@ Item {
color: root.activeZone === "right" ? palette.highlightedText : palette.text
opacity: 0.8
}
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: qsTr("(added to context)")
+ font.pixelSize: 12
+ font.italic: true
+ color: root.activeZone === "right" ? palette.highlightedText : palette.text
+ opacity: 0.6
+ }
}
- Behavior on color {
- ColorAnimation { duration: 150 }
- }
-
- Behavior on border.width {
- NumberAnimation { duration: 150 }
- }
-
- Behavior on border.color {
- ColorAnimation { duration: 150 }
- }
+ Behavior on color { ColorAnimation { duration: 150 } }
+ Behavior on border.width { NumberAnimation { duration: 150 } }
+ Behavior on border.color { ColorAnimation { duration: 150 } }
}
Rectangle {
@@ -193,42 +224,67 @@ Item {
onEntered: (drag) => {
if (drag.hasUrls) {
+ root.isDragActive = true
+ root.filesCount = drag.urls.length
splitDropOverlay.visible = true
+ splitDropOverlay.opacity = 1
root.activeZone = ""
}
}
onExited: {
- splitDropOverlay.visible = false
- root.activeZone = ""
+ root.isDragActive = false
+ root.filesCount = 0
+ splitDropOverlay.opacity = 0
+
+ Qt.callLater(function() {
+ if (!root.isDragActive) {
+ splitDropOverlay.visible = false
+ root.activeZone = ""
+ }
+ })
}
onPositionChanged: (drag) => {
- if (drag.x < globalDropArea.width / 2) {
- root.activeZone = "left"
- } else {
- root.activeZone = "right"
+ if (drag.hasUrls) {
+ root.activeZone = drag.x < globalDropArea.width / 2 ? "left" : "right"
}
}
onDropped: (drop) => {
- var targetZone = root.activeZone
- splitDropOverlay.visible = false
- root.activeZone = ""
+ const targetZone = root.activeZone
+ root.isDragActive = false
+ root.filesCount = 0
+ splitDropOverlay.opacity = 0
- if (drop.hasUrls && drop.urls.length > 0) {
- // Convert URLs to array of strings for C++ processing
- var urlStrings = []
- for (var i = 0; i < drop.urls.length; i++) {
- urlStrings.push(drop.urls[i].toString())
- }
-
- if (targetZone === "right") {
- root.filesDroppedToLink(urlStrings)
- } else {
- root.filesDroppedToAttach(urlStrings)
+ Qt.callLater(function() {
+ splitDropOverlay.visible = false
+ root.activeZone = ""
+ })
+
+ if (!drop.hasUrls || drop.urls.length === 0) {
+ return
+ }
+
+ var urlStrings = []
+ for (var i = 0; i < drop.urls.length; i++) {
+ var urlString = drop.urls[i].toString()
+ if (urlString.startsWith("file://") || urlString.indexOf("://") === -1) {
+ urlStrings.push(urlString)
}
}
+
+ if (urlStrings.length === 0) {
+ return
+ }
+
+ drop.accept(Qt.CopyAction)
+
+ if (targetZone === "right") {
+ root.filesDroppedToLink(urlStrings)
+ } else {
+ root.filesDroppedToAttach(urlStrings)
+ }
}
}
}
diff --git a/qodeassist.cpp b/qodeassist.cpp
index 9e0d74a..1499ed3 100644
--- a/qodeassist.cpp
+++ b/qodeassist.cpp
@@ -62,6 +62,7 @@
#include "widgets/CustomInstructionsManager.hpp"
#include "widgets/QuickRefactorDialog.hpp"
#include
+#include
#include
#include
#include
@@ -87,6 +88,8 @@ public:
~QodeAssistPlugin() final
{
+ Chat::ChatFileManager::cleanupGlobalIntermediateStorage();
+
delete m_qodeAssistClient;
if (m_chatOutputPane) {
delete m_chatOutputPane;
@@ -249,6 +252,8 @@ public:
editorContextMenu->addAction(closeChatViewAction.command(),
Core::Constants::G_DEFAULT_THREE);
}
+
+ Chat::ChatFileManager::cleanupGlobalIntermediateStorage();
}
void extensionsInitialized() final {}