Commit Graph

444 Commits

Author SHA1 Message Date
Levi Neely 9618c79232 gui: native 9P plumb client with edit receiver and mouse chording
Replace QProcess plumb binary shell-out with proper 9P2000 plumb client:
- ninep.h/cpp: minimal 9P2000 protocol client for plan9port plumber
- plumbmsg.h/cpp: plumb message pack/unpack wire codec
- plumber.h/cpp: full plumb client with:
  - socketPath() resolving $NAMESPACE/plumb or display fallback
  - send()/sendTo() write packed messages to send port via 9P
  - PlumbReader thread blocks on edit port, emits edit(file,addr,wdir)
  - startReader() starts the receive loop
  - available() checks plumb socket existence

Add Acme-style mouse chording to ChatBlockDelegate.qml:
- B1+B2 = cut (snarf)
- B1+B3 = paste
- Context menu now includes Cut/Paste with chord hints

Legacy plumb()/plumbTo() methods preserved as aliases to send()/sendTo().
2026-10-08 15:34:29 +02:00
Levi Neely 4774cb9fe9 gui: convert ProcManager to separate Window, sync to active session
- 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
2026-10-08 14:57:25 +02:00
Levi Neely 491f5ff2ae gui: add 'Open Workdir' context menu for sessions and agents
- Add openDirectory() method using QDesktopServices::openUrl
- Session context menu: opens session cwd
- Agent context menu: opens agent's effective cwd
2026-10-08 13:38:29 +02:00
Levi Neely af21dfa770 kde: remove KF5 .protocol file, use KF6 JSON metadata
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/
2026-10-08 12:24:48 +02:00
Levi Neely 01360b961d gui: add process manager dialog
- 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
2026-10-08 12:14:02 +02:00
Levi Neely 1548af81af kate: find GitWidget's button bar and insert Ollie button there
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.
2026-10-08 10:40:04 +02:00
Levi Neely b745170898 kate: add Ollie button to git tool view instead of context menu
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.
2026-10-08 10:36:27 +02:00
Levi Neely c3782dd3b7 kate: fix git widget integration via ChildAdded event filter
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.
2026-10-08 10:34:06 +02:00
Levi Neely a546b8721a kate: integrate with project plugin git widget and diff viewer
- 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
2026-10-08 10:29:12 +02:00
Levi Neely ab4f0ef785 Revert "gui: remove cut/copy/paste from prompt input"
This reverts commit eb09a95a64.
2026-10-07 17:35:10 +02:00
Levi Neely eb09a95a64 gui: remove cut/copy/paste from prompt input
- 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
2026-10-07 17:30:28 +02:00
Levi Neely f7a52088db per-agent cwd override with session-level inheritance
- 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
2026-10-07 15:14:04 +02:00
Levi Neely d5efe575ce consistent agent naming: parent:prefix convention
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
2026-10-07 14:39:47 +02:00
Levi Neely 1c02b50add proc events, bypass shortcuts, Kate session fix
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
2026-10-07 14:22:44 +02:00
Levi Neely 91f295dc2d gui: add activeSessionPaused property for reactive paused state
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
2026-10-06 15:23:44 +02:00
Levi Neely 4be78447fa gui: restart agent streams on session resume
When resuming the active session, restart chat stream so user
can continue working without switching agents.
2026-10-06 15:20:50 +02:00
Levi Neely 7cbaaed014 gui: gray state indicator when session is paused
Session paused state overrides agent state for the indicator.
Reacts to sessionsChanged signal for pause/resume updates.
2026-10-06 15:16:57 +02:00
Levi Neely af772e5e8b gui: use relative geometry for state indicator
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
2026-10-06 15:13:01 +02:00
Levi Neely 8c207a0f3a gui: add right margin to state indicator dot 2026-10-06 15:12:00 +02:00
Levi Neely 64559de661 gui: add agent state indicator dot to session tree
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.
2026-10-06 15:10:12 +02:00
Levi Neely b25e5e2fc6 bypass: emit resolved event for cross-client coordination
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.
2026-10-06 14:54:55 +02:00
Levi Neely 150ca5dfdd gui: add pending bypass indicator to agent tree
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.
2026-10-06 14:47:55 +02:00
Levi Neely f9e6785add gui: hide bypass banner when switching away from the requesting agent 2026-10-06 14:41:09 +02:00
Levi Neely a269a6f790 gui: fix bypass banner - use activeAgentId not agentId in QML 2026-10-06 14:37:48 +02:00
Levi Neely 6dc9ffe3b1 gui: show bypass banner per-agent, not globally
- 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
2026-10-06 14:32:30 +02:00
Levi Neely 59d07d3b4a fix bypass event payload truncation at newlines
The shell command in bypass requests contains embedded newlines.
Escape them as \n in the event payload, unescape in GUI.
2026-10-06 14:28:10 +02:00
Levi Neely ceec28c2b9 gui: show bypass banner for any session, not just active
The GUI is a global view - show bypass requests immediately
regardless of which session is currently selected.
2026-10-06 14:07:05 +02:00
Levi Neely 5882192ae9 gui: fix bypass banner not appearing until session switch
QML's property var change detection doesn't reliably trigger
binding updates when comparing to null. Added explicit bool
hasPendingBypass property that properly triggers visibility.
2026-10-06 13:56:28 +02:00
Levi Neely 86fbc90b43 server: remove statewait file, use event stream instead
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.
2026-10-06 12:44:02 +02:00
Levi Neely 021436bfbf gui: remove per-agent statewait stream, use server event bus
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
2026-10-06 12:11:14 +02:00
Levi Neely f86c8d3cdc docs: update all references from eventwait to event 2026-10-06 12:08:35 +02:00
Levi Neely 25d7fbfc5b server: rename eventwait to event 2026-10-06 12:02:37 +02:00
Levi Neely adb08fc51d server: fix eventwait to use Stream instead of BlockOnce
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.
2026-10-06 12:01:26 +02:00
Levi Neely 70c00541df gui: poll bypass file on session switch
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.
2026-10-06 11:51:27 +02:00
Levi Neely f2f1f80e4e gui: integrate bypass requests into chat UI
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.
2026-10-06 11:44:15 +02:00
Levi Neely 79738a4a39 gui: reduce stopWorker wait from 200ms to 10ms
The fid close should immediately unblock reads. Don't wait long.
2026-10-06 11:38:28 +02:00
Levi Neely 65014395b7 gui: fix slow agent switching by closing fid on stop
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.
2026-10-06 11:36:30 +02:00
Levi Neely 3655b16b4b gui: fix QThread crash in Lib9pStreamer::onWorkerFinished
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.
2026-10-06 11:29:26 +02:00
Levi Neely 3838078394 gui: fix compact button to send /compact command 2026-10-06 11:24:05 +02:00
Levi Neely 1dcc9638df gui: replace NativeStreamer with Lib9pStreamer
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.
2026-10-06 11:16:53 +02:00
Levi Neely cd76864f19 fix agent profile selection from GUI
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
2026-10-06 10:42:35 +02:00
Ollie Agent 72239fe3d5 kde: remove KF5/Qt5 support, build KF6/Qt6 only
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.
2026-09-29 16:44:12 +02:00
Levi Neely 48bd852594 kde/gui: add Yes/No to templates menu 2026-09-21 14:20:07 +02:00
Levi Neely b25b99be4d kde/gui: add Acme-style mouse chording to prompt input
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.
2026-09-04 14:23:58 +02:00
Levi Neely eb12627ea0 kde/gui: fix binding loop and Column anchor errors
- 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
2026-09-04 14:20:40 +02:00
Levi Neely 75a2da080e kde/gui: Acme-style mouse actions and one-handed workflow
Add Plan 9/Acme-inspired mouse interaction:
- B2 (middle-click): Execute selected text as prompt
- B3 (right-click): Plumb selection via plan9port, fallback to context menu

