Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
build/
bin/

# Development tooling
.clangd
compile_commands.json

# CMake files
CMakeCache.txt
CMakeFiles/
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Kate-Code Plugin

A Kate text editor plugin that wraps Claude Code using claude-code-acp.
A Kate text editor plugin that wraps Claude Code using claude-agent-acp.

## Build Instructions

Expand All @@ -22,15 +22,15 @@ Settings > Configure Kate > Plugins > Enable "Kate Code"

### Layer Structure
- **Plugin**: KateCodePlugin, KateCodeView - Kate integration
- **ACP**: ACPService, ACPSession - JSON-RPC 2.0 over stdin/stdout to claude-code-acp
- **ACP**: ACPService, ACPSession - JSON-RPC 2.0 over stdin/stdout to claude-agent-acp
- **MCP**: MCPServer - Built-in MCP server executable for Kate editor tools
- **UI**: ChatWidget, ChatWebView, ChatInputWidget, PermissionDialog
- **Util**: KDEColorScheme - reads ~/.config/kdeglobals

### Key Files
- `src/plugin/KateCodePlugin.{h,cpp}` - Plugin registration via K_PLUGIN_CLASS_WITH_JSON
- `src/plugin/KateCodeView.{h,cpp}` - Creates side panel tool view, provides Kate context
- `src/acp/ACPService.{h,cpp}` - QProcess-based claude-code-acp subprocess management
- `src/acp/ACPService.{h,cpp}` - QProcess-based claude-agent-acp subprocess management
- `src/acp/ACPSession.{h,cpp}` - Protocol flow and session state management
- `src/acp/ACPModels.h` - Data structures (Message, ToolCall, TodoItem, etc.)
- `src/mcp/MCPServer.{h,cpp}` - MCP protocol handler (initialize, tools/list, tools/call)
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(katecode VERSION 1.0.0)
project(katecode VERSION 1.0.1)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand All @@ -21,6 +21,7 @@ find_package(KF6 ${REQUIRED_KF_VERSION} REQUIRED COMPONENTS
SyntaxHighlighting
Wallet
Pty
Parts
)

