- Revert async connect-daemon thread (bt:make-thread unreliable — errors
in the thread cause silent failure, no connection, no error message)
- Restore blocking connect-daemon before with-terminal (original pattern
that was working)
- Revert /reconnect to synchronous call
- Remove stale async thread code and error messages
Cat subprocess (uiop:launch-program '("cat") :input :interactive) was
unreliable — the process would exit immediately in some environments,
breaking ALL keyboard input. Root cause: uiop's :input :interactive mode
opened /dev/tty which failed under specific process-group configurations.
Replace with direct read-char-no-hang on *standard-input*. The bash script
sets stty -icanon -echo -ixon before launching sbcl, so SBCL's stdin is
already in raw mode. No subprocess needed.
Also fixed pre-existing paren imbalance in tui-main (2 extra opens).
- Wrap cat with stdbuf -o0 so keystrokes aren't stuck in cat's 4096-byte
pipe buffer — text input was invisible until buffer filled
- Dialog filter: (characterp ch) rejects integer char codes from raw event
dispatch. Accept integerp in range 32-126 and convert via code-char
- Remove initial render (backend-clear + view calls) before main loop.
Dirty flags already trigger a full sync-wrapped redraw in the first
iteration, eliminating the pre-loop clear flash
Issue 1 — flickering during typing/updating:
- Wrap every frame render in DECICM sync (begin-sync/end-sync) so the
terminal defers rendering until the entire frame is written
- Replace backend-clear (ESC[2J full clear) with draw-rect background
fill — eliminates visible blank frame between redraws
- These two changes together eliminate all visible tearing/flicker
Issue 2 — bottom-anchored minibuffer (Emacs-style):
- Replace centered overlay dialog with bottom-anchored minibuffer
that expands upward from the input line
- Unified command menu: Ctrl+P and / both open the same menu with
all 35+ commands (slash + daemon), dispatch by value type
- Filter prompt at h-3 (same position as normal input),
options listed above, grows up to 15 lines
- No full-screen dim backdrop — just clear the minibuffer area
Issue 3 — color schemes:
- Add 5 new presets: catppuccin, tokyonight, dracula, gemini, mono
- Total: 13 presets (up from 8)
- Update /theme completion list and help text
Also fixed: pre-existing unbalanced paren in tui-main (missing close)
passepartout script:
- Add (uiop:quit 0) after tui-main so SBCL exits on Ctrl+Q
- Remove exec to allow stty restore after sbcl subprocess
- Restore icanon echo ixon after TUI exits (terminal stuck raw)
channel-tui-view.org:
- Remove unused fb/h vars from test-sidebar-not-shown-narrow
- Add (declare (ignore w)) to render-styled
- Qualify theme-color as passepartout.channel-tui:theme-color
(render-styled is in :passepartout package)
- Remove dead :url clause from pick in parse-markdown-spans
(URLs handled by dedicated branch, not via pick)
- Update literate prose for all changes
Replaced (let* ((cat-proc ...) (tty-in ...)) ...) with global
special variables *cat-proc* and *tty-in* with defvar declarations.
The let* caused 'unbound variable' errors on Ctrl+Q because the
lexical scope didn't extend to terminate-process. Global vars have
indefinite scope and work reliably regardless of paren nesting.
- Added -ixon to stty so Ctrl+Q (XON byte) isn't swallowed by the
terminal driver and reaches the TUI as :CTRL-Q
- view-input now truncates the prompt (> prefix + visible text) to
chat-w - 2 characters, and the hint to chat-w characters, so
neither extends into the sidebar area
Added chat-w = w - sidebar_width calculation in view-status and
view-input, matching view-chat's existing approach. Also added
chat-w for the separator line drawing in tui-main. This prevents
the prompt, separator, hint, and status bar from extending into
the sidebar area when it's visible.
uiop:run-program inside SBCL can't access the terminal, so stty
calls from within Lisp fail silently. By running 'stty -icanon -echo'
in the bash script before exec sbcl, the terminal is already in
character-at-a-time mode when the TUI starts, and Ctrl+P/B keys
arrive as individual bytes through the cat pipe.
- Sidebar threshold lowered from 120 to 60 so it works on 83-col
terminals
- Agent response text is now word-wrapped through cl-tty.box:word-wrap
after markdown rendering, preventing text from bleeding past the
terminal edge
- Added chat-w = w - sidebar-width in view-chat for all width
calculations (word-wrap, padding, borders) so text doesn't
bleed into the sidebar area
- Changed Ctrl+B dirty flags from (list t t nil) to (list t t t)
so input view also redraws, fixing the toggle-not-turning-off issue
The key event dispatch was lost during git restores, causing all
:key events (Ctrl+P, Ctrl+B, Enter, etc.) to fall through to
on-key which only handles :enter, :escape, and character insertion.
Added back the case ch with :CTRL-Q/:CTRL-P/:CTRL-B/:CTRL-L
branches and full dialog key routing.
Without -icanon, the terminal driver buffers all input until Enter,
so Ctrl+P/B never arrive as individual key events. With -icanon,
cat reads bytes immediately and pipes them to SBCL. SBCL reads from
the pipe, not fd 0, so there's no fd 0 read block issue.
backend-size can return nil for height (especially when the /dev/tty
ioctl fallback hasn't been compiled in yet). view functions had nil
guards but the direct (- h 4) calls in tui-main's initial render
crashed before reaching them.
cat-proc and tty-in were defined by let* but the let* closed at
sleep's third ), putting them out of scope for terminate-process
and read-char. Restructured closing parens so the let* body wraps
the full loop + cleanup.
view-input drew prompt first (row h-3), then hint (row h-2),
leaving the cursor at end of the hint line after 'complete'.
Typed characters appeared there. Swapped order: hint first,
prompt last, so cursor ends at the > prompt.
The render order was: view-chat → view-input → draw-separator.
After the separator draw, the cursor ended up at row h-4 (the
separator line). Typed characters echoed by the terminal appeared
on the separator line, above the > prompt. Swapped so the input
line is drawn last: view-chat → draw-separator → view-input.
- Changed all 50 org file :tangle targets from ../lisp/ to
~/.local/share/passepartout/lisp/ (XDG data dir)
- Removed 49 generated .lisp files from project lisp/ directory
- Removed tests/system-integration-tests.lisp (generated)
- Removed lisp/*.fasl (compiled, stale)
- Updated core-manifest.org to tangle .asd to XDG root
- Remapped quicklisp symlink: local-projects/passepartout → XDG
TUI fixes in channel-tui-main.org:
- Removed with-raw-terminal (stty raw breaks fd 0 reads in this SBCL)
- Use cat subprocess + pipe for keyboard input (via :input :interactive)
- Blocking read-char on pipe with with-timeout 0.1s for daemon processing
- Key events queued via drain-queue alongside daemon messages
- Full dialog key routing (Escape, Up/Down, Enter, filters, Backspace)
- SIGWINCH resize handling
- Post-handshake backend-size re-query
- Daemon version in status bar (was v0.5.0 hardcoded)
- Handshake version stored in state, no add-msg
- :daemon-version and :size-queried in state plist
- view-status uses draw-rect for background
- Test section gated with #+passepartout-tests
read-char-no-hang on fd 0 streams never returns data because
sb-unix:unix-simple-poll on fd 0 returns NIL in this SBCL
environment. Switched to (listen tty) + (read-char tty) which
blocks until a key is pressed — correct interactive TUI behavior.
Also switched from (open "/dev/tty") to
(sb-sys:make-fd-stream 0 :input t :buffering :none) to directly
read from stdin.
Main loop now checks cl-tty.input::*terminal-resized-p* on every
iteration. When set (by SIGWINCH handler), re-queries backend-size
and marks all regions dirty for re-render.
- Replaced cl-tty read-event with direct read-char-no-hang from
/dev/tty for reliable input (avoids unix-simple-poll fd 0 issue)
- Added (let ((tty ...)) wrapper to open /dev/tty once at startup
- Fixed (code-char raw-ch) bug: raw-ch is already a CHARACTER
- Fixed one extra close paren that closed (let ((ch ...)) early
- Gated fiveam test section behind #+passepartout-tests reader
conditional to prevent crash on TUI startup when fiveam not loaded
- Added initial render (backend-clear + view-all) before main loop
so startup messages appear immediately
- Restored read-event with :timeout 0 from git HEAD
- Removed dispatch-key-event from main loop (simplified to direct on-key)
- Removed :enter from :local keymap (handled directly in on-key)
- Retained direct-to-backend rendering (no framebuffer)
- Retained msgs count in status bar for debugging
- 237/237 tests pass
draw-rect has no method on raw arrays (only on framebuffer-backend,
simple-backend, modern-backend). Three calls in view-status, view-chat,
and view-sidebar passed the framebuffer array to draw-rect, causing
'no applicable method' crash on startup.
Replaced with (draw-text ... (make-string w #\Space) nil bg) which
fills the same area with background spaces.
Complete rewrite of the TUI with warm amber/gold color palette and
clean three-zone layout (chat top, input bottom, status very bottom).
1. Layout restructure: input at y=h-3, hint at y=h-2, status at y=h-1
2. Warm palette: 20-key amber/gold theme, 8 warm presets
3. Readline keybindings: Ctrl+A/E/U/W/K/Y/L/D/F/G in :global keymap
4. Chat messages: user boxes (┌─└─), agent headers, collapsible tools
5. Command palette: Ctrl+P top-centered overlay, warm colors
6. Sidebar: Ctrl+B toggle, right panel with focus/rules/context/MCP
7. Keybindings: :ctrl+x, :?, mouse wheel support
8. Search: existing /search with match highlighting
9. Help overlay: ? shows keybinding and command reference
- KEY_ENTER (343) and KEY_BACKSPACE (263) were not handled in on-key
causing Enter/Backspace to silently fail in tests using ncurses keycodes
- Escape (27) was not matched for streaming interrupt in on-key
- theme-color test expected keyword :white but function returns hex string
Main loop was calling (backend-clear curr-fb) where curr-fb is a
framebuffer array. Changed to (backend-clear be) using the cl-tty
backend, which writes the terminal clear escape sequence.
The revert removed the (keyword ...) clause from the typecase in
on-key's printable branch. Keyword symbols from the main loop
(:a, :h, etc.) fell through to (t nil), making all character input
silently ignored. Typing and sending now works correctly.
- Add missing word-wrap function (was declared in contract but never defined)
- TUI now renders correctly: draw-text on framebuffer arrays works
- Daemon connection verified
- All three view functions (status, chat, input) call draw-text correctly
- cl-tty stty calls now use :ignore-error-status t (works in PTY/piped env)
- backend-size wraps in ignore-errors with 80x24 fallback in resize handler
- Both fixes enable TUI to run in environments without full terminal capabilities
- Remove dead croatoan-to-tty-event keymap dispatch clause from on-key
- Replace all (st :key) with (getf *state* :key) and all
(setf (st :key) val) with (setf (getf *state* :key) val)
to avoid SBCL cross-file SETF expander issues (239 replacements)
- Fix redraw arity: called with 4 args but defined with 3
- TUI now loads, initializes, and connects to daemon successfully
- Replace numeric key code dispatch with cl-tty keyword events
- Replace Croatoan code-key/key-name normalization with direct keyword dispatch
- Update main loop to construct Ctrl-key keywords from cl-tty key-event modifiers
- Remove croatoan-to-tty-event compatibility shim and its test
- Remove duplicate Esc handling from main loop (now handled by on-key)
- Update all documentation contracts, prose, docstrings to remove Croatoan refs
- Remove :croatoan from package dependencies
- All event handling now goes through cl-tty keymaps or keyword dispatch
v0.8.0: Information Radiator now built on cl-tty v1.1.0. Minibuffer
uses cl-tty Dialog stack. New TODO items: conversation view (ScrollBox
+ Markdown), command palette (Select), sidebar (slot system), status bar
(Box + Theme), keybindings (keymap).
v0.9.1: Emacs is now an optional secondary client, not the primary
bridge. cl-tty is the primary TUI.
Bug fixes:
- Fix box() calls: set color-pair before box, pass ACS default chtype integers
- Fix markdown functions: move to passepartout.channel-tui package where
Croatoan is imported; use add-attributes/remove-attributes instead of
:bold/:underline kwargs to add-string; call theme-color in gate-trace-lines
to convert theme keys to Croatoan colors
- Fix sandbox: remove dex:get/dex:post from restricted symbols
(blocked neuro-provider from loading)
- Export *log-lock* from passepartout (was unbound in jailed skill packages)
- Fix configure: always deploy to XDG, skip cp when source==dest
- Fix bash crash handler format string (~~ escaping)
- Revert test reorder in 28 files (caused package leakage in skill loader)
Design cleanup:
- Extract tui-run-screen from tui-main for clean separation
- Remove inject-stimulus alias
- Merge *backend-registry* into *probabilistic-backends*
- Fix read-framed-message whitespace DoS (4096-iteration max)
- Add *read-eval* nil to dispatcher-approvals-process read-from-string