diff --git a/CMakeLists.txt b/CMakeLists.txt index 9070687..2a65764 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,6 @@ include(KDECompilerSettings NO_POLICY_SCOPE) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -# libollie.so built by Go (expected in build/ after `make lib`) -set(OLLIE_LIB "${CMAKE_SOURCE_DIR}/build/libollie.so") -set(OLLIE_HEADER "${CMAKE_SOURCE_DIR}/build/libollie.h") - if(OLLIE_KF5) # --- Qt5 / KF5 --- find_package(Qt5 REQUIRED COMPONENTS Core DBus Widgets Quick Qml) @@ -37,27 +33,6 @@ if(OLLIE_KF5) TextEditor ) - # --- Daemon --- - qt5_add_dbus_adaptor(DBUS_ADAPTOR_SRCS - daemon/org.ollie.SessionManager.xml - daemon/session_manager.h SessionManager) - - add_executable(ollie-kde - daemon/main.cpp - daemon/session_manager.cpp - ${DBUS_ADAPTOR_SRCS} - ) - target_include_directories(ollie-kde PRIVATE - ${CMAKE_SOURCE_DIR}/build - ${CMAKE_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ) - target_link_libraries(ollie-kde - Qt5::Core - Qt5::DBus - ${OLLIE_LIB} - ) - # --- System Tray --- add_executable(ollie-tray tray/main.cpp @@ -113,7 +88,7 @@ if(OLLIE_KF5) plasma_install_package(plasmoid org.ollie.plasmoid) # --- Install --- - install(TARGETS ollie-kde ollie-tray DESTINATION ${KDE_INSTALL_BINDIR}) + install(TARGETS ollie-tray DESTINATION ${KDE_INSTALL_BINDIR}) install(TARGETS ollie-plasmoid-plugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/ollie/private) install(FILES plasmoid/plugin/qmldir @@ -126,27 +101,6 @@ else() find_package(KF6 REQUIRED COMPONENTS Runner Notifications CoreAddons Config) find_package(Plasma REQUIRED) - # --- Daemon --- - qt6_add_dbus_adaptor(DBUS_ADAPTOR_SRCS - daemon/org.ollie.SessionManager.xml - daemon/session_manager.h SessionManager) - - add_executable(ollie-kde - daemon/main.cpp - daemon/session_manager.cpp - ${DBUS_ADAPTOR_SRCS} - ) - target_include_directories(ollie-kde PRIVATE - ${CMAKE_SOURCE_DIR}/build - ${CMAKE_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ) - target_link_libraries(ollie-kde - Qt6::Core - Qt6::DBus - ${OLLIE_LIB} - ) - # --- System Tray --- add_executable(ollie-tray tray/main.cpp @@ -203,7 +157,7 @@ else() plasma_install_package(plasmoid org.ollie.plasmoid) # --- Install --- - install(TARGETS ollie-kde ollie-tray DESTINATION ${KDE_INSTALL_BINDIR}) + install(TARGETS ollie-tray DESTINATION ${KDE_INSTALL_BINDIR}) install(TARGETS ollie-plasmoid-plugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/ollie/private) endif() diff --git a/Makefile b/Makefile index 35fa753..793ca48 100644 --- a/Makefile +++ b/Makefile @@ -1,43 +1,33 @@ -# kde-ollie top-level Makefile -# Build order: libollie.so (Go) → ollie-kde daemon (C++/CMake) +# kde-ollie Makefile +# Build order: cmake (KDE tools only — daemon is now in ../dbus) BUILD_DIR := build-cmake -LIB_DIR := build -.PHONY: all lib daemon clean run install uninstall \ +.PHONY: all clean run install uninstall \ kf5 kf5-install kf5-uninstall \ krunner-install dolphin-install plasmoid-install plasmoid-uninstall \ tray data -all: daemon data +all: build data -# Step 1: Build libollie.so from Go -lib: $(LIB_DIR)/libollie.so - -$(LIB_DIR)/libollie.so: lib/capi.go lib/go.mod - cd lib && go build -buildmode=c-shared -o ../$(LIB_DIR)/libollie.so - -# Step 2: Build the C++ daemon against libollie.so -daemon: lib +# Build KDE tools (tray, krunner, kate, plasmoid) +build: cmake -B $(BUILD_DIR) -S . cmake --build $(BUILD_DIR) -# Step 2b: Build using KF5/Qt5 (for Plasma 5.27) +# Build using KF5/Qt5 (for Plasma 5.27) KF5_BUILD_DIR := build-kf5 -kf5: lib +kf5: cmake -B $(KF5_BUILD_DIR) -S . -DOLLIE_KF5=ON cmake --build $(KF5_BUILD_DIR) # --- KF6 Install (default) --- -install: daemon +install: build @echo "=== Installing ollie-kde (KF6) ===" - # Daemon + tray binaries - install -m755 $(BUILD_DIR)/ollie-kde /usr/bin/ + # Tray binary install -m755 $(BUILD_DIR)/ollie-tray /usr/bin/ - # Go shared library - install -m755 $(LIB_DIR)/libollie.so /usr/lib64/ # KRunner plugin mkdir -p /usr/lib64/qt6/plugins/kf6/krunner install -m755 $(BUILD_DIR)/lib/kf6/krunner/krunner_ollie.so \ @@ -64,8 +54,6 @@ install: daemon install -m755 dolphin/ollie-actions.desktop ~/.local/share/kio/servicemenus/ install -m755 dolphin/ollie-ask /usr/local/bin/ install -m755 dolphin/ollie-session-here /usr/local/bin/ - # XDG autostart - install -m644 org.ollie.SessionManager.desktop /etc/xdg/autostart/ # Finalize ldconfig kquitapp6 krunner 2>/dev/null; true @@ -75,23 +63,21 @@ install: daemon uninstall: @echo "=== Uninstalling ollie-kde ===" - pkill -u "$$(id -u)" -x ollie-kde 2>/dev/null; true - rm -f /usr/bin/ollie-kde /usr/bin/ollie-tray - rm -f /usr/lib64/libollie.so /usr/lib64/libollie-plasmoid-plugin.so + rm -f /usr/bin/ollie-tray + rm -f /usr/lib64/libollie-plasmoid-plugin.so rm -f /usr/lib64/qt6/plugins/kf6/krunner/krunner_ollie.so rm -f /usr/lib64/qt6/plugins/kf6/ktexteditor/ollie_kate.so rm -rf /usr/lib64/qt6/qml/org/ollie kpackagetool6 -t Plasma/Applet -r org.ollie.plasmoid 2>/dev/null; true rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop rm -f /usr/local/bin/ollie-ask /usr/local/bin/ollie-session-here - rm -f /etc/xdg/autostart/org.ollie.SessionManager.desktop ldconfig kquitapp6 krunner 2>/dev/null; true @echo "=== Uninstall complete ===" # --- Individual component installs --- -krunner-install: daemon +krunner-install: build mkdir -p /usr/lib64/qt6/plugins/kf6/krunner install -m755 $(BUILD_DIR)/lib/kf6/krunner/krunner_ollie.so \ /usr/lib64/qt6/plugins/kf6/krunner/ @@ -106,7 +92,7 @@ dolphin-install: install -m755 dolphin/ollie-session-here /usr/local/bin/ @echo "Dolphin menus installed. Restart Dolphin or re-open context menu." -plasmoid-install: daemon +plasmoid-install: build kpackagetool6 -t Plasma/Applet -r org.ollie.plasmoid 2>/dev/null; true kpackagetool6 -t Plasma/Applet -i plasmoid/ mkdir -p /usr/lib64/qt6/qml/org/ollie/private @@ -131,11 +117,8 @@ plasmoid-uninstall: kf5-install: kf5 @echo "=== Installing ollie-kde (KF5) ===" - # Daemon + tray binaries - install -m755 $(KF5_BUILD_DIR)/ollie-kde /usr/bin/ + # Tray binary install -m755 $(KF5_BUILD_DIR)/ollie-tray /usr/bin/ - # Go shared library - install -m755 $(LIB_DIR)/libollie.so /usr/lib/x86_64-linux-gnu/ # KRunner plugin mkdir -p /usr/lib/x86_64-linux-gnu/qt5/plugins/kf5/krunner install -m755 $(KF5_BUILD_DIR)/lib/krunner_ollie.so \ @@ -163,8 +146,6 @@ kf5-install: kf5 install -m755 dolphin/ollie-actions-kf5.desktop ~/.local/share/kio/servicemenus/ollie-actions.desktop install -m755 dolphin/ollie-ask /usr/local/bin/ install -m755 dolphin/ollie-session-here /usr/local/bin/ - # XDG autostart - install -m644 org.ollie.SessionManager.desktop /etc/xdg/autostart/ # Finalize ldconfig kquitapp5 krunner 2>/dev/null; true @@ -174,16 +155,13 @@ kf5-install: kf5 kf5-uninstall: @echo "=== Uninstalling ollie-kde (KF5) ===" - pkill -u "$$(id -u)" -x ollie-kde 2>/dev/null; true - rm -f /usr/bin/ollie-kde /usr/bin/ollie-tray - rm -f /usr/lib/x86_64-linux-gnu/libollie.so + rm -f /usr/bin/ollie-tray rm -f /usr/lib/x86_64-linux-gnu/qt5/plugins/kf5/krunner/krunner_ollie.so rm -f /usr/lib/x86_64-linux-gnu/qt5/plugins/ktexteditor/ollie_kate.so rm -rf /usr/lib/x86_64-linux-gnu/qt5/qml/org/ollie kpackagetool5 -t Plasma/Applet -r org.ollie.plasmoid 2>/dev/null; true rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop rm -f /usr/local/bin/ollie-ask /usr/local/bin/ollie-session-here - rm -f /etc/xdg/autostart/org.ollie.SessionManager.desktop ldconfig kquitapp5 krunner 2>/dev/null; true @echo "=== Uninstall complete (KF5) ===" @@ -203,12 +181,8 @@ data: # --- Development helpers --- -run: daemon - LD_LIBRARY_PATH=$(LIB_DIR):$$LD_LIBRARY_PATH ./$(BUILD_DIR)/ollie-kde - -tray: daemon +tray: build ./$(BUILD_DIR)/ollie-tray clean: - rm -rf $(BUILD_DIR) - rm -f $(LIB_DIR)/libollie.so $(LIB_DIR)/libollie.h + rm -rf $(BUILD_DIR) $(KF5_BUILD_DIR) diff --git a/README.md b/README.md index b2d05dd..3851053 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # ollie-kde -KDE-native integration for [ollie](https://github.com/lkn/ollie) — a long-lived -D-Bus daemon that manages AI agent sessions, with thin KDE clients (system tray, -Plasmoid, KRunner, Kate plugin, Dolphin menus). +KDE-native integration for [ollie](https://github.com/lkn/ollie) — thin KDE +clients (system tray, Plasmoid, KRunner, Kate plugin, Dolphin menus) that talk +to the `ollied` D-Bus daemon. ## Architecture @@ -13,114 +13,57 @@ Plasmoid, KRunner, Kate plugin, Dolphin menus). └──────────────────────────┬───────────────────────────────────┘ │ D-Bus (org.ollie.SessionManager) ┌──────────────────────────┴───────────────────────────────────┐ -│ ollie-kde daemon │ -│ C++ Qt6 │ D-Bus adaptor │ libollie.so (Go) │ +│ ollied (../dbus) │ +│ Pure Go │ godbus │ ollie/core │ └──────────────────────────────────────────────────────────────┘ ``` -The daemon owns all sessions and the Go runtime (libollie.so). KDE components -are pure D-Bus clients — lightweight, stateless, and independently restartable. +The daemon lives in `../dbus/` (the `ollie-dbus` submodule). KDE components +here are pure D-Bus clients — lightweight, stateless, and independently +restartable. ## Dependencies -- Go 1.25+ - Qt 6 (Core, DBus, Widgets, Quick) or Qt 5 (Core, DBus, Widgets, Quick, Qml) - KDE Frameworks 6 (StatusNotifierItem, Runner, TextEditor, CoreAddons, Config) or KDE Frameworks 5 (Notifications, Runner, TextEditor, CoreAddons, Config, Plasma) - Plasma 6 or Plasma 5 (for Plasmoid) - ECM (Extra CMake Modules) -- ollie/core (sibling directory at `../ollie/core`) -KF6/Qt6 is the default (`CMakeLists.txt`). To build against KF5/Qt5, point CMake -at the alternate file: +KF6/Qt6 is the default. To build against KF5/Qt5: ```sh -cmake -S . -B build-cmake -DCMAKE_PROJECT_INCLUDE=CMakeLists-kf5.txt -# or copy/symlink it: -ln -sf CMakeLists-kf5.txt CMakeLists.txt +make kf5 ``` ## Build ```sh -make # builds libollie.so (Go) then ollie-kde + ollie-tray (CMake) +make # builds tray + KRunner + Kate + Plasmoid via CMake ``` Outputs: -- `build/libollie.so` — Go shared library (cgo c-shared) -- `build-cmake/ollie-kde` — D-Bus daemon - `build-cmake/ollie-tray` — system tray icon -- `build-cmake/lib/kf6/krunner/krunner_ollie.so` — KRunner plugin (kf5/ on KF5 builds) -- `build-cmake/lib/kf6/ktexteditor/ollie_kate.so` — Kate plugin (kf5/ on KF5 builds) +- `build-cmake/lib/kf6/krunner/krunner_ollie.so` — KRunner plugin +- `build-cmake/lib/kf6/ktexteditor/ollie_kate.so` — Kate plugin - `build-cmake/org/ollie/private/` — Plasmoid QML plugin ## Install ```sh -# Daemon + tray -sudo install -m755 build-cmake/ollie-kde /usr/bin/ -sudo install -m755 build/libollie.so /usr/lib64/ +sudo make install # all KDE components (KF6) +sudo make kf5-install # all KDE components (KF5) -# KRunner plugin (use kf5/ and qt5 paths on KF5 builds) -sudo cp build-cmake/lib/kf6/krunner/krunner_ollie.so /usr/lib64/qt6/plugins/kf6/krunner/ - -# Kate plugin -sudo cp build-cmake/lib/kf6/ktexteditor/ollie_kate.so /usr/lib64/qt6/plugins/kf6/ktexteditor/ - -# Plasmoid -make plasmoid-install - -# KRunner (restart needed) +# Individual: make krunner-install - -# Dolphin service menus make dolphin-install - -# System tray (optional standalone) -sudo install -m755 build-cmake/ollie-tray /usr/bin/ +make plasmoid-install ``` -## Service Setup - -The daemon starts automatically via XDG autostart when you log into a KDE Plasma -session. No manual service configuration is needed after `make install`. - -To disable autostart without uninstalling: - -```sh -# Per-user override -cp /etc/xdg/autostart/org.ollie.SessionManager.desktop ~/.config/autostart/ -echo "Hidden=true" >> ~/.config/autostart/org.ollie.SessionManager.desktop -``` - -### Manual - -```sh -make run # foreground, for development -``` +The D-Bus daemon (`ollied`) is installed separately from the `../dbus/` submodule. ## Usage -### D-Bus API - -The daemon registers as `org.ollie.SessionManager` on the session bus. - -```sh -# Create a session -dbus-send --session --dest=org.ollie.SessionManager --type=method_call --print-reply \ - /org/ollie/SessionManager org.ollie.SessionManager.CreateSession \ - string:"$HOME" string:"" string:"" string:"default" - -# Submit a prompt -dbus-send --session --dest=org.ollie.SessionManager --type=method_call --print-reply \ - /org/ollie/SessionManager org.ollie.SessionManager.Submit \ - string:"" string:"your prompt here" - -# Get chat output -gdbus call --session --dest org.ollie.SessionManager --object-path /org/ollie/SessionManager \ - --method org.ollie.SessionManager.GetChat "" 0 -``` - ### KRunner - `ollie ` — one-shot: creates session, submits, shows popup with result @@ -158,48 +101,12 @@ Add the "Ollie" widget to your panel or desktop: - Status: passive (no sessions), active (sessions idle), attention (agent working) - Right-click: New Session, Sessions submenu (kill each), Stop All, Quit -## D-Bus Interface - -Methods: -- `CreateSession(cwd, backend, model, agent) → session_id` -- `ListSessions() → [id\tstate\tmodel\tagent, ...]` -- `KillSession(session_id) → success` -- `RenameSession(session_id, new_name) → success` -- `Submit(session_id, prompt) → success` -- `Interrupt(session_id) → success` -- `GetState(session_id) → state` -- `GetChat(session_id, offset) → text, new_offset` -- `GetUsage(session_id) → usage` -- `GetCost(session_id) → cost` -- `GetConfig(session_id) → key=value pairs` -- `SetConfig(session_id, key, value) → success` -- `GetContext(session_id) → JSONL messages` -- `ListBackends() → [names]` -- `ListModels(session_id) → [names]` -- `ListAgents() → [names]` -- `PeerAdd(session_id, peer_id) → success` -- `PeerRemove(session_id, peer_id) → success` -- `PeerList(session_id) → [peer_ids]` -- `PeerSubmit(session_id, peer_id, prompt) → success` - -Signals: -- `SessionCreated(session_id)` -- `SessionKilled(session_id)` -- `StateChanged(session_id, new_state)` -- `ChatUpdated(session_id, offset, new_text)` - ## File Layout ``` ollie-kde/ -├── Makefile # Go + CMake orchestration +├── Makefile # CMake orchestration ├── CMakeLists.txt -├── lib/ -│ └── capi.go # cgo exports (libollie.so) -├── daemon/ -│ ├── main.cpp # D-Bus registration, event loop -│ ├── session_manager.h/cpp # D-Bus adaptee, bridges C API -│ └── org.ollie.SessionManager.xml ├── tray/ │ ├── main.cpp │ └── ollie_tray.h/cpp # KStatusNotifierItem @@ -218,6 +125,5 @@ ollie-kde/ │ ├── ollie-actions.desktop # Service menu entries │ ├── ollie-ask # One-shot helper script │ └── ollie-session-here # Session creation helper -├── org.ollie.SessionManager.desktop # XDG autostart entry └── test-e2e.sh # End-to-end test script ``` diff --git a/daemon/main.cpp b/daemon/main.cpp deleted file mode 100644 index 39ecf21..0000000 --- a/daemon/main.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -#include "session_manager.h" -#include "sessionmanageradaptor.h" // generated by qt6_add_dbus_adaptor - -// Async-signal-safe shutdown via socketpair -static int sigFd[2]; - -static void signalHandler(int) -{ - char c = 1; - write(sigFd[0], &c, 1); -} - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - app.setApplicationName("ollie-kde"); - app.setOrganizationName("ollie"); - - // Set up signal handling via socketpair (async-signal-safe) - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0) { - qCritical() << "Cannot create signal socketpair"; - return 1; - } - - auto *sigNotifier = new QSocketNotifier(sigFd[1], QSocketNotifier::Read, &app); - QObject::connect(sigNotifier, &QSocketNotifier::activated, &app, [&]() { - char c; - read(sigFd[1], &c, 1); - qDebug() << "Received shutdown signal, exiting gracefully..."; - app.quit(); - }); - - signal(SIGTERM, signalHandler); - signal(SIGINT, signalHandler); - - // Create the session manager (initializes ollie core) - SessionManager manager; - - // Create the D-Bus adaptor (generated from XML) - new SessionManagerAdaptor(&manager); - - // Register on the session bus - QDBusConnection bus = QDBusConnection::sessionBus(); - if (!bus.isConnected()) { - qCritical() << "Cannot connect to D-Bus session bus"; - return 1; - } - - if (!bus.registerService("org.ollie.SessionManager")) { - qCritical() << "Cannot register D-Bus service org.ollie.SessionManager:" - << bus.lastError().message(); - return 1; - } - - if (!bus.registerObject("/org/ollie/SessionManager", &manager)) { - qCritical() << "Cannot register D-Bus object /org/ollie/SessionManager:" - << bus.lastError().message(); - return 1; - } - - qDebug() << "ollie-kde daemon started on D-Bus: org.ollie.SessionManager"; - - int rc = app.exec(); - - qDebug() << "ollie-kde daemon exiting"; - return rc; -} diff --git a/daemon/org.ollie.SessionManager.xml b/daemon/org.ollie.SessionManager.xml deleted file mode 100644 index 4be2fa6..0000000 --- a/daemon/org.ollie.SessionManager.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/daemon/session_manager.cpp b/daemon/session_manager.cpp deleted file mode 100644 index c2ca453..0000000 --- a/daemon/session_manager.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include "session_manager.h" -#include "libollie.h" - -#include -#include -#include - -// Global pointer to the singleton — used by C callbacks to route events. -static SessionManager *g_instance = nullptr; - -// --- C callback handlers (called from Go goroutines, must be thread-safe) --- - -static void onStateChange(const char *session_id, const char *state) -{ - if (!g_instance) return; - QString sid = QString::fromUtf8(session_id); - QString st = QString::fromUtf8(state); - QMetaObject::invokeMethod(g_instance, "handleStateChange", - Qt::QueuedConnection, - Q_ARG(QString, sid), Q_ARG(QString, st)); -} - -static void onChatUpdate(const char *session_id, int64_t offset, const char *text, int len) -{ - if (!g_instance) return; - QString sid = QString::fromUtf8(session_id); - QString txt = QString::fromUtf8(text, len); - qlonglong off = static_cast(offset); - QMetaObject::invokeMethod(g_instance, [sid, off, txt]() { - emit g_instance->ChatUpdated(sid, off, txt); - }, Qt::QueuedConnection); -} - -// --- SessionManager implementation --- - -SessionManager::SessionManager(QObject *parent) - : QObject(parent) -{ - g_instance = this; - ollie_init(nullptr); - installCallbacks(); - qDebug() << "SessionManager: initialized ollie core"; -} - -SessionManager::~SessionManager() -{ - ollie_shutdown(); - g_instance = nullptr; - qDebug() << "SessionManager: shut down ollie core"; -} - -void SessionManager::installCallbacks() -{ - ollie_on_state_change(onStateChange); - ollie_on_chat_update(onChatUpdate); -} - -// --- Session lifecycle --- - -QString SessionManager::CreateSession(const QString &cwd, const QString &backend, - const QString &model, const QString &agent) -{ - QByteArray cwdUtf8 = cwd.toUtf8(); - QByteArray backendUtf8 = backend.toUtf8(); - QByteArray modelUtf8 = model.toUtf8(); - QByteArray agentUtf8 = agent.toUtf8(); - - char *outID = nullptr; - int rc = ollie_create_session( - const_cast(cwdUtf8.constData()), - const_cast(backendUtf8.constData()), - const_cast(modelUtf8.constData()), - const_cast(agentUtf8.constData()), - &outID); - if (rc != 0 || !outID) { - qWarning() << "CreateSession failed, rc=" << rc; - return QString(); - } - - QString sessionID = QString::fromUtf8(outID); - ollie_free(outID); - - emit SessionCreated(sessionID); - return sessionID; -} - -QStringList SessionManager::ListSessions() -{ - char *buf = nullptr; - ollie_list_sessions(&buf); - QStringList result; - - if (buf) { - QString raw = QString::fromUtf8(buf); - ollie_free(buf); - result = raw.split('\n', Qt::SkipEmptyParts); - } - return result; -} - -bool SessionManager::KillSession(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - int rc = ollie_kill_session(const_cast(idUtf8.constData())); - if (rc == 0) { - m_sessionStates.remove(session_id); - emit SessionKilled(session_id); - return true; - } - return false; -} - -bool SessionManager::RenameSession(const QString &session_id, const QString &new_name) -{ - QByteArray idUtf8 = session_id.toUtf8(); - QByteArray nameUtf8 = new_name.toUtf8(); - int rc = ollie_rename_session( - const_cast(idUtf8.constData()), - const_cast(nameUtf8.constData())); - return rc == 0; -} - -// --- Interaction --- - -bool SessionManager::Submit(const QString &session_id, const QString &prompt) -{ - QByteArray idUtf8 = session_id.toUtf8(); - QByteArray promptUtf8 = prompt.toUtf8(); - int rc = ollie_submit( - const_cast(idUtf8.constData()), - const_cast(promptUtf8.constData())); - return rc == 0; -} - -bool SessionManager::Interrupt(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - int rc = ollie_interrupt(const_cast(idUtf8.constData())); - return rc == 0; -} - -// --- State queries --- - -QString SessionManager::GetState(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int rc = ollie_get_state(const_cast(idUtf8.constData()), &out); - if (rc != 0 || !out) return QString(); - QString state = QString::fromUtf8(out); - ollie_free(out); - return state; -} - -QString SessionManager::GetChat(const QString &session_id, qlonglong offset, qlonglong &new_offset) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int64_t newOff = 0; - int rc = ollie_get_chat( - const_cast(idUtf8.constData()), - static_cast(offset), &out, &newOff); - if (rc != 0 || !out) { - new_offset = offset; - return QString(); - } - QString text = QString::fromUtf8(out); - ollie_free(out); - new_offset = static_cast(newOff); - return text; -} - -QString SessionManager::GetUsage(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int rc = ollie_get_usage(const_cast(idUtf8.constData()), &out); - if (rc != 0 || !out) return QString(); - QString usage = QString::fromUtf8(out); - ollie_free(out); - return usage; -} - -QString SessionManager::GetCost(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int rc = ollie_get_cost(const_cast(idUtf8.constData()), &out); - if (rc != 0 || !out) return QString(); - QString cost = QString::fromUtf8(out); - ollie_free(out); - return cost; -} - -// --- Config --- - -QString SessionManager::GetConfig(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int rc = ollie_get_config(const_cast(idUtf8.constData()), &out); - if (rc != 0 || !out) return QString(); - QString config = QString::fromUtf8(out); - ollie_free(out); - return config; -} - -bool SessionManager::SetConfig(const QString &session_id, const QString &key, const QString &value) -{ - QByteArray idUtf8 = session_id.toUtf8(); - QByteArray keyUtf8 = key.toUtf8(); - QByteArray valueUtf8 = value.toUtf8(); - int rc = ollie_set_config( - const_cast(idUtf8.constData()), - const_cast(keyUtf8.constData()), - const_cast(valueUtf8.constData())); - return rc == 0; -} - -// --- Context --- - -QString SessionManager::GetContext(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int rc = ollie_get_context(const_cast(idUtf8.constData()), &out); - if (rc != 0 || !out) return QString(); - QString context = QString::fromUtf8(out); - ollie_free(out); - return context; -} - -// --- Backends/models/agents --- - -QStringList SessionManager::ListBackends() -{ - char *out = nullptr; - ollie_list_backends(&out); - if (!out) return {}; - QString raw = QString::fromUtf8(out); - ollie_free(out); - return raw.split('\n', Qt::SkipEmptyParts); -} - -QStringList SessionManager::ListModels(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - int rc = ollie_list_models(const_cast(idUtf8.constData()), &out); - if (rc != 0 || !out) return {}; - QString raw = QString::fromUtf8(out); - ollie_free(out); - return raw.split('\n', Qt::SkipEmptyParts); -} - -QStringList SessionManager::ListAgents() -{ - char *out = nullptr; - ollie_list_agents(&out); - if (!out) return {}; - QString raw = QString::fromUtf8(out); - ollie_free(out); - return raw.split('\n', Qt::SkipEmptyParts); -} - -// --- Peers --- - -bool SessionManager::PeerAdd(const QString &session_id, const QString &peer_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - QByteArray peerUtf8 = peer_id.toUtf8(); - int rc = ollie_peer_add( - const_cast(idUtf8.constData()), - const_cast(peerUtf8.constData())); - return rc == 0; -} - -bool SessionManager::PeerRemove(const QString &session_id, const QString &peer_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - QByteArray peerUtf8 = peer_id.toUtf8(); - int rc = ollie_peer_remove( - const_cast(idUtf8.constData()), - const_cast(peerUtf8.constData())); - return rc == 0; -} - -QStringList SessionManager::PeerList(const QString &session_id) -{ - QByteArray idUtf8 = session_id.toUtf8(); - char *out = nullptr; - ollie_peer_list(const_cast(idUtf8.constData()), &out); - if (!out) return {}; - QString raw = QString::fromUtf8(out); - ollie_free(out); - return raw.split('\n', Qt::SkipEmptyParts); -} - -bool SessionManager::PeerSubmit(const QString &session_id, const QString &peer_id, const QString &prompt) -{ - QByteArray idUtf8 = session_id.toUtf8(); - QByteArray peerUtf8 = peer_id.toUtf8(); - QByteArray promptUtf8 = prompt.toUtf8(); - int rc = ollie_peer_submit( - const_cast(idUtf8.constData()), - const_cast(peerUtf8.constData()), - const_cast(promptUtf8.constData())); - return rc == 0; -} - -// --- Notifications --- - -void SessionManager::handleStateChange(const QString &session_id, const QString &new_state) -{ - QString prev = m_sessionStates.value(session_id, "idle"); - m_sessionStates[session_id] = new_state; - - if (new_state == "idle" && prev != "idle") { - sendNotification("Ollie", "Session " + session_id + " finished"); - } - - emit StateChanged(session_id, new_state); -} - -void SessionManager::sendNotification(const QString &title, const QString &body) -{ - QDBusInterface notifyIface( - "org.freedesktop.Notifications", - "/org/freedesktop/Notifications", - "org.freedesktop.Notifications", - QDBusConnection::sessionBus()); - notifyIface.call("Notify", - "ollie-kde", // app_name - (uint)0, // replaces_id - "system-run", // app_icon - title, // summary - body, // body - QStringList(), // actions - QVariantMap(), // hints - (int)5000); // timeout ms -} diff --git a/daemon/session_manager.h b/daemon/session_manager.h deleted file mode 100644 index 4795ce2..0000000 --- a/daemon/session_manager.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef SESSION_MANAGER_H -#define SESSION_MANAGER_H - -#include -#include -#include -#include -#include -#include - -// SessionManager is the D-Bus adaptee. The generated SessionManagerAdaptor -// (from qt6_add_dbus_adaptor) forwards D-Bus method calls to slots here. -// Signals defined here are relayed by the adaptor onto the bus. - -class SessionManager : public QObject -{ - Q_OBJECT - -public: - explicit SessionManager(QObject *parent = nullptr); - ~SessionManager() override; - -public slots: - // Session lifecycle - QString CreateSession(const QString &cwd, const QString &backend, - const QString &model, const QString &agent); - QStringList ListSessions(); - bool KillSession(const QString &session_id); - bool RenameSession(const QString &session_id, const QString &new_name); - - // Interaction - bool Submit(const QString &session_id, const QString &prompt); - bool Interrupt(const QString &session_id); - - // State queries - QString GetState(const QString &session_id); - QString GetChat(const QString &session_id, qlonglong offset, qlonglong &new_offset); - QString GetUsage(const QString &session_id); - QString GetCost(const QString &session_id); - - // Config - QString GetConfig(const QString &session_id); - bool SetConfig(const QString &session_id, const QString &key, const QString &value); - - // Context - QString GetContext(const QString &session_id); - - // Backends/models/agents - QStringList ListBackends(); - QStringList ListModels(const QString &session_id); - QStringList ListAgents(); - - // Peers - bool PeerAdd(const QString &session_id, const QString &peer_id); - bool PeerRemove(const QString &session_id, const QString &peer_id); - QStringList PeerList(const QString &session_id); - bool PeerSubmit(const QString &session_id, const QString &peer_id, const QString &prompt); - -signals: - void SessionCreated(const QString &session_id); - void SessionKilled(const QString &session_id); - void StateChanged(const QString &session_id, const QString &new_state); - void ChatUpdated(const QString &session_id, qlonglong offset, const QString &new_text); - -private: - void installCallbacks(); - void sendNotification(const QString &title, const QString &body); - - QHash m_sessionStates; - -private slots: - void handleStateChange(const QString &session_id, const QString &new_state); -}; - -#endif // SESSION_MANAGER_H diff --git a/lib/capi.go b/lib/capi.go deleted file mode 100644 index 9a55e45..0000000 --- a/lib/capi.go +++ /dev/null @@ -1,635 +0,0 @@ -package main - -/* -#include -#include - -// Callback typedefs — set by the C++ daemon to receive push events. -typedef void (*ollie_state_cb)(const char *session_id, const char *state); -typedef void (*ollie_chat_cb)(const char *session_id, int64_t offset, const char *text, int len); - -// Trampolines: cgo cannot call function pointers directly from Go. -static inline void ollie_state_cb_invoke(ollie_state_cb cb, const char *sid, const char *state) { - if (cb) cb(sid, state); -} -static inline void ollie_chat_cb_invoke(ollie_chat_cb cb, const char *sid, int64_t offset, const char *text, int len) { - if (cb) cb(sid, offset, text, len); -} -*/ -import "C" -import ( - "context" - "encoding/json" - "fmt" - "os" - "sync" - "unsafe" - - "ollie/pkg/agent" - "ollie/pkg/backend" - "ollie/pkg/config" - "ollie/pkg/env" - "ollie/pkg/paths" - "ollie/pkg/tools" - "ollie/pkg/tools/execute" -) - -// --- Global state --- - -var ( - mu sync.RWMutex - sessions map[string]*managedSession - stateCB C.ollie_state_cb - chatCB C.ollie_chat_cb -) - -// managedSession wraps a Core with its context and metadata. -type managedSession struct { - core agent.Core - ctx context.Context - cancel context.CancelFunc - id string - agent string - log []byte - logMu sync.Mutex - peers map[string]bool -} - -// --- Lifecycle --- - -//export ollie_init -func ollie_init(configPath *C.char) C.int { - env.EnsureDefaults() - mu.Lock() - sessions = make(map[string]*managedSession) - mu.Unlock() - return 0 -} - -//export ollie_shutdown -func ollie_shutdown() { - mu.Lock() - for id, sess := range sessions { - sess.core.Interrupt(agent.ErrInterrupted) - sess.core.Close() - sess.cancel() - delete(sessions, id) - } - mu.Unlock() -} - -// --- Sessions --- - -//export ollie_create_session -func ollie_create_session(cwdC *C.char, backendC *C.char, modelC *C.char, agentC *C.char, outID **C.char) C.int { - cwd := C.GoString(cwdC) - backendName := C.GoString(backendC) - modelName := C.GoString(modelC) - agentName := C.GoString(agentC) - - if cwd == "" { - cwd, _ = os.Getwd() - } - cwd = paths.ExpandHome(os.ExpandEnv(cwd)) - - if agentName == "" { - agentName = "default" - if v := os.Getenv("OLLIE_DEFAULT_AGENT"); v != "" { - agentName = v - } - } - - sessID := agent.NewSessionID() - - // Load agent config - agentsDir := paths.CfgDir() + "/agents" - var cfg *config.Config - cfgPath := agent.AgentConfigPath(agentsDir, agentName) - if f, err := os.Open(cfgPath); err == nil { - cfg, _ = config.Load(f) - f.Close() - } - - // Resolve backend - if backendName == "" && cfg != nil && cfg.Backend != "" { - backendName = cfg.Backend - } - be, err := backend.NewWithName(backendName) - if err != nil { - return -1 - } - - // Resolve model - if modelName == "" && cfg != nil && cfg.Model != "" { - modelName = cfg.Model - } - if modelName == "" { - modelName = os.Getenv("OLLIE_MODEL") - } - if modelName != "" { - be.SetModel(modelName) - } - - // Sessions dir - sessionsDir := paths.DataDir() + "/sessions" - os.MkdirAll(sessionsDir, 0700) - - // Build dispatcher + runtime - newDisp := tools.NewDispatcherFunc(map[string]func() tools.Server{ - "execute": execute.Decl(cwd), - }) - rt := agent.BuildRuntime(cfg, newDisp(), cwd, []string{"OLLIE_SESSION_ID=" + sessID}) - - // Create the agent core - core := agent.NewAgentCore(agent.AgentCoreConfig{ - Backend: be, - AgentName: agentName, - AgentsDir: agentsDir, - SessionsDir: sessionsDir, - SessionID: sessID, - CWD: cwd, - Runtime: rt, - }) - - ctx, cancel := context.WithCancel(context.Background()) - sess := &managedSession{ - core: core, - ctx: ctx, - cancel: cancel, - id: sessID, - agent: agentName, - } - - // Subscribe to events for the chat log + callback dispatch - streamingRole := "" // tracks current streaming role ("assistant" or "reasoning") - core.Bus().Subscribe("event", func(ev agent.Event) { - var text string - switch ev.Role { - case "assistant", "reasoning": - if streamingRole != ev.Role { - if streamingRole != "" { - text += "\n\n" - } - text += "[" + ev.Role + "]\n" - streamingRole = ev.Role - } - text += ev.Content - default: - if ev.Role == "usage" { - return - } - if streamingRole != "" { - text += "\n\n" - streamingRole = "" - } - switch ev.Role { - case "user": - text += "[user]\n" + ev.Content + "\n\n" - case "call": - text += "[call:" + ev.Name + "]\n" + ev.Content + "\n\n" - case "tool": - text += "[tool:" + ev.Name + "]\n" + ev.Content + "\n\n" - case "error": - text += "[error]\n" + ev.Content + "\n\n" - case "info": - text += "[info] " + ev.Content + "\n\n" - default: - text += "[" + ev.Role + "]\n" + ev.Content + "\n\n" - } - } - if text == "" { - return - } - - sess.logMu.Lock() - offset := int64(len(sess.log)) - sess.log = append(sess.log, []byte(text)...) - sess.logMu.Unlock() - - if chatCB != nil { - cID := C.CString(sess.id) - cText := C.CString(text) - C.ollie_chat_cb_invoke(chatCB, cID, C.int64_t(offset), cText, C.int(len(text))) - C.free(unsafe.Pointer(cID)) - C.free(unsafe.Pointer(cText)) - } - }) - - // Watch state changes in a goroutine - go func() { - current := "idle" - for { - next, ok := core.WaitChange(ctx, agent.WatchState, current) - if !ok { - return - } - current = next - if stateCB != nil { - cID := C.CString(sess.id) - cState := C.CString(current) - C.ollie_state_cb_invoke(stateCB, cID, cState) - C.free(unsafe.Pointer(cID)) - C.free(unsafe.Pointer(cState)) - } - } - }() - - mu.Lock() - sessions[sessID] = sess - mu.Unlock() - - *outID = C.CString(sessID) - return 0 -} - -//export ollie_kill_session -func ollie_kill_session(sessionIDC *C.char) C.int { - id := C.GoString(sessionIDC) - mu.Lock() - sess, ok := sessions[id] - if !ok { - mu.Unlock() - return -1 - } - delete(sessions, id) - mu.Unlock() - - sess.core.Interrupt(agent.ErrInterrupted) - sess.core.Close() - sess.cancel() - return 0 -} - -//export ollie_rename_session -func ollie_rename_session(sessionIDC *C.char, newNameC *C.char) C.int { - id := C.GoString(sessionIDC) - newName := C.GoString(newNameC) - - mu.Lock() - sess, ok := sessions[id] - if !ok { - mu.Unlock() - return -1 - } - delete(sessions, id) - sess.id = newName - sessions[newName] = sess - mu.Unlock() - - if err := sess.core.SetSessionID(newName); err != nil { - mu.Lock() - delete(sessions, newName) - sess.id = id - sessions[id] = sess - mu.Unlock() - return -1 - } - return 0 -} - -//export ollie_list_sessions -func ollie_list_sessions(outBuf **C.char) C.int { - mu.RLock() - defer mu.RUnlock() - - var result string - for id, sess := range sessions { - result += fmt.Sprintf("%s\t%s\t%s\t%s\n", - id, sess.core.State(), sess.core.ModelName(), sess.agent) - } - *outBuf = C.CString(result) - return C.int(len(sessions)) -} - -// --- Interaction --- - -//export ollie_submit -func ollie_submit(sessionIDC *C.char, promptC *C.char) C.int { - id := C.GoString(sessionIDC) - prompt := C.GoString(promptC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - go sess.core.Submit(sess.ctx, prompt) - return 0 -} - -//export ollie_interrupt -func ollie_interrupt(sessionIDC *C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - sess.core.Interrupt(agent.ErrInterrupted) - return 0 -} - -// --- State queries --- - -//export ollie_get_state -func ollie_get_state(sessionIDC *C.char, outState **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - *outState = C.CString(sess.core.State()) - return 0 -} - -//export ollie_get_chat -func ollie_get_chat(sessionIDC *C.char, offset C.int64_t, outText **C.char, outNewOffset *C.int64_t) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - sess.logMu.Lock() - off := int64(offset) - if off < 0 { - off = 0 - } - if off > int64(len(sess.log)) { - off = int64(len(sess.log)) - } - text := string(sess.log[off:]) - newOff := int64(len(sess.log)) - sess.logMu.Unlock() - - *outText = C.CString(text) - *outNewOffset = C.int64_t(newOff) - return 0 -} - -//export ollie_get_usage -func ollie_get_usage(sessionIDC *C.char, out **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - *out = C.CString(sess.core.Usage()) - return 0 -} - -//export ollie_get_cost -func ollie_get_cost(sessionIDC *C.char, out **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - *out = C.CString(sess.core.Cost()) - return 0 -} - -//export ollie_get_config -func ollie_get_config(sessionIDC *C.char, outBuf **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - // Expose key=value pairs for session config - var result string - result += "model=" + sess.core.ModelName() + "\n" - result += "backend=" + sess.core.BackendName() + "\n" - result += "agent=" + sess.agent + "\n" - result += "cwd=" + sess.core.CWD() + "\n" - result += "state=" + sess.core.State() + "\n" - *outBuf = C.CString(result) - return 0 -} - -//export ollie_set_config -func ollie_set_config(sessionIDC *C.char, keyC *C.char, valueC *C.char) C.int { - id := C.GoString(sessionIDC) - key := C.GoString(keyC) - value := C.GoString(valueC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - switch key { - case "model": - // Submit a /model command to change model - sess.core.Submit(sess.ctx, "/model "+value) - case "cwd": - if err := sess.core.SetCWD(value); err != nil { - return -1 - } - default: - return -1 // unknown key - } - return 0 -} - -//export ollie_get_context -func ollie_get_context(sessionIDC *C.char, outBuf **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - // Return context as JSONL (one JSON message per line) - msgs := sess.core.Context() - var result string - for _, msg := range msgs { - data, err := json.Marshal(msg) - if err != nil { - continue - } - result += string(data) + "\n" - } - *outBuf = C.CString(result) - return 0 -} - -// --- Peers --- - -//export ollie_peer_add -func ollie_peer_add(sessionIDC *C.char, peerIDC *C.char) C.int { - id := C.GoString(sessionIDC) - peerID := C.GoString(peerIDC) - - mu.RLock() - _, ok := sessions[id] - _, peerOk := sessions[peerID] - mu.RUnlock() - if !ok || !peerOk { - return -1 - } - - mu.Lock() - sess := sessions[id] - if sess.peers == nil { - sess.peers = make(map[string]bool) - } - sess.peers[peerID] = true - mu.Unlock() - return 0 -} - -//export ollie_peer_remove -func ollie_peer_remove(sessionIDC *C.char, peerIDC *C.char) C.int { - id := C.GoString(sessionIDC) - peerID := C.GoString(peerIDC) - - mu.Lock() - sess, ok := sessions[id] - if !ok { - mu.Unlock() - return -1 - } - delete(sess.peers, peerID) - mu.Unlock() - return 0 -} - -//export ollie_peer_list -func ollie_peer_list(sessionIDC *C.char, outBuf **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - var result string - for peerID := range sess.peers { - result += peerID + "\n" - } - *outBuf = C.CString(result) - return C.int(len(sess.peers)) -} - -//export ollie_peer_submit -func ollie_peer_submit(sessionIDC *C.char, peerIDC *C.char, promptC *C.char) C.int { - id := C.GoString(sessionIDC) - peerID := C.GoString(peerIDC) - prompt := C.GoString(promptC) - - mu.RLock() - sess, ok := sessions[id] - peer, peerOk := sessions[peerID] - mu.RUnlock() - if !ok || !peerOk { - return -1 - } - - // Verify peer is registered - if !sess.peers[peerID] { - return -1 - } - - // Submit to the peer session - go peer.core.Submit(peer.ctx, prompt) - return 0 -} - -// --- Backends/models/agents --- - -//export ollie_list_backends -func ollie_list_backends(out **C.char) C.int { - backends := "ollama\nopenai\nopenrouter\nanthropic\ncopilot\nkiro\ngemini\n" - *out = C.CString(backends) - return 7 -} - -//export ollie_list_models -func ollie_list_models(sessionIDC *C.char, out **C.char) C.int { - id := C.GoString(sessionIDC) - - mu.RLock() - sess, ok := sessions[id] - mu.RUnlock() - if !ok { - return -1 - } - - *out = C.CString(sess.core.ListModels()) - return 0 -} - -//export ollie_list_agents -func ollie_list_agents(out **C.char) C.int { - var result string - var count int - for _, dir := range agent.AgentsDirs() { - entries, err := os.ReadDir(dir) - if err != nil { - continue - } - for _, e := range entries { - name := e.Name() - if len(name) > 5 && name[len(name)-5:] == ".json" { - result += name[:len(name)-5] + "\n" - count++ - } - } - } - *out = C.CString(result) - return C.int(count) -} - -// --- Callbacks --- - -//export ollie_on_state_change -func ollie_on_state_change(cb C.ollie_state_cb) { - stateCB = cb -} - -//export ollie_on_chat_update -func ollie_on_chat_update(cb C.ollie_chat_cb) { - chatCB = cb -} - -// --- Memory --- - -//export ollie_free -func ollie_free(ptr *C.char) { - C.free(unsafe.Pointer(ptr)) -} - -// main is required for c-shared but never called. -func main() {} diff --git a/lib/go.mod b/lib/go.mod deleted file mode 100644 index b02c17f..0000000 --- a/lib/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module ollie-kde - -go 1.25.6 - -require ollie v0.0.0-00010101000000-000000000000 - -require ( - github.com/simonfxr/pubsub v0.0.5 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) - -replace ollie => ../../core diff --git a/lib/go.sum b/lib/go.sum deleted file mode 100644 index f2c6f57..0000000 --- a/lib/go.sum +++ /dev/null @@ -1,14 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/simonfxr/pubsub v0.0.5 h1:DJfvFoglqGvwJriIOC5NI5um34n2YX8KAU5+7jv768w= -github.com/simonfxr/pubsub v0.0.5/go.mod h1:bQ+B2NEEHZ08VY/0xVFGaGL1KMJ7cl3yLaXe8xvyC24= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/org.ollie.SessionManager.desktop b/org.ollie.SessionManager.desktop deleted file mode 100644 index 09b5752..0000000 --- a/org.ollie.SessionManager.desktop +++ /dev/null @@ -1,12 +0,0 @@ -[Desktop Entry] -Type=Application -Name=Ollie Session Manager -GenericName=AI Agent D-Bus Daemon -Comment=D-Bus session manager for Ollie AI agent sessions -Exec=/usr/bin/ollie-kde -Icon=ollie -Terminal=false -Categories=Utility; -OnlyShowIn=KDE; -X-KDE-autostart-phase=1 -X-DBUS-ServiceName=org.ollie.SessionManager