- agor_resize.c: C library with GTK signal handlers for resize
- native-resize.ts: Bun FFI wrapper for libagor-resize.so
- resize-test.html: minimal stub for isolating resize behavior
- index.ts: native resize disabled pending stability testing
- RESIZE_TEST env var for loading stub page via Vite
New: agor-pty/native/agor_resize.c — C shared library that:
- Connects button-press-event on GtkWindow + WebView children in C
- Stores mouseButton, xroot, yroot, dragTime from real GTK events
- Exports agor_resize_start(edge) for Bun FFI
Build: gcc -shared -fPIC -o libagor-resize.so agor_resize.c $(pkg-config --cflags --libs gtk+-3.0)
New: ui-electrobun/src/bun/native-resize.ts — Bun FFI wrapper
App.svelte: simplified to just edge detection + RPC call
All previous approaches failed because they initiated resize from JS
(too late, wrong timestamp, WebKit steals grab). The correct approach
(proven by Tauri/tao) is to connect button-press-event DIRECTLY on the
GtkWindow at the GTK level, BEFORE WebKitGTK processes events.
New: gtk-resize.ts
- JSCallback for button-press-event + motion-notify-event
- Hit-test in 8px border zone (same as tao's 5*scale_factor)
- begin_resize_drag with REAL event timestamp (not GDK_CURRENT_TIME)
- Returns TRUE to STOP propagation (WebKit never sees the press)
- Cursor updates on motion-notify in border zone
Removed: all JS resize handles (divs, mousemove, mouseup, RPC calls)
begin_resize_drag + XUngrabPointer still fails because GTK's layout
cycle re-asserts WebView preferred size, fighting the WM resize.
New approach: JS mousemove → XMoveResizeWindow via libX11.so.6 FFI.
Completely bypasses GTK size negotiation. GTK only receives
ConfigureNotify after the X server has already resized the window.
Added: x11SetFrame() using gdk_x11_display_get_xdisplay +
gdk_x11_window_get_xid + XMoveResizeWindow.
Codex review #2 found: set_size_request only controls minimum, not
natural/preferred size. WebView still reports content size as natural,
causing rubber-band effect during shrink.
Fix: reparent WebKitWebView into GtkScrolledWindow via FFI with
propagate-natural-width/height=FALSE and min-content=1x1. This
decouples WebView content size from window size negotiation.
Also reverted to native begin_resize_drag (WM handles everything).
Electrobun's setSize respects WebView min-size constraint. Bypass it
with direct gtk_window_resize() + gtk_window_move() FFI calls.
clearMinSizeTree() runs on every resize frame to suppress WebView
re-propagation. gtkSetFrame() exported as new RPC endpoint.
GTK begin_resize_drag loses grip when cursor moves inward past the 6px
handle zone. Replaced with document-level mousemove/mouseup listeners
that compute delta from initial frame and call setPosition+setSize.
- clearMinSize RPC clears WebView min-size before resize starts
- Cursor locks to resize direction during drag (body.style.cursor)
- user-select disabled during drag to prevent text selection
- Frame captured async before resize starts (no race condition)
Root cause: WebKitWebView requests min_size = content_size (5120x1387 on
ultrawide), which GTK propagates to WM_NORMAL_HINTS, blocking all resize.
Fix: recursively walk the GTK widget tree (GtkWindow → GtkBin → WebView)
and call gtk_widget_set_size_request(-1, -1) on every widget. Then set
gtk_window_set_geometry_hints with min=400x300.
Result: WM_NORMAL_HINTS now shows min=10x10, window is fully resizable.
Root cause: WebKitGTK reports stale modifier state (0x14=Ctrl+Alt) after
SIGTERM of previous instance. Electrobun interprets this as Cmd+click and
opens a new window, which closes the main window.
Finding: when modifier state is clean (0x10, isCtrlHeld=0), the window
opens correctly. The event emitter API isn't publicly exported from
electrobun/bun — needs upstream fix or different approach.
- SidecarManager: spawns claude/codex/ollama runners via Bun.spawn(),
NDJSON stdio protocol, Claude CLI auto-detection, env stripping,
AbortController stop, Deno/Node runtime detection
- MessageAdapter: parses Claude stream-json, Codex ThreadEvent, Ollama
chunks into common AgentMessage format
- agent-store.svelte.ts: per-project reactive session state, RPC event
listeners for agent.message/status/cost
- AgentPane: wired to real sessions (start/stop/prompt), stop button,
thinking/system message rendering
- ProjectCard: status dot from real agent status, cost/tokens from store
- 5 new RPC types (agent.start/stop/prompt/list + events)
All settings wired to SQLite persistence:
- AgentSettings: shell, CWD, permissions, providers (JSON blob)
- SecuritySettings: branch policies (JSON array)
- ProjectSettings: per-project via setProject RPC
- OrchestrationSettings: wake, anchors, notifications
- AdvancedSettings: logging, OTLP, plugins, import/export JSON
Theme Editor:
- 26 color pickers (14 Accents + 12 Neutrals)
- Live CSS var preview as you pick colors
- Save custom theme to SQLite, cancel reverts
- Import/export theme as JSON
- Custom themes in dropdown with delete button
Extensions Marketplace:
- 8-plugin demo catalog (Browse/Installed tabs)
- Search/filter by name or tag
- Install/uninstall with SQLite persistence
- Plugin cards with emoji icons, tags, version
Terminal font hot-swap:
- fontStore.onTermFontChange() → xterm.js options update + fitAddon.fit()
- Resize notification to PTY daemon after font change
All 7 settings categories functional. Every control persists and takes effect.
- Bun process connects to agor-ptyd via PtyClient (5 retries, exponential backoff)
- RPC bridge: 5 request handlers (create/write/resize/unsubscribe/close)
- Daemon output forwarded to WebView as pty.output messages (base64 passthrough)
- Terminal.svelte: real PTY sessions via RPC instead of echo mode
- Shared RPC schema at src/shared/pty-rpc-schema.ts
- Fixed pty-client.ts protocol: base64 string for data (was number array)
- TerminalTabs passes sessionId to Terminal component