Based on Kate source analysis (apps/lib/diff/diffwidget.*):
- DiffWidget uses DiffEditor children (QPlainTextEdit subclass)
- In Raw/Unified mode, editors contain the actual diff text
- Use looksLikeDiff() to identify which editor has valid diff
Simplified from multi-strategy approach to single focused method.
Removed unused QTextEdit and functional includes.
Add minimumWidth: 320 and minimumHeight: 240 to allow the window to
resize properly when tiled by KDE's window manager. Without explicit
minimums, Qt calculates implicit minimums from content that may be
too large for narrow tile slots.
Make the six context-menu action methods (askAboutFile, explainSelection,
submitSelectionPrompt, sendVerbatim, reviewDiff, startSession) public
Q_INVOKABLE so sibling plugins can trigger them by name via
QMetaObject::invokeMethod. The Deft radial menu uses this to offer an 'Ollie'
submenu when this plugin is enabled. No behaviour change for existing callers.
Right-click on files/directories in Kate's project panel now shows
Ollie actions:
For directories:
- Ask about directory (explain purpose/structure)
- Start Session Here
For files:
- Ask about file (explain purpose/design)
- Review file (code review)
- Write tests
Constructs file paths by walking up the tree model and joining with
the project base directory.
Added Output sections with explicit bans on narration, hedging, and
verbose summaries to all agent-*.md files:
- author, conductor, copilot, foreman, observer, panelist, reviewer, theo
- Strengthened existing Output sections in explorer, librarian, navigator, taskmanager
All agents now have consistent brevity guidelines.
Added concrete examples of banned output patterns:
- Preambles (Great question!, I'd be happy to help!)
- Narration (Let me..., I'll now...)
- Hedging (It seems like, It appears that)
- Over-explaining and self-congratulation
- Summaries that restate what was just done
Added positive guidance: start with the answer, state task
completion in one sentence, end when information is delivered.
Models respond better to explicit prohibitions with examples than
to general instructions to 'be brief'.
Frontend changes to match the backend's multi-request support:
- bypassResolved signal now includes the request ID
- ChatPane tracks pendingBypasses as a map (id -> request)
- onBypassRequested adds to the map; onBypassResolved removes by ID
- currentBypass shows the first pending request for the active agent
- Switching agents updates the banner to show that agent's pending request
- Approve/Deny now remove only the specific resolved request
This allows each agent to have multiple pending bypass requests without
blocking other agents, and the banner correctly shows requests only for
the currently active agent.
Tests cover:
- Multiple concurrent pending requests from different agents
- BypassPendingByID lookup
- ResolveBypass removes only the resolved request
- ResolveBypass fails for non-existent ID
- Empty session has no pending requests
Previously a session tracked only one pending bypass request. If
agent A1 had a pending bypass, agent A2's bypass request would block
waiting to be read from toolsrv's channel, effectively blocking all
agents in the session.
Now bypassPending is a map keyed by request ID:
- SetBypassPending adds to the map instead of overwriting
- BypassPending returns all pending requests (slice)
- BypassPendingByID returns a specific request
- ResolveBypass removes from the map by ID
- 9P bypass file returns JSON array of all pending
The bypass loop reads requests continuously without waiting for
resolution, so multiple agents can have concurrent pending requests.
- SplitView allows dragging the divider between process list and output
- Show/Hide Output button toggles output panel visibility
- View Output and double-click auto-show the panel if hidden
- Output panel always visible with placeholder text
- View Output clears panel before refreshing
- Added Dismiss button to close window
- Process list has fixed height, output panel fills remaining space
Removed 'Explain this', 'Fix the bug', 'Write tests', 'Summarize',
'Refactor', 'Add comments' — these require context from Kate which
isn't available in the GUI. Replaced with 'Load skills and tools...'
which inserts 'Load all required skills and tools, then ' into the
prompt for user to complete.
B3 (right-click) on a word now plumbs it directly without visually
selecting it first. Double-click word selection includes underscores,
so snake_case selects the whole identifier.
MouseArea's onDoubleClicked doesn't fire when placed on a TextEdit with
selectByMouse:true — the TextEdit's internal mouse handling consumes the
events. TapHandler coexists with TextEdit's mouse handling and reliably
receives double-tap events.
Double-click on a bracket or quote delimiter now selects the content
between the matching pair. Quotes use parity to decide opener/closer
direction. Falls back to word selection when no delimiter is adjacent.
Works in chat blocks (mainTextEdit, textComponent) and prompt textarea.
The MouseArea (chordArea) is a sibling of the ScrollView containing
promptInput, so mouse.x/y are relative to the parent Item, not the
TextArea. Map coordinates via mapToItem before calling positionAt.
Extract selectBracketPair, selectWordAt, and helpers into TextSelection.js
and import it in both ChatBlockDelegate.qml and ChatPane.qml. Prompt
textarea now has the same double-click behavior as chat blocks:
delimiter adjacent to cursor -> select pair content, else -> word select.
Quotes use parity to decide direction and scan document-wide, so
multi-line content between the pair is selected in full.
Quote matching now scans the whole block text and computes opener/closer
parity document-wide, so content between a '' "" `` pair that spans
multiple lines is selected in full. The adjacent quote (left or right of
the cursor) sets the direction; the matching end quote is found by
scanning that way.
The overlay MouseArea swallows the B1 double-click, so returning
mouse.accepted=false did not make the TextEdit perform its native
word select — a non-delimiter double-click selected nothing. Now the
handler selects the word directly via selectWordAt when no bracket or
quote pair is under the cursor, so double-click is deterministic:
delimiter -> pair select, otherwise -> word select.
The Item wrapper added in 1cfa424 set height: mainTextEdit.height while
the TextEdit used anchors.fill: parent, so the TextEdit height depended
on the Item height and vice versa. The resulting binding loop collapsed
the block layout into visual garbage. Size the TextEdit from
width: parent.width and let its content height drive the Item.
selectBracketPair now also handles '' "" `` quote pairs. Since a
quote char opens and closes with the same glyph, a quote to the right
of the cursor scans forward for its match, and a quote to the left
scans backward.
Double-clicking next to a bracket (()[]{}) selects the text between
the matching pair, including nested pairs. Falls through to the
default word-select when no bracket is adjacent.
Also: B3-click on word now highlights it before plumbing.
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
Every background process emission now includes:
'Do NOT sleep, poll, or wait. Continue with other work —
output will be injected automatically when available.'
Add explicit instruction that models must not use sleep, loops,
or any blocking mechanism to wait for background process output.
The system injects updates automatically.
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
The cwd= parameter in agent/new payloads was not being parsed,
so scripts like ollie-session-here could not set agent cwd on
creation. Now parsed and passed to AgentParams.CwdOverride.
Match ollie-session-here behavior: update cwd for existing agents,
not just on creation. Ensures agent cwd reflects current project root
when invoked from a different context.
- 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