projmux 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@
37
37
  actions, and `focus` dispatch diagnostics for session fallback, unresolved
38
38
  targets, window fallback, pane fallback, explicit id failures, and
39
39
  notify-only fallback.
40
- - Picker focused unit coverage includes backend-neutral picker item/action mapping, fzf adapter output, native title-focused filtering, numeric selection, and shared close actions.
40
+ - Picker focused unit coverage includes backend-neutral picker item/action mapping, fzf adapter output, native title-focused filtering, numeric selection, shared close actions, saved picker backend config, Settings Labs backend switching, environment override precedence, compact multi-line metadata gutters aligned to the project-name column, proportional native scrollbar thumb rendering, fixed split-preview and sidebar list viewports with scrollbar tracks, preview tab/control normalization before width clipping, optional native frame titlebars, titled native Alt-1 sidebar chrome, statusbar-preserving sidebar popup height, native-only compact project sidebar popup sizing, and notify sidebar popup sizing that preserves the fzf minimum/ratio baseline.
41
41
  - `make test-integration`: Docker-backed Linux integration smoke with real `tmux`, `fzf`, `git`, and `stty`; covers `doctor`, tmux config print/install/apply, and notify queue CRUD against isolated HOME/XDG paths.
42
42
  - `make test-install-smoke`: Docker-backed source install smoke; covers `make install`, atomic binary replacement, `tmux apply` against a live `projmux` socket, and post-install notify queue initialization.
43
43
  - `make test-e2e`: Docker-backed real-tmux workflow smoke for session/pane setup, app config sourcing, reply-state notify reconciliation, focus notify fallback, and status notify rendering with contextual project/state/agent badges. Host-only terminal, WSL, macOS, and GUI notification behavior remains outside Docker; see [docs/testing.md](testing.md).
@@ -44,8 +44,8 @@ Responsibilities:
44
44
  Picker data is modeled independently from fzf rows. The app builds
45
45
  backend-neutral `picker.Item` values (`Title`, `Value`, `SearchText`,
46
46
  `MetaLines`, `Badges`, `PreviewTarget`) and then adapts them to the selected
47
- backend. `fzf` remains the default, stable backend; the native backend is
48
- opt-in through `PROJMUX_PICKER_BACKEND=native` while it reaches full parity.
47
+ backend. Native is the default backend, while `PROJMUX_PICKER_BACKEND=fzf`
48
+ keeps the external fzf backend available as an explicit fallback.
49
49
 
50
50
  Responsibilities:
51
51
  - rows for popup and sidebar views
package/docs/cli.md CHANGED
@@ -54,17 +54,15 @@ projmux switch toggle-tag | toggle-pin | kill | settings | preview
54
54
  projmux switch cycle-pane | cycle-window | sidebar-focus
55
55
  ```
56
56
 
57
- Project picker. With no positional argument, opens the fzf-driven popup or
58
- sidebar (depending on entry helper). With a path, jumps directly. The
57
+ Project picker. With no positional argument, opens the configured picker popup
58
+ or sidebar (depending on entry helper). With a path, jumps directly. The
59
59
  sub-verbs are entry hooks invoked by tmux keybindings (e.g.
60
60
  `sidebar-focus` is wired to the sidebar's focus binding so navigation keeps
61
61
  the active session in sync).
62
62
 
63
- `PROJMUX_PICKER_BACKEND=native` opts the switcher into the experimental native
64
- picker backend. fzf remains the default and the only backend with full preview
65
- pane, sidebar focus, and key-action parity. Native currently provides
66
- multiline card rendering, title-focused search, numeric selection, and the
67
- shared close-action contract.
63
+ Settings > Labs > Picker Engine can switch between the default native picker
64
+ backend and the external fzf fallback. `PROJMUX_PICKER_BACKEND=fzf` is supported
65
+ as an environment override and takes priority over the saved Labs setting.
68
66
 
69
67
  ## setup
70
68
 
@@ -179,11 +177,11 @@ projmux notify reconcile [--json]
179
177
  reply badges that do not queue because no AI agent is attached, live AI
180
178
  reply panes missing a queue entry, matched AI reply entries, and stale
181
179
  queue entries whose live pane no longer matches. `--ui=sidebar` opens the
182
- compact interactive notify list where Enter focuses and acks a target, `a`
183
- acks the selected row, and `Ctrl-A` clears all; opening or navigating the
180
+ compact interactive notify list where Enter focuses and acks a target, `x`
181
+ acks the selected row, and `Ctrl-X` clears all; opening or navigating the
184
182
  sidebar does not ack. The sidebar uses two-line cards with notification text
185
- first and compact age/project/window/pane metadata below, while keeping ids,
186
- source, severity, and target details searchable.
183
+ first and compact age/project/window/pane metadata below. Hidden queue ids
184
+ remain action values, but the sidebar has no search input.
187
185
  - `ack <id>` removes one entry; `--all` flushes the queue.
188
186
  - `reconcile` — walks `tmux list-panes -a` and back-fills entries for
189
187
  panes whose attention state is `reply` AND whose AI agent option is
@@ -222,9 +220,11 @@ projmux status usage [--max-width N] [--force|-f]
222
220
  projmux status notify [--max-width N]
223
221
  ```
224
222
 
225
- - `git` — `#[bold,fg=colour16,bg=colour45] <branch> #[default]` for the
226
- pane's `pane_current_path` (or the supplied path). Empty when not in a
227
- repo.
223
+ - `git` — `#[bold,fg=colour16,bg=colour45] <branch> <state> #[default]` for
224
+ the pane's `pane_current_path` (or the supplied path). Empty when not in a
225
+ repo. `<state>` is omitted when clean, otherwise it may include `*` for
226
+ local changes, `+N` staged entries, and `↑N`/`↓N` ahead/behind counts, with
227
+ compact per-token colors in tmux output.
228
228
  - `kube` — `⎈ <context>/<namespace>` segment. Reads
229
229
  `~/.cache/tmux/kube-segment-<session>.txt` first (TTL governed by
230
230
  `TMUX_KUBE_CACHE_TTL`, default `5s`). Picks up a per-session
@@ -301,7 +301,7 @@ entry into the notify queue.
301
301
  ## tmux
302
302
 
