Handle events in onPressed instead of onClicked so they work
with editable text. Remove propagateComposedEvents since we
want to intercept middle/right clicks completely.
RMB on text without selection now expands to the word at cursor using
acme's isfilec character set: alphanumeric + . - + / : @
This matches acme behavior for clicking on file paths like foo.go:42
Plumb messages now include the current session's cwd as wdir.
Added sessionCwd() helper to ChatPane and ChatBlockDelegate.
Updated plumber.plumb() to accept optional wdir parameter.
B3 (right-click) now only plumbs selection when available — no fallback
context menu. Mouse chording (B1+B2 cut, B1+B3 paste) still works.
Removed contextMenuComponent and promptContextMenu entirely.
- Convert from Dialog to Window (not modal, separate window)
- Title shows current session name
- Syncs to activeSessionId/activeAgentId changes in main window
- Header shows which session is being displayed
- Double-click row to view output
- Sort processes by PID descending (newest first)
- Clear selection when session changes
The ollie.protocol file was being installed to kservices5/, which is
the KF5 mechanism. KF6 KIO workers embed protocol metadata in the
plugin's JSON file (ollie.json), which we already have.
Remove:
- kio/ollie.protocol file
- CMake install rule for .protocol file
Manual cleanup needed: sudo rm -rf /usr/local/share/kservices5/
- Add procStarted signal to Ollie9pClient for proc.start events
- Add listProcs(), procTerm(), procKill(), procOutput() methods
- Create ProcManagerDialog.qml showing background processes for
the active session/agent with status, runtime, commands
- Add 'Procs' button to action toolbar to open the dialog
- Auto-refresh every 2 seconds when dialog is visible
- Support terminate, kill, and view output actions
The GitWidget delays initialization until showEvent. Find the
QHBoxLayout containing QToolButtons (the button bar) and insert
our button there, next to Commit/Push/Pull buttons.
The GitWidget creates local QMenu objects that can't be intercepted.
Instead, add a QToolButton with dropdown menu to the git tool view:
- Review Staged Changes
- Review Unstaged Changes
- Explain Selected Files
This approach doesn't require Kate source modification.
The previous approach using QMetaObject::invokeMethod on gitWidget()
failed because that method isn't Q_INVOKABLE. The new approach:
- Find git tool view by object name or 'git' in name
- Install event filter to catch QEvent::ChildAdded
- When a QMenu child is added, connect to aboutToShow
- Add Ollie actions to the menu before it's shown
Also add retry timer for setupProjectGitWidget since the plugin
view may not exist at construction time.
- setupProjectGitWidget(): Hook into kateprojectplugin's GitWidget
via gitWidget() method, install event filter on tree view
- addOllieActionsToGitContextMenu(): Add 'Review Staged Changes' and
'Ask About Selection' to the git widget's context menu
- reviewStagedChanges(): Get staged (or unstaged) diff via git process
- askAboutGitSelection(): Ask Ollie about selected files in git view
- onWidgetAdded(): Detect DiffWidget additions by shouldClose() method
- onDiffWidgetContextMenu(): Add 'Review This Diff' to diff widget
- reviewDiffFromWidget(): Extract diff from widget and send to Ollie
- Remove cut/copy/paste menu items from context menu
- Remove paste button (📋) from input row
- Remove B1+B2/B1+B3 chord handling for cut/paste
- Simplify mouse handling to just B2=exec, B3=plumb
- Standard Ctrl+X/C/V still work via TextArea defaults
- Agent cwd is optional; empty = inherit session cwd (the common case)
- Session cwd is required at creation and is the inheritance root
- toolsrv maintains agentCWD map, resolved per call from agent= field
- Override set via agent cfg (cwd=...) or ctl (cwd [<dir>|-])
- Agent.SyncCwdToToolServer re-pushes on every (re)connect
- GUI NewAgentDialog shows '(inherit: <sessionCwd>)' as placeholder
- proc_test.go covers per-agent cwd isolation
- Kate and acme scripts updated for new session/agent creation flow
- AGENTS.md documents the architecture
Agent names derived from cwd using parent:prefix format:
- /home/user/src/ollie -> src:ollie
- /home/user/proj/ABC-123_feature/repo -> abc-123:repo
Updates:
- Kate plugin: one agent per project, git root fallback if no project plugin
- acme-ollie-ensure: single 'acme' session, per-project agents
- ollie-session-here: single 'default' session, per-project agents
Also fixed write -> rdwr for session/agent creation endpoints
Backend:
- Add proc.start/proc.exit events for background process lifecycle
- Add proc idx ctl command for machine-readable process listing (TSV)
- Add event.pub file for external event publishing
- Add ListProcsIdx to toolclient and toolsrv
- Fix bypass commands to use Setpgid for process group isolation
GUI:
- Add configurable bypass approval shortcuts (Ctrl+Y/Ctrl+N default)
- Add Keyboard Shortcuts section to Settings dialog
- Store shortcuts in theme.conf
Kate:
- Fix 'Start Session Here' - use rdwr for session/new endpoint
The isSessionPaused() Q_INVOKABLE didn't trigger QML binding
re-evaluation on pause/resume. New property with proper signal
makes ChatPane bindings reactive.
- activeSessionPaused property tracks active session's paused state
- Updated on refreshSessions() and switchAgent()
- ChatPane.qml uses property instead of function call
Size and margins scale with row height:
- height: 30% of row height
- width: same as height (circular)
- left margin: 15% of row height
- right margin: 25% of row height
Small colored dot to the right of agent name shows execution state:
- Green: idle
- Blue: thinking
- Orange: calling tool
- Gray: paused
Updates reactively via agentStateChanged event signal.
Server emits session.{sid}.agent.{aid}.bypass.resolved with id and
action (approved/denied) when a bypass is resolved by any client.
GUI handles bypass.resolved events to clear the banner and pending
count when CLI or another client resolves a bypass request.
This allows CLI 'o sess approve' to clear the GUI banner automatically.
Track multiple concurrent pending bypasses per agent in C++ backend:
- Add m_pendingBypasses QHash<QString,QSet<QString>> keyed by session:agent
- Add pendingBypassCount(sessionId, agentId) Q_INVOKABLE
- Add pendingBypassCountChanged(sessionId, agentId) signal
- Update resolveBypass to take agentId and remove from tracking set
SessionTree.qml: show ⚠ indicator left of agent name when the agent
has pending bypass requests. Uses Connections to refresh on signal.
ChatPane.qml: pass agentId to resolveBypass calls.
- Changed event topic: session.{sid}.agent.{aid}.bypass.request
- Added agentId parameter to bypassRequested signal
- Filter bypass events to show only for the active agent
The event stream with filtering replaces statewait:
- echo filter | rdwrs event
Removed:
- statewait file from agent namespace
- All non-historical references in docs and code
The state file remains for simple polling reads.
The server event stream already delivers state change events for all
agents. Removed the redundant per-agent statewait streamer - now agent
switching has no teardown/startup overhead for state monitoring.
- Removed m_state streamer entirely
- State updates come via event stream's session.{sid}.agent.{aid}.state events
- Only chat stream needs per-agent setup/teardown
EventValue was storing only the latest event and using hash comparison,
which caused events to be overwritten if they arrived faster than the
client could read them.
Now eventwait uses Stream mode with EventStream which delivers each
event as it arrives. Events won't be lost due to rapid arrival.
Events can be missed if GUI wasn't connected when they were published.
Now checkPendingBypass() reads the bypass file directly when switching
agents/sessions to catch any pending requests.
Server changes:
- Session tracks pending bypass request and exposes methods
- New 9P files: session/{sid}/bypass (read/write), bypasswait (blocking)
- Publish bypass.request events for GUI listeners
GUI changes:
- Handle bypass.request events from eventwait
- Show inline amber banner with command and cwd
- Approve/Deny buttons resolve via 9P
Desktop notifications still work in parallel for non-GUI usage.
When switching agents, the old state/chat streams would block until
data arrived (up to 500ms for statewait, indefinitely for chat).
Now requestStop() closes the fid from the calling thread, which
unblocks the worker's blocking read immediately. This makes agent
switching instant instead of waiting for the read timeout.
QThread::~QThread() aborts if the thread is still running. The previous
code called delete unconditionally after a 100ms wait timeout. Now we
follow the same pattern as stopWorker(): check if wait() succeeded,
and if not, abandon the thread safely via deleteLater.
Switch streaming reads (chat, state, events) from subprocess-based
ollie-9p to native lib9p via worker threads. This eliminates:
- Process spawn/teardown overhead
- Subprocess failure modes
- Signal handling complexity
Lib9pStreamer uses QThread workers with blocking reads. On stop,
workers are given 200ms to exit cleanly, then abandoned (they'll
exit when the read completes or connection closes).
Also: make KRunner/Kate/KIO plugins optional in CMakeLists.txt
to fix build when KF6Runner etc aren't installed. Added
QT_DEFAULT_MAJOR_VERSION=6 to fix Qt6 detection with CMake 4.x.
Two bugs:
1. GUI sends 'agent=<profile>' but server only recognized 'profile='
- Added 'agent' as alias for 'profile' in parseAgentNewRequest
2. Model dropdown showed cost columns appended to model names
- /models format: backend<tab>model[<tab>in<tab>out...]
- Parser took everything after first tab as model name
- Now stops at second tab to extract just the model name
Drop the OLLIE_KF5 CMake option and the entire Qt5/KF5 build branch;
delete KF5-only assets (99-ollie-kf5.sh, ollie-actions-kf5.desktop);
collapse all QT_VERSION_MAJOR and KTEXTEDITOR_VERSION_MAJOR conditionals
to the KF6 path in the KRunner, Kate, KIO, and GUI sources; update
Makefile, README, and docs. Verified: KF6 configure + full build of
ollie-gui, krunner_ollie, ollie_kate, kio_ollie.
Implement proper Plan 9/Acme mouse chording in the input area:
- B1 = select (TextArea default)
- B2 = execute selection as prompt
- B3 = plumb selection or context menu
- B1+B2 = cut (chord while selecting)
- B1+B3 = paste (chord while selecting)
Uses MouseArea overlay that detects when B1 is held while B2/B3
is pressed to trigger chord actions. Context menu items now show
the chord shortcuts (Cut B1+B2, Paste B1+B3).
Placeholder text shows the mouse action reference.
- Remove chatPane property from delegate (was shadowing id, causing binding loop)
- Remove contentArea MouseArea from inside Column (invalid anchor)
- Simplify hovered property to use only headerArea
- Edit button now copies to clipboard instead of trying to access chatPane