find_package(Qt6 REQUIRED COMPONENTS
Expand Down
7 changes: 4 additions & 3 deletions PKGBUILD
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Maintainer: Your Name <your.email@example.com>
pkgname=kate-code
pkgver=1.0.0
pkgver=1.0.1
pkgrel=1
pkgdesc="Claude Code integration for Kate text editor"
arch=('x86_64')
url="https://github.com/undefinedopcode/kate-code"
url="https://github.com/molove/kate-code"
license=('MIT')
depends=(
'ktexteditor'
Expand All @@ -15,6 +15,7 @@ depends=(
'kwallet'
'kpty'
'qt6-webengine'
'ttf-material-symbols-variable'
)
makedepends=(
'cmake'
Expand All @@ -24,7 +25,7 @@ makedepends=(
optdepends=(
'claude-code-acp: Required for Claude Code functionality'
)
source=("${pkgname}::git+https://github.com/undefinedopcode/kate-code.git")
source=("${pkgname}::git+https://github.com/molove/kate-code.git")
sha256sums=('SKIP')

build() {
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ See what Claude is doing with inline tool call displays:
- Image paste support: paste images from clipboard directly into chat messages

### Architecture
- **ACP Protocol**: JSON-RPC 2.0 over stdin/stdout with `claude-code-acp` subprocess
- **ACP Protocol**: JSON-RPC 2.0 over stdin/stdout with `claude-agent-acp` subprocess
- **Qt WebChannel**: Bidirectional C++/JavaScript bridge for real-time UI updates
- **Web UI**: HTML/CSS/JS rendered in Qt WebEngineView for rich formatting

Expand All @@ -57,18 +57,18 @@ See what Claude is doing with inline tool call displays:
- C++17 compatible compiler

### Runtime Dependencies
- `claude-code-acp` binary installed and available in PATH
- Install from: https://github.com/zed-industries/claude-code-acp
- `claude-agent-acp` binary installed and available in PATH
- Install from: https://github.com/agentclientprotocol/claude-agent-acp

## Installation

### Install claude-code-acp
### Install claude-agent-acp

Follow the instructions at https://github.com/zed-industries/claude-code-acp to install the ACP binary.
Follow the instructions at https://github.com/agentclientprotocol/claude-agent-acp to install the ACP binary (the installed binary is named `claude-agent-acp`).

Verify installation:
```bash
which claude-code-acp
which claude-agent-acp
```

### Option 1: Install from Package (Recommended)
Expand Down Expand Up @@ -131,8 +131,8 @@ cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build
cmake --build build

# Install to system (requires sudo)
sudo cmake --install build
# Install to system (requires sudo) - Arch/Fedora/most distros need --prefix /usr
sudo cmake --install build --prefix /usr

# Or install to user directory
cmake --install build --prefix ~/.local
Expand All @@ -156,7 +156,7 @@ The plugin will be installed to:
### Starting a Session

1. The Kate Code panel appears in Kate's side panel area (left or right sidebar)
2. Click the **Connect** button to start a claude-code-acp session
2. Click the **Connect** button to start a claude-agent-acp session
3. The plugin will initialize using your current project's directory as the working directory

### Sending Messages
Expand Down Expand Up @@ -241,7 +241,7 @@ The plugin automatically adapts to your KDE color scheme by reading `~/.config/k
- Restart Kate completely (close all windows)

### Connection fails
- Verify `claude-code-acp` is in PATH: `which claude-code-acp`
- Verify `claude-agent-acp` is in PATH: `which claude-agent-acp`
- Look for error messages in terminal when launching Kate from command line: `kate`

### Messages not displaying
Expand Down Expand Up @@ -321,5 +321,5 @@ Contributions welcome! Please:
## Acknowledgments

- Built with Qt 6 and KDE Frameworks 6
- Integrates with [claude-code-acp](https://github.com/zed-industries/claude-code-acp) by Zed Industries
- Integrates with [claude-agent-acp](https://github.com/agentclientprotocol/claude-agent-acp) by Zed Industries
- Markdown rendering by [marked.js](https://marked.js.org/)
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ target_link_libraries(katecode
KF6::SyntaxHighlighting
KF6::Wallet
KF6::Pty
KF6::Parts
Qt6::Core
Qt6::DBus
Qt6::Widgets
Expand Down
2 changes: 1 addition & 1 deletion src/acp/ACPService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ACPService::ACPService(QObject *parent)
: QObject(parent)
, m_process(nullptr)
, m_messageId(0)
, m_executable(QStringLiteral("claude-code-acp"))
, m_executable(QStringLiteral("claude-agent-acp"))
{
}

Expand Down
44 changes: 43 additions & 1 deletion src/acp/ACPSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ void ACPSession::createNewSession()

if (!mcpServerPath.isEmpty() && QFileInfo::exists(mcpServerPath)) {
QJsonObject kateMcp;
kateMcp[QStringLiteral("type")] = QStringLiteral("stdio");
kateMcp[QStringLiteral("name")] = QStringLiteral("kate");
kateMcp[QStringLiteral("command")] = mcpServerPath;
kateMcp[QStringLiteral("args")] = QJsonArray();
Expand Down Expand Up @@ -269,6 +268,27 @@ void ACPSession::loadSession(const QString &sessionId)
params[QStringLiteral("sessionId")] = sessionId;
params[QStringLiteral("cwd")] = m_workingDir;

// Include mcpServers so Kate tools are available in the resumed session
QJsonArray mcpServers;
QString mcpServerPath;
#ifdef KATE_MCP_SERVER_PATH
mcpServerPath = QStringLiteral(KATE_MCP_SERVER_PATH);
#endif
if (mcpServerPath.isEmpty() || !QFileInfo::exists(mcpServerPath)) {
const QString found = QStandardPaths::findExecutable(QStringLiteral("kate-mcp-server"));
if (!found.isEmpty())
mcpServerPath = found;
}
if (!mcpServerPath.isEmpty() && QFileInfo::exists(mcpServerPath)) {
QJsonObject kateMcp;
kateMcp[QStringLiteral("name")] = QStringLiteral("kate");
kateMcp[QStringLiteral("command")] = mcpServerPath;
kateMcp[QStringLiteral("args")] = QJsonArray();
kateMcp[QStringLiteral("env")] = QJsonArray();
mcpServers.append(kateMcp);
}
params[QStringLiteral("mcpServers")] = mcpServers;

m_sessionLoadRequestId = m_service->sendRequest(QStringLiteral("session/load"), params);
qDebug() << "[ACPSession] Sent session/load request, id:" << m_sessionLoadRequestId;
}
Expand Down Expand Up @@ -1728,6 +1748,23 @@ void ACPSession::handleFsWriteTextFile(const QJsonObject &params, int requestId)
// Check if this is a new file
bool isNewFile = !QFile::exists(path);

// Capture old content for diff display before writing
QString oldContent;
if (!isNewFile) {
if (m_documentProvider) {
KTextEditor::Document *doc = m_documentProvider(path);
if (doc) {
oldContent = doc->text();
}
}
if (oldContent.isEmpty()) {
QFile oldFile(path);
if (oldFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
oldContent = QString::fromUtf8(oldFile.readAll());
}
}
}

// Try to write through Kate document if open
if (m_documentProvider) {
KTextEditor::Document *doc = m_documentProvider(path);
Expand Down Expand Up @@ -1797,6 +1834,11 @@ void ACPSession::handleFsWriteTextFile(const QJsonObject &params, int requestId)
}
}

// Emit for diff display (only meaningful if content actually changed)
if (!isNewFile && content != oldContent) {
Q_EMIT fsEditApplied(path, oldContent, content);
}

QJsonObject result;
result[QStringLiteral("result")] = QJsonValue::Null;
m_service->sendResponse(requestId, result);
Expand Down
3 changes: 3 additions & 0 deletions src/acp/ACPSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class ACPSession : public QObject
void terminalOutputUpdated(const QString &terminalId, const QString &output, bool finished);
void toolCallTerminalIdSet(const QString &messageId, const QString &toolCallId, const QString &terminalId);

// Emitted when a built-in Edit/Write tool writes a file, with old and new content for diff display
void fsEditApplied(const QString &filePath, const QString &oldText, const QString &newText);

private Q_SLOTS:
void onConnected();
void onDisconnected(int exitCode);
Expand Down
2 changes: 1 addition & 1 deletion src/config/SettingsStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ void SettingsStore::setAutoResumeSessions(bool enable)
QList<ACPProvider> SettingsStore::builtinProviders() const
{
return {
{QStringLiteral("claude-code"), QStringLiteral("Claude Code"), QStringLiteral("claude-code-acp"), QString(), true},
{QStringLiteral("claude-code"), QStringLiteral("Claude Code"), QStringLiteral("claude-agent-acp"), QString(), true},
{QStringLiteral("vibe-mistral"), QStringLiteral("Vibe (Mistral)"), QStringLiteral("vibe-acp"), QString(), true},
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/katecode.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"Id": "katecode",
"License": "MIT",
"Name": "Kate Code",
"Version": "1.0.0",
"Version": "1.0.1",
"Website": "https://github.com/anthropics/claude-code"
}
}
Loading