303
303
  ```
304
- projmux tmux popup-toggle <mode>
304
+ projmux tmux popup-toggle [--client <key>] <mode>
305
305
  projmux tmux popup-switch
306
306
  projmux tmux popup-sessions
307
307
  projmux tmux popup-preview <session>
@@ -317,7 +317,8 @@ projmux tmux apply
317
317
  Helpers tmux's keybindings and the install pipeline call into. Modes
318
318
  accepted by `popup-toggle` mirror the historical sessionizer surface:
319
319
  `session-popup`, `sessionizer`, `sessionizer-sidebar`,
320
- `ai-split-picker-right`, `ai-split-picker-down`, `ai-split-settings`.
320
+ `notify-sidebar`, `ai-split-picker-right`, `ai-split-picker-down`,
321
+ `ai-split-settings`.
321
322
  `apply` reloads the live `-L projmux` server's config without restarting
322
323
  it; `make install` and `projmux upgrade` invoke it after replacing the
323
324
  binary.
@@ -402,18 +403,20 @@ flags with the top-level `switch` UX:
402
403
  - `attach auto [--keep=N] [--fallback=home|ephemeral]` — auto-attach to
403
404
  the most recent session, with bounded retention and a fallback policy.
404
405
  - `settings` — interactive configuration UI for the project picker, AI
405
- splits, Status Bar cwd/git decoration, Project Root management, the
406
- switcher's saved workdirs list, and About/Update status. In Project Picker,
407
- `Project Root` manages the saved
406
+ splits, Icons & Decorations mode, Project Root management, the
407
+ switcher's saved workdirs list, Labs, and About/Update status. In Project
408
+ Picker, `Project Root` manages the saved
408
409
  primary root (`~/.config/projmux/projdir`) and displays whether the effective
409
410
  value comes from `PROJMUX_PROJDIR`, tmux `@projmux_projdir`, saved config, or
410
411
  no configured source. When no source is configured, the direct-set prompt
411
412
  starts with `$HOME` as an editable fallback, but `$HOME` is not used as the
412
413
  effective root unless saved. `Workdirs` remains separate: those entries are
413
- additional search roots, not the primary root. Status Bar stores
414
+ additional search roots, not the primary root. Icons & Decorations stores
414
415
  `~/.config/projmux/statusbar-decoration` as `off` (default), `symbol`, or
415
- `emoji` and updates the live tmux option when available. The About section
416
- reads the cached update status without network access;
416
+ `emoji` and updates the live tmux option when available. Labs stores
417
+ `~/.config/projmux/picker-backend` as `native` (default) or `fzf` and updates
418
+ the live tmux `PROJMUX_PICKER_BACKEND` environment when available. The About
419
+ section reads the cached update status without network access;
417
420
  selecting Check Updates runs `projmux update check`, and Update Now runs
418
421
  `projmux update apply`. The same About section also lists the keybinding
419
422
  diagnostic path: zero-config first, `setup` for swallowed keys, `init` for
@@ -51,7 +51,7 @@ The file is read only when no env root list is set.
51
51
  | `PROJMUX_USAGE_DEBUG` | When non-empty, prints adapter errors from `projmux status usage` to stderr. |
52
52
  | `PROJMUX_USAGE_LIMITS_PATH` | Deprecated. Read but ignored; limits now come from upstream APIs and local Codex rollout state. |
53
53
  | `PROJMUX_FOCUS_DEBUG` | When non-empty, `projmux focus` prints one telemetry line to stderr. |
54
- | `PROJMUX_PICKER_BACKEND` | Set to `native` to opt into the experimental native picker backend. `fzf` remains the default and stable backend. |
54
+ | `PROJMUX_PICKER_BACKEND` | Override the picker backend. Native is the default; set `fzf` to use the external fzf backend. |
55
55
  | `PROJMUX_INSTALLER` | Installer source hint used by update flows. npm installs set this automatically; advanced release installs can set `github-release`. |
56
56
 
57
57
  Example:
@@ -100,13 +100,13 @@ ${PROJMUX_USAGE_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/projmux/usage}/
100
100
  See [Usage tracking](usage-tracking.md) for adapter behavior, throttling, and
101
101
  failure handling.
102
102
 
103
- ## Status Bar Decoration
103
+ ## Decoration Mode
104
104
 
105
- Settings > Status Bar controls the optional cwd/git leading decoration:
105
+ Settings > Icons & Decorations controls optional status and picker decoration:
106
106
 
107
107
  - `off` is the default and avoids icon-font assumptions.
108
- - `symbol` restores the Nerd Font-style folder/git icons.
109
- - `emoji` uses emoji decorators.
108
+ - `symbol` restores the Nerd Font-style folder, GitHub, and bell icons.
109
+ - `emoji` uses emoji decorators, including the notify sidebar header bell.
110
110
 
111
111
  The saved value lives at:
112
112
 
@@ -0,0 +1,228 @@
1
+ # Native Picker Engine
2
+
3
+ This note tracks the native picker engine. Native is the default picker backend,
4
+ while the `internal/ui/fzf` backend remains available as an explicit fallback.
5
+
6
+ The fzf compatibility surface for the native engine is tracked in
7
+ [native-picker-parity.md](native-picker-parity.md).
8
+
9
+ ## What This Covers
10
+
11
+ - `internal/ui/picker` is the backend-neutral contract for native picker rows,
12
+ actions, filtering, and typed-query prompts.
13
+ - `internal/ui/projmuxpicker` is the projmux-specific native picker surface for
14
+ frame, redraw updates, theme tokens, ANSI width/truncation,
15
+ prompt/footer/list rendering, and preview pane layout. The POC keeps `picker`
16
+ responsible for backend routing, keyboard input, filtering, preview command
17
+ execution, and result contracts, while moving visual composition into
18
+ `projmuxpicker` so projmux can evolve a native picker design without coupling
19
+ every visual tweak to the fzf adapter.
20
+ - `internal/ui/fzf` now owns the adapter between fzf's legacy option/result
21
+ shape and the backend-neutral `picker.Options` contract. App code should
22
+ describe picker intent as rows, actions, preview commands, and initial focus;
23
+ the fzf adapter is responsible for translating that into `--expect`,
24
+ `--bind execute-silent(...)`, `+refresh-preview`, and `start:pos(N)`.
25
+ - `intfzf.NewPickerRunner()` wraps fzf behind the same `picker.Runner`
26
+ interface as the native runner. This is the current DI boundary for swapping
27
+ picker engines while keeping fzf available.
28
+ - Settings > Labs > Picker Engine stores the backend selection in
29
+ `~/.config/projmux/picker-backend` and updates the live tmux environment so
30
+ new picker popups can switch between `fzf` and `native` without restarting
31
+ the app server.
32
+ - Native is the default backend. `PROJMUX_PICKER_BACKEND=fzf` remains an
33
+ explicit environment override and takes priority over the saved Labs setting.
34
+ - Picker flows covered by the native path include AI picker/settings, shell
35
+ update prompt, settings hub sections, switch settings/add-pin, the main
36
+ project switcher list, recent sessions, and notify sidebar.
37
+ - The native picker supports ranked fuzzy search/filter, arrow-key selection in
38
+ normal CSI and tmux application-cursor modes, Enter, Esc, Ctrl-C, Backspace,
39
+ Ctrl-U, Ctrl-W, PageUp/PageDown, Home/End, modified CSI keys, custom expect
40
+ keys such as Ctrl-X/Alt-P, printable expect keys such as notify `x`, control
41
+ expect keys such as notify `Ctrl-X`, `start:pos(N)` initial focus, preview
42
+ command output, preview cycle command bindings, and sidebar focus command
43
+ bindings.
44
+ - FZF-style movement keys are supported for native selection: `Ctrl-N` moves
45
+ down, while `Ctrl-P` and `Ctrl-K` move up unless the app claims the key as a
46
+ custom action.
47
+ - Typed-query prompts support cursor-aware insertion/deletion with a visible
48
+ prompt cursor, Left/Right, Ctrl-A/E, Delete, Backspace, Ctrl-U, and Ctrl-W
49
+ for settings path entry.
50
+ - The native key parser recognizes the app's CSI-u keybind-probe sequences
51
+ such as `ESC [ 9005 u` for `Alt-1`, plus generic modified CSI-u forms such as
52
+ `ESC [ 115 ; 7 u` for `Ctrl-Alt-S`.
53
+ - Native interactive picker screens use an alternate screen lifecycle to better
54
+ match fzf fullscreen behavior and restore the tmux pane after exit. Frame
55
+ updates and screen exit both return to column 0 before emitting terminal
56
+ control sequences, and screen exit resets styles plus clears the alternate
57
+ buffer from the home cursor before restore. This keeps restore/update escapes
58
+ and selected-session handoff output from visually trailing the bottom border
59
+ in tmux/script captures. Native also gives real TTY screen restore a short
60
+ settle window before returning to callers that may immediately draw a tmux
61
+ session.
62
+ - Native interactive picker screens render inside a full-screen border frame to
63
+ match the app's fzf `--height 100% --border` surface more closely.
64
+ - Popup-toggle commands use tmux `display-popup -B` when the native backend is
65
+ active so the native picker owns the visible frame and does not double-draw
66
+ with tmux's outer popup border.
67
+ - Native Alt-1 sidebar popups use the same responsive width calculation as fzf
68
+ with a smaller native-only minimum, so the borderless native frame is not
69
+ wider than the existing fzf sidebar surface on normal terminals.
70
+ - Native Alt-2 notify sidebar popups keep the fzf baseline width contract
71
+ (`24%`, minimum `64`) while still letting the native picker own the frame.
72
+ - Native sidebar popups reserve two rows at the bottom for the tmux statusbar
73
+ area instead of using the full client height.
74
+ - Simple native lists use the available terminal height after header, prompt,
75
+ footer, and preview reservations instead of a fixed page-sized viewport.
76
+ - Navigation-only native lists mirror fzf `--disabled --no-input`: the input
77
+ prompt is hidden, printable non-action keys do not alter the query, and
78
+ expect/action keys still work.
79
+ - Native frame content now uses the full inner border width so prompt/list/footer
80
+ separators reach the right border like fzf.
81
+ - Native frames can render an optional picker-owned titlebar row below the top
82
+ border when `picker.Options.Title` is set; empty titles keep the default frame
83
+ unchanged. The native Alt-1 project sidebar uses this for a `Projects`
84
+ titlebar.
85
+ - Native width/truncation uses terminal cell width for Korean/CJK text, emoji,
86
+ and combining marks instead of raw rune count, so localized project names and
87
+ decorated notify headers do not push the right frame border out of alignment.
88
+ - Searchable native pickers draw an explicit `Search` label and a muted
89
+ separator under the prompt/count line so the query area reads as distinct
90
+ chrome rather than the first row of the list. Footer, down-preview, and
91
+ multi-line card gaps share the same `projmuxpicker` separator primitive for a
92
+ more consistent native surface.
93
+ - Native interactive mode enables SGR mouse reporting while the alternate screen
94
+ is active. Primary click applies the clicked row, release events are ignored,
95
+ mouse wheel moves selection up/down, and reporting is disabled again during
96
+ screen restore.
97
+ - When terminal size detection is unavailable, native picker falls back to a
98
+ conservative 80x24 terminal instead of assuming a wider surface. Interactive
99
+ tmux popups still use the detected popup size when `stty size` is available.
100
+ - Simple and multi-line native rows share the same projmux current-row style and
101
+ pointer marker rather than falling back to terminal inverse video for simple
102
+ pickers.
103
+ - Selected multi-line rows use the same pointer-width `▌` continuation marker
104
+ as the first selected project line, so switch/session/notify cards read as one
105
+ focused block.
106
+ - Pointer and continuation markers render inside the current-row gutter style so
107
+ selected cards do not visually break between the marker and row content.
108
+ - Native redraws use terminal synchronized-update wrappers and coalesced
109
+ row-diff updates after the first frame. The frame/redraw renderer lives in
110
+ `projmuxpicker` rather than the backend loop, skips unchanged frames, and
111
+ avoids a trailing newline after the bottom border. This reduces visible
112
+ keyboard-navigation flicker and prevents exact-height popups from scrolling
113
+ the top border off screen.
114
+ - Native preview panes normalize tabs and control bytes before horizontal
115
+ clipping, preventing long preview rows from wrapping and consuming extra
116
+ vertical viewport rows in Alt-3/session popups.
117
+ - Native sidebar list scrollbars use the fixed list viewport as their track and
118
+ measure multi-line cards in rendered rows, so the thumb does not shrink or
119
+ jump when card heights vary.
120
+ - Switch picker git branch badges are capped more tightly for the native card
121
+ surface, so inactive branch backgrounds do not dominate narrow Alt-1 sidebar
122
+ rows.
123
+ - Native selection changes render their frame diff before running sidebar focus
124
+ commands, so tmux focus/switch side effects do not delay the visible picker
125
+ movement.
126
+ - In app TTY contexts, the native picker opens the controlling terminal
127
+ (`/dev/tty`) before entering raw mode. This avoids stdin/stdout mismatch and
128
+ line-mode escape leakage such as arrow keys appearing as `^[[`.
129
+ - Raw TTY reads keep polling briefly across empty reads while decoding
130
+ escape-key sequences, so split arrow/Alt key bytes are consumed by the picker
131
+ instead of leaking into the query or parent shell.
132
+
133
+ ## Experimental Boundaries
134
+
135
+ - The `projmuxpicker` package is intended as a foundation that can be carried
136
+ forward, along with the fzf-to-picker adapter boundary in `internal/ui/fzf`.
137
+ Its frame, row, preview, theme, ANSI, and redraw modules are foundation code;
138
+ Docker sandbox scripts and dependency-policy notes remain support
139
+ scaffolding.
140
+ - Switch and sessions preview panes are native previews for the concrete
141
+ projmux option shapes. Wide right-side preview windows render beside the
142
+ list, and sidebar-style `down,25%,border-top` previews render below the list
143
+ without a synthetic preview title row, using fzf-measured percent sizing.
144
+ Preview rows are padded by `projmuxpicker` to the full preview surface width
145
+ before the outer frame is applied, which keeps split/down preview columns
146
+ visually stable during redraws.
147
+ The full fzf preview-window grammar remains outside this POC surface.
148
+ - Preview cycle state is covered in Docker e2e against real tmux sessions: the
149
+ switch and sessions popup flows type a filtered query, send `Right` and
150
+ `Alt-Down`, and assert the stored preview window/pane cursor for the selected
151
+ session.
152
+ - Public doctor dependency policy remains separate from picker backend
153
+ selection. Native is the default picker backend, and fzf remains available as
154
+ an explicit fallback.
155
+
156
+ ## Interactive No-fzf Sandbox
157
+
158
+ Use this when you want to enter a Docker container and experience this build
159
+ directly without `fzf`. It builds the no-fzf dependency image, mounts this
160
+ worktree, builds `projmux` inside the container, creates sample projects under
161
+ `/workspace/projects`, stores the native picker backend in the sandbox config,
162
+ writes a tmux config with the same backend in the tmux server environment, and
163
+ launches `projmux shell`. It also forces UTF-8 locale inside the container. This
164
+ uses `wt path` instead of `wt run` because `docker run -it` needs the current
165
+ terminal TTY:
166
+
167
+ ```sh
168
+ bash "$(wt path poc/native-picker-no-fzf)/scripts/poc-native-picker-no-fzf-sandbox.sh"
169
+ ```
170
+
171
+ Inside the tmux shell, try:
172
+
173
+ ```sh
174
+ projmux switch
175
+ projmux settings
176
+ projmux doctor --json
177
+ ```
178
+
179
+ Manual UX checks for the Docker sandbox:
180
+
181
+ - Alt-1 opens with the top border/title visible, not clipped.
182
+ - Vertical borders stay continuous while moving Up/Down.
183
+ - Alt-1 closes the sidebar immediately when pressed again.
184
+ - Alt-2, Alt-3, Alt-4, and Alt-5 open their matching native popups and close
185
+ on the same Alt key immediately.
186
+ - Arrow keys move selection without leaking `^[[` text into the query.
187
+
188
+ `fzf` is intentionally not installed in the image.
189
+
190
+ ## Automated No-fzf Docker E2E Command
191
+
192
+ Run this from the repository root. It builds a Go 1.24 Trixie no-fzf
193
+ dependency image from `test/docker/no-fzf-poc.Dockerfile`, including Go module
194
+ cache, then mounts the repository into an isolated `--network none` container,
195
+ builds `projmux`, asserts `fzf` is not on `PATH`, runs the focused native-picker
196
+ tests, stores the native backend through Settings > Labs, verifies the saved
197
+ backend works without an env override, exercises `projmux switch --ui=sidebar`
198
+ search/selection under a container PTY,
199
+ exercises `projmux switch --ui=popup` and `projmux sessions --ui=popup` against
200
+ existing tmux sessions under a wide 150x30 PTY, sends `Right` and `Alt-Down`
201
+ once to smoke the preview-cycle bindings, asserts those popup flows stay on the
202
+ right-side preview layout instead of falling back to inline preview, asserts the
203
+ explicit `Search` chrome across the searchable native picker surfaces, launches
204
+ `projmux shell` under a container PTY, verifies
205
+ that it creates a tmux session, verifies immediate launch-key close behavior for
206
+ Alt-1 through Alt-5 native popup surfaces, exercises `notify list --ui=sidebar`
207
+ with the printable `x` expect key, and exercises the settings picker under a PTY
208
+ using Enter and arrow-key navigation through the native backend. Settings flows
209
+ must keep stderr clean in the no-tmux-server container; tmux no-server noise is
210
+ treated as an e2e failure.
211
+
212
+ Short tmux-friendly form:
213
+
214
+ ```sh
215
+ wt run poc/native-picker-no-fzf -- scripts/poc-native-picker-no-fzf-e2e.sh
216
+ ```
217
+
218
+ The script contains the Docker image build and isolated `docker run` command:
219
+
220
+ ```sh
221
+ scripts/poc-native-picker-no-fzf-e2e.sh
222
+ ```
223
+
224
+ To compare another base image without editing the repo, override the build arg:
225
+
226
+ ```sh
227
+ PROJMUX_POC_NO_FZF_BASE_IMAGE=golang:1.24-bookworm bash "$(wt path poc/native-picker-no-fzf)/scripts/poc-native-picker-no-fzf-sandbox.sh"
228
+ ```
@@ -0,0 +1,145 @@
1
+ # Native Picker fzf Parity Map
2
+
3
+ This audit note reverse-engineers the subset of fzf behavior that projmux
4
+ currently uses and maps it to native picker evidence. It supports the default
5
+ native picker engine and is not a public dependency-policy change.
6
+
7
+ ## App fzf Surface
8
+
9
+ | fzf surface | projmux usage | Native status | Evidence |
10
+ | --- | --- | --- | --- |
11
+ | `--prompt` | AI, settings, shell update, switch, sessions, notify | Covered | `renderNativeInteractive`, `renderNative`; `TestNativePromptLineIncludesInlineMatchCount` |
12
+ | prompt/list separation | native searchable picker chrome | Covered | native renders an explicit `Search` header label plus a separator under searchable prompt/count lines; `TestNativeInteractiveSeparatesSearchHeaderFromList`; Docker no-fzf e2e asserts the `Search` header in Settings, AI settings, mouse-click, switch sidebar, switch popup, sessions popup, and shell Alt-1 PTY logs |
13
+ | `--height 100%` / `--border` | all interactive picker screens | Covered for fullscreen rounded border frame | `renderNativeFrame`; screen-height list budgeting; conservative 80x24 fallback only when terminal size detection is unavailable; `TestNativeInteractiveRendersBorderFrame`; `TestNativeInteractiveUsesAvailableHeightForSimpleLists` |
14
+ | `--header` | AI, settings, shell update, notify | Covered | `renderNativeInteractive`, `renderNative`; settings native tests |
15
+ | `--footer` / `--footer-border line` | AI, settings, shell update, switch, sessions, notify | Covered for interactive native screens | `renderNativeInteractive` reserves bottom footer space and renders a separator line; `TestNativeInteractiveRendersFooterAtBottom` |
16
+ | `--ansi` | colored row labels from render package | Covered | native writes row labels directly, strips ANSI escapes from default search text, restores selected-row styling after embedded ANSI resets, and measures rendered cell width for Korean/CJK text, emoji, and combining marks; `TestFilterItemsIgnoresANSIEscapeSequences`; `TestNativeInteractiveUsesCurrentStyleForSimpleSelection`; `TestVisibleLenUsesTerminalCellWidth`; Docker e2e shows ANSI rows |
17
+ | hidden value after tab delimiter | all picker selections and default fzf matching | Covered by `picker.Item.Value` and default search text | `fzf.PickerOptions`; `TestNativeRunnerFiltersAndSelectsByNumber`; `TestFilterItemsSearchesHiddenValueWhenNoSearchKey` |
18
+ | plain fzf candidates without structured entries | legacy runner call shape | Covered | `fzf.PickerOptions`; `TestPickerOptionsFromFZFMapsCandidatesWhenEntriesAreEmpty` |
19
+ | search key filtering (`--nth`/reload filter file) | switch/sessions/notify entries | Covered by `Item.SearchText` with fzf reload order preservation | `FilterItems`; `TestFilterItemsUsesSearchTextNotMetadata`; `TestFilterItemsPreservesSearchKeyOrder` |
20
+ | default `--smart-case` matching | all searchable picker rows | Covered | native filter keeps lower-case queries case-insensitive and uppercase queries case-sensitive; `TestFilterItemsUsesFZFSmartCase` |
21
+ | fzf match highlighting | searchable simple picker rows | Covered for non-search-key simple rows | native highlights matched visible label runes while preserving embedded ANSI style; search-key reload lists intentionally keep fzf disabled-filter rendering without match highlights; `TestNativeInteractiveHighlightsSimpleQueryMatches`; `TestNativeInteractiveDoesNotHighlightSearchKeyReloadLists` |
22
+ | `--disabled --no-input` | navigation-only notify sidebar | Covered | native suppresses prompt/query editing and ignores printable non-action input; `TestNativeInteractiveDisableSearchIgnoresPrintableInput`; Docker no-fzf e2e asserts notify prompt is hidden |
23
+ | fuzzy result ranking | simple non-search-key picker UX | Covered with fzf V2 dynamic scoring for normal app rows | `fuzzyScore`; `TestFilterItemsRanksBetterMatchesFirst`; `TestFilterItemsPrefersFZFBoundaryAndCamelCaseMatches`; `TestFuzzyScoreMatchesFZFV2ReferenceScores` |
24
+ | `--scrollbar █` | long switch/session/settings lists | Covered for app lists | `nativeListLinesWithScrollbarRows`; proportional multi-row thumb rendering in `projmuxpicker`; split-preview and sidebar list viewports keep a fixed row budget and scrollbar track; multi-line cards use rendered-row scroll units; `TestNativeInteractiveUsesScrollbarForLongLists`; `TestListLinesWithScrollbarUsesProportionalThumb`; `TestListLinesWithScrollbarMovesThumbGradually`; `TestListLinesWithScrollbarRowsKeepsViewportTrack`; `TestRenderSplitPreviewRowsKeepsRequestedViewport`; `TestNativeListScrollbarUnitsUseRenderedRowsForMultiline`; `TestNativeInteractiveKeepsMultilineScrollbarOnViewportTrack` |
25
+ | `--read0` multi-line rows | switch, sessions, notify | Covered | `Options.MultiLine`; `TestNativeInteractiveRendersFZFLikeMultilineSelection` |
26
+ | `--gap --gap-line ─` | switch, sessions, notify multi-line rows | Covered for app multiline rows | `nativeGapLine`, row-budgeted range; `TestNativeInteractiveRendersMultilineGapLine`, `TestNativeVisibleRangeCountsMultilineRenderedRows` |
27
+ | selected multi-line marker | selected switch/session/notify cards | Covered for app multiline rows | native uses the same compact pointer-width red `▌` gutter as the first selected project line, and metadata lines align to the project-name column without the old deeper indent; `nativeContinuation`; `TestNativeInteractiveRendersSelectedMultilineContinuationMarker`; `TestInteractiveRowLinesUsesCompactSelectedMetaIndent`; `TestInteractiveRowLinesAlignsUnselectedMetaWithProjectName` |
28
+ | fzf current row colors | simple and multi-line rows | Covered for app rows | `nativeCurrentStart`, `nativePointer`; pointer/continuation gutter tokens carry the current-row background; `TestNativeSelectedContentKeepsCurrentStyleAfterReset`; `TestNativeInteractiveUsesCurrentStyleForSimpleSelection` |
29
+ | `--expect` keys | Enter/Ctrl-X/Alt-P/notify keys | Covered | `fzf.PickerOptions`; `TestNativeInteractiveSupportsCustomExpectKeys` |
30
+ | printable expect keys | notify sidebar `x` ack | Covered | `TestNativeInteractiveSupportsPrintableExpectKeys`; Docker no-fzf e2e |
31
+ | control expect keys | notify sidebar `Ctrl-X`, settings `Ctrl-Alt-S` close | Covered | `TestNativeInteractiveSupportsControlExpectKeys`; `TestNativeInteractiveSupportsControlAltCloseKeys` |
32
+ | close `--bind key:abort` | Esc, Ctrl-C, Alt-N, Ctrl-Alt-S variants | Covered | `CloseActions`; `TestNativeRunnerUsesSharedCloseActions` |
33
+ | terminal CSI-u key encoding | app keybind probe sequences, Ghostty/kitty-style modified keys | Covered | native handles app-specific Alt keys, generic modified letters/digits, and non-text keys such as Enter/Esc/Backspace/Tab; `TestNativeInteractiveSupportsCSIuAppKeyBindings` |
34
+ | `execute-silent(...)+refresh-preview` | switch/session preview cycling | Covered for command execution and rerender loop | `fzf.PickerOptions`/`fzf.OptionsFromPicker`; `TestNativeInteractiveRunsCustomActionCommandAndRefreshes`; `TestPickerOptionsMapsFZFBindingsToContractActions`; Docker no-fzf e2e sends `Right` and `Alt-Down` before selection |
35
+ | `focus:execute-silent(...)` | switch sidebar focus | Covered | native renders the selection frame diff before running sidebar focus commands so movement stays visible before tmux focus side effects; `runNativeFocusAction`; `TestNativeInteractiveRunsFocusActionOnSelectionChange` |
36
+ | `start:pos(N)` | switch sidebar initial row | Covered | `fzf.PickerOptions`/`fzf.OptionsFromPicker`; `TestPickerOptionsFromFZFMapsStartPosToInitialIndex`; `TestPickerOptionsMapsFZFBindingsToContractActions` |
37
+ | `--preview` | switch, sessions | Covered by command output | `nativePreviewLines`; `TestNativeInteractiveRendersSelectedPreview` |
38
+ | `--preview-window right,60%,border-left` | switch popup, sessions popup | Covered for projmux option shape | `renderNativeSplitPreview` renders a single-column left border without a synthetic title row, uses fzf-measured percent sizing, normalizes preview tabs/control bytes before clipping, and pads both panes to fixed row widths so long preview rows do not wrap into extra vertical rows; `TestNativeInteractiveRendersWidePreviewBesideList`; `TestNativePreviewWidthUsesPreviewWindowPercent`; `TestRenderSplitPreviewRowsPadsBothPanes`; `TestRenderSplitPreviewRowsNormalizesPreviewTabsBeforeTruncating` |
39
+ | `--preview-window down,25%,border-top` | switch sidebar | Covered for projmux option shape | `renderNativeDownPreview` renders an immediate top border without a synthetic title row, uses fzf-measured percent sizing, and pads preview rows to the surface width; `TestNativeInteractiveRendersDownPreviewBelowList`; `TestNativePreviewHeightUsesPreviewWindowPercent`; `TestRenderDownPreviewPadsPreviewRows` |
40
+ | preview scrolling | long switch/session preview output | Covered for keyboard preview scroll | `previewOffset`; `TestNativeInteractiveRendersPreviewOffset` |
41
+ | `--query` | typed settings path defaults | Covered | `Options.InitialQuery`; settings tests |
42
+ | `--print-query` accept-query mode | typed settings path prompts | Covered | `Options.AcceptQuery`; `TestNativeRunnerAcceptsTypedQuery` |
43
+ | query cursor editing | typed settings path prompts | Covered | Left/Right, Ctrl-A/E, Delete, Backspace, Ctrl-U/W query editing plus visible prompt cursor; `TestNativeInteractiveEditsTypedQueryAtCursor`; `TestNativeInteractiveSupportsQueryLineEditingKeys`; `TestNativeInteractiveCtrlUDeletesBeforeCursor`; `TestNativePromptLineRendersQueryCursor` |
44
+ | terminal arrow key variants | interactive selection in tmux/docker | Covered | CSI, SS3/application cursor, modified CSI tests; app TTY `/dev/tty` fallback; raw TTY EOF polling keeps split ESC sequences from leaking into the query |
45
+ | mouse support | optional fzf mouse picker interaction | Partially covered | native enables SGR mouse reporting in interactive alternate-screen mode, primary click applies the clicked row, release events are ignored, and wheel input moves selection; drag gestures remain outside this POC; `TestNativeInteractiveSupportsMouseClickSelection`; `TestNativeInteractiveIgnoresMouseReleaseBeforeClick`; `TestNativeInteractiveSupportsMouseWheelSelection`; Docker no-fzf e2e clicks the AI settings row under a PTY |
46
+ | fzf navigation keys | interactive selection in searchable lists | Covered | native maps CSI-u `Ctrl-J` plus `Ctrl-N` to down and `Ctrl-P`/`Ctrl-K` to up when not claimed by a custom action; raw LF remains Enter for PTY compatibility; `TestNativeInteractiveSupportsFZFNavigationKeys` |
47
+ | alternate-screen lifecycle | fzf fullscreen picker screen restore | Covered | native frame updates and screen exit return to column 0 before terminal control sequences, screen exit resets styles plus clears the alternate buffer from the home cursor before restore, and real TTY restores get a short settle window before caller handoff; `nativeScreenEnter`; `TestNativeInteractiveUsesAlternateScreen`; `TestRenderFullFrameUpdateAlwaysHomesAndWritesFrame` |
48
+ | frame content width | fzf border inner width | Covered | `ContentLayout` uses the frame inner width so separators and rows reach the right border; `TestRendererContentLayoutUsesFrameInnerWidth` |
49
+ | tmux popup frame interaction | native picker popups launched through `popup-toggle` | Covered for native backend popups | `popup-toggle` passes tmux `display-popup -B` when `PROJMUX_PICKER_BACKEND=native`, so the native picker owns the visible frame instead of double-drawing with the tmux popup border; native Alt-1 uses a compact native-only minimum while fzf keeps the previous project sidebar minimum; Alt-1/Alt-2 sidebar heights reserve two bottom statusbar rows; Alt-2 notify sidebar keeps the fzf-like `24%` / min `64` baseline; `TestAppRunTmuxPopupToggleUsesBorderlessPopupForNativeBackend`; `TestSessionizerSidebarWidthKeepsFZFMinimum`; `TestSidebarPopupHeightLeavesStatusbarRows`; `TestNotifySidebarWidthMatchesFZFBaseline`; `TestAppRunTmuxPopupToggleKeepsNotifySidebarFZFSizingForNative` |
50
+ | optional native titlebar | native picker popup frame | Covered for empty-title compatibility and opt-in titles | `picker.Options.Title`; `RenderFrameWithTitle`; `ContentLayoutWithTitle`; empty titles keep the prior frame unchanged, non-empty titles render in a picker-owned row below the top border, and the native Alt-1 project sidebar opts into `Projects`; `TestRendererRenderFrameWithTitleKeepsDefaultWhenTitleEmpty`; `TestRendererRenderFrameWithTitleUsesTitlebarRow`; `TestRendererContentLayoutWithTitleReservesTitlebarRow`; `TestNativeInteractiveRendersOptionalTitlebar`; `TestSwitchCommandNativeSidebarSetsTitle` |
51
+ | redraw flicker/top clipping | keyboard navigation in exact-height tmux popup | Partially covered | native redraws use synchronized updates plus coalesced row diffs after the first frame, skip unchanged frames, render frame diffs before sidebar focus commands, frame rendering avoids trailing bottom-border CRLF, and screen exit clears the alternate buffer before restore; `TestNativeInteractiveWrapsRedrawsInSynchronizedUpdates`; `TestFrameUpdateRendererSkipsUnchangedFrame`; `TestFrameUpdateRendererCoalescesEachFrameUpdate`; `TestRendererRenderFrameUsesCRLFRowsForRawTTY`; `TestNativeInteractiveUsesAlternateScreen` |
52
+
53
+ ## Native Surface Architecture
54
+
55
+ - `internal/ui/picker` remains the backend-neutral contract and owns fzf/native
56
+ routing, keyboard input, fuzzy filtering, action dispatch, preview command
57
+ execution, and result handling.
58
+ - `internal/ui/projmuxpicker` owns projmux-native visual composition: frame,
59
+ redraw updates, ANSI width/truncation, theme tokens, prompt/footer/list
60
+ rendering, selected row styling, scrollbars/gap rows, and preview pane
61
+ geometry/rendering.
62
+ - `internal/ui/fzf` owns the compatibility adapter in both directions:
63
+ `picker.Options` becomes fzf flags/bindings for fallback, and legacy
64
+ `fzf.Options` becomes `picker.Options` for the native backend. This keeps app
65
+ code closer to a DI-style picker contract instead of embedding fzf binding
66
+ strings at each call site.
67
+ - `intfzf.NewPickerRunner()` adapts fzf to the same `picker.Runner` interface
68
+ as `picker.NativeRunner`, so follow-up branches can inject either backend at
69
+ a narrower boundary without deleting the existing fzf runner.
70
+ - Settings > Labs > Picker Engine persists the selected backend in
71
+ `~/.config/projmux/picker-backend` and updates the live tmux server
72
+ environment through `PROJMUX_PICKER_BACKEND`, while direct environment
73
+ overrides still win over saved config. Native is the default when no saved
74
+ backend or override exists; `fzf` remains available as an explicit fallback.
75
+ - The split lets projmux grow a first-party picker design independently from
76
+ the fzf compatibility adapter.
77
+
78
+ ## Verified Flows
79
+
80
+ - `ai` picker/settings: native backend routing covered by app tests. Docker
81
+ no-fzf e2e also types `Codex` into `projmux ai settings` and verifies the
82
+ native simple picker writes the `codex` mode without fzf.
83
+ - `shell` update prompt: native backend routing covered by shared fzf-to-native
84
+ adapter and settings-style typed prompt tests.
85
+ - `settings`: native backend exercised in unit tests and Docker no-fzf e2e
86
+ using Enter plus arrow-key navigation under a PTY. The Docker e2e also fails
87
+ if the Settings flows write tmux no-server noise to stderr while running
88
+ outside tmux.
89
+ - `settings > Labs`: unit-covered backend toggle writes
90
+ `~/.config/projmux/picker-backend`, updates the tmux global
91
+ `PROJMUX_PICKER_BACKEND`, and lets env override saved config.
92
+ - `switch --ui=sidebar`: Docker no-fzf e2e creates sample projects, types
93
+ `bravo`, selects `bravo-web`, and confirms the opened tmux shell path.
94
+ - `switch --ui=popup`: Docker no-fzf e2e creates existing tmux sessions using
95
+ the app's session naming convention, runs the picker under a 150x30 PTY,
96
+ types `bravo`, sends `Right` and `Alt-Down` to exercise preview window/pane
97
+ cycle, asserts the popup stays on the right-side preview layout instead of
98
+ inline preview, asserts the stored preview cursor, selects `bravo-web`, and
99
+ asserts tmux reports the selected session's active target on the expected
100
+ window with the expected pane path.
101
+ - `sessions --ui=popup`: Docker no-fzf e2e creates existing tmux sessions,
102
+ runs the picker under a 150x30 PTY, types `bravo`, sends `Right` and
103
+ `Alt-Down` to exercise preview window/pane cycle, asserts the popup stays on
104
+ the right-side preview layout instead of inline preview, asserts the stored
105
+ preview cursor, selects `bravo-web`, and asserts tmux reports the selected
106
+ session's active target on the expected window with the expected pane path.
107
+ - `notify sidebar`: native routing is unit-covered; Docker no-fzf e2e pushes a
108
+ notification, presses printable expect key `x`, and verifies the row is acked.
109
+
110
+ ## Experimental Boundaries
111
+
112
+ - Preview-window parity is covered for the concrete projmux option shapes
113
+ (`right,60%,border-left` and `down,25%,border-top`) with fzf-measured percent
114
+ sizing. The full fzf preview-window grammar, threshold alternatives, sticky
115
+ headers, and offset expressions are intentionally outside this POC surface.
116
+ - fzf V2 dynamic scoring is covered for normal app-length non-search-key
117
+ rows, including reference scores for boundary, delimiter, camelCase/number,
118
+ gap, and consecutive bonuses. Very large `query * row` matrices intentionally
119
+ fall back to the greedy scorer to avoid pathological memory use. Search-keyed
120
+ app pickers preserve fzf's `--disabled` reload order instead of score-sorting.
121
+ - Mouse support is intentionally narrow in this POC: primary click applies the
122
+ clicked row, release events are ignored, and wheel input moves selection.
123
+ Drag gestures and the full fzf mouse grammar are follow-up work.
124
+ - The public doctor/docs dependency policy is tracked separately from picker
125
+ backend selection. Native is the default picker backend, while fzf remains an
126
+ explicit fallback.
127
+ - Draft PR: https://github.com/crevissepartners/projmux/pull/98.
128
+
129
+ ## Commands
130
+
131
+ Automated no-fzf e2e:
132
+
133
+ ```sh
134
+ wt run poc/native-picker-no-fzf -- scripts/poc-native-picker-no-fzf-e2e.sh
135
+ ```
136
+
137
+ Interactive no-fzf sandbox:
138
+
139
+ ```sh
140
+ bash "$(wt path poc/native-picker-no-fzf)/scripts/poc-native-picker-no-fzf-sandbox.sh"
141
+ ```
142
+
143
+ Do not run the interactive sandbox through `wt run`: current `wt run` captures
144
+ child stdio instead of forwarding the caller's TTY, so Docker cannot attach
145
+ `-it` and terminal picker input will not behave like a real session.
@@ -83,10 +83,11 @@ preserves the stable JSON array used by scripts.
83
83
 
84
84
  `--ui=sidebar` opens the notify queue as an interactive right-side list when
85
85
  run inside the tmux popup surface. Enter focuses the selected target pane and
86
- acks the row after focus succeeds. `a` acks the selected row. `Ctrl-A` clears
86
+ acks the row after focus succeeds. `x` acks the selected row. `Ctrl-X` clears
87
87
  all rows via `notify ack --all`. Rows are intentionally compact: the visible
88
88
  label keeps notification text first, then age, project, window, and pane
89
- metadata; id/source/severity/target remain searchable.
89
+ metadata; hidden queue ids remain action values but the sidebar has no search
90
+ input.
90
91
 
91
92
  `--live` adds a non-mutating explanation view that reads
92
93
  `tmux list-panes -a` and compares the queue with live reply-state panes. It
@@ -13,10 +13,10 @@ or session title, instead of matching every contextual preview line.
13
13
  The picker contract is split in two layers:
14
14
 
15
15
  - `internal/ui/picker` owns backend-neutral items, actions, preview metadata,
16
- backend selection, title-focused filtering, and the opt-in native runner.
16
+ backend selection, title-focused filtering, and the default native runner.
17
17
  - `internal/ui/fzf` adapts that model into the historical fzf command line.
18
18
 
19
- The default fzf backend still sends one logical row per item:
19
+ The fzf fallback backend sends one logical row per item:
20
20
 
21
21
  ```text
22
22
  <visible label>\t<selection value>
@@ -100,12 +100,12 @@ Current implementation:
100
100
  `SearchText`, `MetaLines`, `Badges`, and `PreviewTarget`.
101
101
  - `picker.Options` carries backend-neutral actions, preview metadata, prompt,
102
102
  footer, initial query, and multiline intent.
103
- - fzf remains the default backend and renders the same popup/sidebar surfaces.
104
- - `PROJMUX_PICKER_BACKEND=native` opts into the native runner. It supports
103
+ - Native is the default backend and renders the popup/sidebar surfaces.
104
+ - `PROJMUX_PICKER_BACKEND=fzf` opts into the external fzf runner. Native supports
105
105
  multiline item rendering, title-focused search via `SearchText`, numeric
106
106
  selection, and shared close actions.
107
- - Switcher popup/sidebar still use the fzf backend for full preview and key
108
- action parity. Native preview panes, raw-key navigation, and sidebar focus
109
- tracking remain follow-up work.
107
+ - Switcher popup/sidebar use the selected backend for preview and key action
108
+ parity, including native preview panes, raw-key navigation, and sidebar focus
109
+ tracking.
110
110
 
111
- fzf can stay as the stable fallback while the native picker reaches parity.
111
+ fzf can stay as the stable fallback while the native picker continues to mature.
package/docs/roadmap.md CHANGED
@@ -73,9 +73,9 @@ v0.4 shipped.
73
73
 
74
74
  - Picker-domain model separate from fzf row encoding (kept fzf as the
75
75
  stable fallback backend). Done in the 0.5 picker contract slice.
76
- - Opt-in native picker backend for multi-line card rows and
77
- title-focused search. Done in the 0.5 picker contract slice via
78
- `PROJMUX_PICKER_BACKEND=native`.
76
+ - Native picker backend for multi-line card rows and title-focused search.
77
+ Done in the 0.5 picker contract slice, later promoted to the default picker
78
+ backend with `PROJMUX_PICKER_BACKEND=fzf` kept as the explicit fallback.
79
79
  - Port switcher popup/sidebar surfaces after parity tests cover
80
80
  selection, preview, and key actions.
81
81
 
package/docs/statusbar.md CHANGED
@@ -27,7 +27,11 @@ row 1 #[range=user|notify] <notify HUD pill> #[norange]
27
27
  `isWindowListRangeToken` fallback is now defense-in-depth only.
28
28
  The session, pwd, kube, and git segments on this row are wrapped
29
29
  in `#[range=user|<id>]` ranges and dispatched through the projmux
30
- handler.
30
+ handler. The git segment shows the current branch or detached commit,
31
+ then compact state indicators when available: `*` for local changes,
32
+ `+N` for staged entries, and `↑N`/`↓N` for ahead/behind counts. Each
33
+ state token gets its own compact foreground color while preserving the
34
+ existing branch block background.
31
35
  - Row 1 splits the line with `#[align=left]` (the pending AI notify
32
36
  queue, capped at 80
33
37
  cells) and `#[align=right]` (usage, capped at 120 cells). `notify` is the
@@ -73,8 +77,10 @@ The path popup uses a short title, one-line copy status, the current path, and
73
77
  an `Enter closes this popup` prompt. If the tmux buffer write fails, it keeps
74
78
  the same compact surface with `Current path` as the title and a copy-unavailable
75
79
  message. The notification HUD detail surface (`Alt-2` / `User2`) opens the
76
- right-side `Notifications` popup with newest-first rows; selecting a row still
77
- focuses and acknowledges that notification.
80
+ right-side notification popup with newest-first rows. The popup itself is
81
+ untitled; when decoration mode is `symbol` or `emoji`, the bell appears before
82
+ the fzf header text instead. Selecting a row still focuses and acknowledges
83
+ that notification.
78
84
 
79
85
  Empty `#{mouse_status_range}` (a click on whitespace) falls through to
80
86
  `select-window -t @<mouse_window>` when `--mouse-window` is non-empty,
@@ -128,10 +134,10 @@ emits a deterministic block per segment), regenerate, and re-apply:
128
134
  projmux tmux apply
129
135
  ```
130
136
 
131
- Settings > Status Bar > cwd/git leading decoration controls the optional
132
- prefix before the path and git branch. The persisted enum lives at
137
+ Settings > Icons & Decorations controls the optional decoration mode used by
138
+ the path, git branch, and notification sidebar header. The persisted enum lives at
133
139
  `~/.config/projmux/statusbar-decoration`; valid values are `off` (default,
134
- font-safe), `symbol` (Nerd Font-style folder/git icons), and `emoji`.
140
+ font-safe), `symbol` (Nerd Font-style folder/GitHub/bell icons), and `emoji`.
135
141
  Settings also updates tmux `@projmux_statusbar_decoration` for the live
136
142
  server when run inside tmux.
137
143
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projmux",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "tmux project session manager",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/crevissepartners/projmux#readme",
@@ -24,10 +24,10 @@
24
24
  "LICENSE"
25
25
  ],
26
26
  "optionalDependencies": {
27
- "@projmux/darwin-arm64": "0.4.6",
28
- "@projmux/darwin-x64": "0.4.6",
29
- "@projmux/linux-arm64": "0.4.6",
30
- "@projmux/linux-x64": "0.4.6"
27
+ "@projmux/darwin-arm64": "0.4.7",
28
+ "@projmux/darwin-x64": "0.4.7",
29
+ "@projmux/linux-arm64": "0.4.7",
30
+ "@projmux/linux-x64": "0.4.7"
31
31
  },
32
32
  "scripts": {
33
33
  "package:npm": "scripts/package-npm.sh",