Plumber integration (plumber.h/cpp):
- Wraps plan9port's plumb command for context-aware actions
- Auto-detects plumb binary in common plan9port locations
- Graceful fallback when plumber not available

Block tag line (ChatBlockDelegate):
- Hover-visible action buttons: Copy, Retry, Continue, Edit
- Per-block-type actions (Retry for assistant/error, Edit for user)

Action toolbar (ChatPane):
- Stop, Compact, Copy Last, Templates dropdown
- Mouse-first workflow without keyboard shortcuts

Input area improvements:
- Larger touch targets (48px send button, 32px toggle)
- Clear and Paste buttons
- B2/B3 mouse actions in prompt input
- Placeholder text explains mouse actions

Context menus now include:
- Execute Selection (B2)
- Plumb Selection (B3)
- Standard Cut/Copy/Paste/Select All
2026-09-04 13:47:51 +02:00
Levi Neely 5f68871c65 kde/gui: render markdown tables in chat view
Add table rendering support to ChatBlockModel:
- isTableLine(): detect pipe-delimited table rows
- renderTable(): convert table lines to HTML <table>
- renderProse(): split prose into text/table segments
- incrementalAppend: handle table state transitions during streaming

Tables render with header row detection (before |---|---| separator)
and proper incremental updates as content streams in.
2026-09-04 13:28:06 +02:00
Levi Neely 307687542c gui: add submit button to prompt input
Add a ▶ button next to the text area for mouse-based submission.
Extract shared doSubmit() on the input RowLayout. Button uses
focusPolicy: Qt.NoFocus so it doesn't steal focus from the TextArea.
2026-08-28 13:40:14 +02:00
Levi Neely 9829498d57 gui: fix text selection in prompt box
Replace MouseArea overlay with TapHandler inside TextArea.
The MouseArea sat on top and intercepted left-button press events,
blocking click-and-drag text selection. TapHandler cooperates with
the TextArea's built-in selection handling.
2026-08-28 13:25:54 +02:00
Ollie Agent bb6df3a073 Hide context blocks in KDE chat 2026-08-20 17:34:53 +02:00