projmux 0.6.7 → 0.7.1
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.
- package/README-ko.md +36 -5
- package/README.md +40 -12
- package/docs/agent-workflow.md +10 -6
- package/docs/architecture.md +4 -3
- package/docs/assets/projmux-ai-attention.gif +0 -0
- package/docs/assets/projmux-skill-workflow.gif +0 -0
- package/docs/cli.md +22 -11
- package/docs/configuration.md +106 -43
- package/docs/keybindings.md +89 -32
- package/docs/native-picker-no-fzf-poc.md +3 -2
- package/docs/native-picker-parity.md +4 -4
- package/docs/notify-queue.md +56 -19
- package/docs/settings-ia.md +19 -11
- package/docs/statusbar.md +31 -7
- package/docs/testing.md +5 -1
- package/docs/theme-palette.md +130 -55
- package/docs/upgrading.md +77 -0
- package/package.json +5 -5
- package/docs/assets/projmux-shell-sidebar.gif +0 -0
- package/docs/readme-hero-gif-recording.md +0 -97
package/docs/keybindings.md
CHANGED
|
@@ -4,7 +4,7 @@ projmux is keyboard-driven, but the guaranteed launch contract is small:
|
|
|
4
4
|
fresh installs bind `Alt-1` through `Alt-5` as plain Meta sequences
|
|
5
5
|
(`M-1`..`M-5`, bytes `\x1b1`..`\x1b5`). Other actions remain discoverable in
|
|
6
6
|
Settings > Keybindings. Transport-dependent actions keep their built-in
|
|
7
|
-
transport default key, and Settings can add separate safe tmux plain
|
|
7
|
+
transport default key, and Settings can add separate safe tmux plain keys to
|
|
8
8
|
the same action. They are not installed as terminal-specific User-key
|
|
9
9
|
fallbacks. `UserN` and `CSI-u` are legacy/removal/unsupported targets, not
|
|
10
10
|
supported fallback guidance.
|
|
@@ -15,14 +15,26 @@ The recommended path when a key does not fire:
|
|
|
15
15
|
2. Run `projmux setup` outside tmux to see which bytes reach the process.
|
|
16
16
|
3. For supported terminals, preview `projmux init [terminal]`; add `--apply`
|
|
17
17
|
only after reviewing the merge.
|
|
18
|
-
4. For unsupported terminals, configure plain Meta bytes or add a
|
|
18
|
+
4. For unsupported terminals, configure plain Meta bytes or add a custom key in
|
|
19
19
|
Settings > Keybindings.
|
|
20
20
|
|
|
21
|
-
Settings
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
running
|
|
25
|
-
and
|
|
21
|
+
Settings saves safe tmux plain chords for actions and automatically applies the
|
|
22
|
+
change to the app config and the running tmux session when Settings is opened
|
|
23
|
+
from inside tmux. After each save/reset it shows the three outcomes together:
|
|
24
|
+
saved, prepared, and running session. Successful in-tmux saves keep those labels
|
|
25
|
+
user-facing; failure and skipped states include diagnostic terms such as
|
|
26
|
+
`keymap.toml`, generated tmux config, or live tmux reload so the broken stage is
|
|
27
|
+
clear. If Settings is run outside tmux, the running-session stage is skipped and
|
|
28
|
+
the recovery/sync action is `projmux tmux apply`. Raw escape payloads, Windows
|
|
29
|
+
Terminal `sendInput` strings, and tmux User keys are rejected as action keys.
|
|
30
|
+
Settings capture diagnostics split the observed result into logical key, raw
|
|
31
|
+
bytes, and the tmux key name that can be saved. Diagnostic states distinguish
|
|
32
|
+
keys that did not arrive, ambiguous bytes such as Enter/Ctrl-M, and keys that
|
|
33
|
+
need a supported terminal adapter. Safe direct keys are logical tmux names such
|
|
34
|
+
as `M-a`, `M-1`, `C-r`, `C-Space`, function/navigation names, or printable
|
|
35
|
+
keys. Raw escape bytes, CSI-u, xterm modified-key payloads, and tmux
|
|
36
|
+
UserKey/UserSequence names stay diagnostic-only and are not promoted into
|
|
37
|
+
`keymap.toml`.
|
|
26
38
|
|
|
27
39
|
## Quick Start
|
|
28
40
|
|
|
@@ -32,10 +44,14 @@ These shortcuts are the guaranteed launch defaults. They need no tmux prefix.
|
|
|
32
44
|
| --- | --- |
|
|
33
45
|
| `Alt-1` | Project sidebar |
|
|
34
46
|
| `Alt-2` | Notify sidebar |
|
|
35
|
-
| `Alt-3` |
|
|
47
|
+
| `Alt-3` | Recent Windows |
|
|
36
48
|
| `Alt-4` | AI split popup picker |
|
|
37
49
|
| `Alt-5` | Settings |
|
|
38
50
|
|
|
51
|
+
`RecentWindows:Open` opens the cross-project recent windows queue. It switches
|
|
52
|
+
to the selected live tmux window using that window's current active pane; it is
|
|
53
|
+
separate from `last-pane` and from the existing-session popup.
|
|
54
|
+
|
|
39
55
|
The tmux prefix remains the upstream default `Ctrl-b`. Inside a running
|
|
40
56
|
session, `Ctrl-b ?` lists the live tmux bindings.
|
|
41
57
|
|
|
@@ -43,19 +59,29 @@ session, `Ctrl-b ?` lists the live tmux bindings.
|
|
|
43
59
|
|
|
44
60
|
Settings > Keybindings lists the full action catalogue. In particular, sidebar
|
|
45
61
|
keymap actions, pane switching, window switching, and rename actions remain
|
|
46
|
-
visible.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
visible.
|
|
63
|
+
|
|
64
|
+
The Settings flow is intentionally simple: the root is one action list with a
|
|
65
|
+
key summary and state. The key summary uses the first key plus `+N`, or
|
|
66
|
+
`Not bound` when no key is active. State vocabulary is limited to Default,
|
|
67
|
+
Custom, Available, and Unbound. Each action detail shows the action label,
|
|
68
|
+
state, a flat Keys list with `+ Add key`, Options, and a collapsed
|
|
69
|
+
Troubleshooting row with Test key delivery and Advanced... entry points. Key
|
|
70
|
+
rows open key detail for Remove key and Test key. Add key opens Press a key by
|
|
71
|
+
default; Enter key name, the safe direct key pool, risky/reserved key copy, and
|
|
72
|
+
raw diagnostics live under Advanced. Advanced delivery is still owned by the
|
|
73
|
+
selected Projmux action: supported Ghostty and Windows Terminal mappings are
|
|
74
|
+
previewed/applied through `projmux init`, not by storing raw sequences in the
|
|
75
|
+
primary keymap. Options covers unbinding the action and reset/use-default
|
|
76
|
+
flows. Diagnostic/probe/init workflows are not first-class Settings tabs; use
|
|
77
|
+
`projmux setup` and `projmux init` from the terminal when key delivery needs
|
|
78
|
+
remediation.
|
|
79
|
+
|
|
80
|
+
Optional direct keys can be added for actions such as:
|
|
56
81
|
|
|
57
82
|
| Canonical action | Meaning |
|
|
58
83
|
| --- | --- |
|
|
84
|
+
| `RecentWindows:Open` | Recent windows queue across projects |
|
|
59
85
|
| `ProjectSwitcherToggle` | Project switcher popup |
|
|
60
86
|
| `AISplitPickerToggle` | AI split popup picker; pressing again closes the picker popup |
|
|
61
87
|
| `ai-split-right` | Open a new direct AI split to the right |
|
|
@@ -77,20 +103,20 @@ movement. Previous/next window remain transport-dependent and the generated app
|
|
|
77
103
|
tmux config binds `M-S-Left` / `M-S-Right` to the tmux window navigation
|
|
78
104
|
commands. These default transport keys are always rendered by projmux, because
|
|
79
105
|
delivery still depends on the terminal forwarding the modifier-arrow sequence.
|
|
80
|
-
Settings can add extra safe plain
|
|
81
|
-
`previous-window`; those
|
|
106
|
+
Settings can add extra safe plain keys, such as `M-[` for
|
|
107
|
+
`previous-window`; those keys are saved to `keymap.toml` as `keys = [...]`
|
|
82
108
|
without storing or replacing the transport default. Rename actions no longer
|
|
83
109
|
have a built-in terminal fallback; use tmux's prefix rename flow or configure
|
|
84
|
-
an explicit safe
|
|
110
|
+
an explicit safe key where the action is editable.
|
|
85
111
|
|
|
86
112
|
## Product Requirements
|
|
87
113
|
|
|
88
114
|
Settings > Keybindings stays a discovery surface. It must continue to expose
|
|
89
115
|
launch toggles, sidebar keymap actions, picker-local actions, pane switching,
|
|
90
|
-
window switching, and rename actions. The
|
|
91
|
-
terminal remediation surface:
|
|
92
|
-
terminal mapping preview/apply, and init execution rows stay out of
|
|
93
|
-
detail.
|
|
116
|
+
window switching, and rename actions. The basic Settings flow is not the
|
|
117
|
+
terminal remediation surface: key-role replacement, disable-default, typed
|
|
118
|
+
fallback, terminal mapping preview/apply, and init execution rows stay out of
|
|
119
|
+
the action detail.
|
|
94
120
|
|
|
95
121
|
The product model does not support `UserN` or `CSI-u` as fallback guidance.
|
|
96
122
|
Windows Terminal and Ghostty adapters use built-in plain Meta/control bytes or
|
|
@@ -110,10 +136,31 @@ by different picker surfaces, while conflicts inside one surface are rejected.
|
|
|
110
136
|
| `SessionPopup:KillSession` | Kill the focused session |
|
|
111
137
|
| `SessionPopup:CyclePreviewWindowPrev` / `SessionPopup:CyclePreviewWindowNext` | Preview windows |
|
|
112
138
|
| `SessionPopup:CyclePreviewPanePrev` / `SessionPopup:CyclePreviewPaneNext` | Preview panes |
|
|
113
|
-
| `NotifySidebar:Ack` / `NotifySidebar:ClearNonCritical` / `NotifySidebar:ClearAll` | Manage notifications |
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
139
|
+
| `NotifySidebar:Ack` / `NotifySidebar:AckGroup` / `NotifySidebar:ClearNonCritical` / `NotifySidebar:ClearAll` | Manage notifications |
|
|
140
|
+
|
|
141
|
+
Notify sidebar Right/Left child-row show/hide behavior is picker-local and is
|
|
142
|
+
not part of the Settings action catalog. `NotifySidebar:AckGroup` defaults to
|
|
143
|
+
uppercase `A`, distinct from `NotifySidebar:Ack` on lowercase `a`.
|
|
144
|
+
|
|
145
|
+
Runtime picker footers render key guides from the merged keymap, using the
|
|
146
|
+
first active key as the representative key.
|
|
147
|
+
|
|
148
|
+
In Settings > Keybindings, **Add key** appends a key to the selected action's
|
|
149
|
+
`keys = [...]` list. For catalog popup toggle actions, those keys are used both
|
|
150
|
+
by generated tmux open bindings and by popup-internal close bindings, so the
|
|
151
|
+
same key can close the corresponding already-open popup. This same-key close
|
|
152
|
+
behavior is only for actions cataloged as popup toggles, such as
|
|
153
|
+
`ProjectSidebarToggle`, `NotifySidebarToggle`, `RecentWindows:Open`,
|
|
154
|
+
`AISplitPickerToggle`, `SettingsToggle`, `ProjectSwitcherToggle`, and
|
|
155
|
+
`SessionPopupToggle`. Direct command actions such as `new-window`, pane/window
|
|
156
|
+
navigation, and direct AI split actions remain command bindings and are not
|
|
157
|
+
treated as popup close keys.
|
|
158
|
+
|
|
159
|
+
Settings is the default apply path for key edits: it writes the key list,
|
|
160
|
+
refreshes the generated config, and reloads the running tmux session when
|
|
161
|
+
possible. Use `projmux tmux apply` as a CLI recovery/sync command after editing
|
|
162
|
+
the keymap file by hand, after an outside-tmux Settings save, or after resolving
|
|
163
|
+
a reported generated-config or live-reload failure.
|
|
117
164
|
|
|
118
165
|
## Keymap File
|
|
119
166
|
|
|
@@ -150,7 +197,7 @@ so Settings can distinguish them from the `Alt-4` popup picker toggle.
|
|
|
150
197
|
## Diagnose: `projmux setup`
|
|
151
198
|
|
|
152
199
|
Run `projmux setup` outside tmux to find out which projmux keys reach the raw
|
|
153
|
-
terminal. Settings > Keybindings remains the action
|
|
200
|
+
terminal. Settings > Keybindings remains the action-key editor; setup is the
|
|
154
201
|
terminal delivery diagnostic.
|
|
155
202
|
|
|
156
203
|
| Status | Meaning |
|
|
@@ -159,6 +206,16 @@ terminal delivery diagnostic.
|
|
|
159
206
|
| `MISS timeout` | No bytes arrived because the terminal swallowed the key. |
|
|
160
207
|
| `MISS unknown` | Bytes arrived, but they do not match the expected plain sequence. |
|
|
161
208
|
|
|
209
|
+
Settings capture uses the same underlying probe but reports a read model with
|
|
210
|
+
separate fields:
|
|
211
|
+
|
|
212
|
+
| Field | Meaning |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| Logical key | The key the user intended to press, such as `Alt-1`. |
|
|
215
|
+
| Raw bytes | The bytes captured from the terminal, shown escaped. |
|
|
216
|
+
| tmux received key | The logical tmux key name that can be saved, or a diagnostic placeholder when none is safe. |
|
|
217
|
+
| Delivery status | `delivered`, `key-did-not-arrive`, `ambiguous-key`, or `adapter-needed`. |
|
|
218
|
+
|
|
162
219
|
Useful flags:
|
|
163
220
|
|
|
164
221
|
```sh
|
|
@@ -184,7 +241,7 @@ projmux init --allow-symlink
|
|
|
184
241
|
|
|
185
242
|
The merge is idempotent: matching bindings are no-ops, missing bindings are
|
|
186
243
|
added, and keys already mapped to a different user action are skipped with a
|
|
187
|
-
warning. `projmux init` does not read `keymap.toml`; direct tmux
|
|
244
|
+
warning. `projmux init` does not read `keymap.toml`; direct tmux keys still
|
|
188
245
|
belong in Settings > Keybindings or the keymap file.
|
|
189
246
|
|
|
190
247
|
### Ghostty
|
|
@@ -219,7 +276,7 @@ previous/next window:
|
|
|
219
276
|
"actions": [
|
|
220
277
|
{ "command": { "action": "sendInput", "input": "\u001b1" }, "id": "User.projmuxSidebar" },
|
|
221
278
|
{ "command": { "action": "sendInput", "input": "\u001b2" }, "id": "User.projmuxNotifySidebar" },
|
|
222
|
-
{ "command": { "action": "sendInput", "input": "\u001b3" }, "id": "User.
|
|
279
|
+
{ "command": { "action": "sendInput", "input": "\u001b3" }, "id": "User.projmuxRecentWindows" },
|
|
223
280
|
{ "command": { "action": "sendInput", "input": "\u001b4" }, "id": "User.projmuxAIPicker" },
|
|
224
281
|
{ "command": { "action": "sendInput", "input": "\u001b5" }, "id": "User.projmuxSettings" },
|
|
225
282
|
{ "command": { "action": "sendInput", "input": "\u0002r" }, "id": "User.projmuxAISplitRight" },
|
|
@@ -112,7 +112,7 @@ The fzf compatibility surface for the native engine is tracked in
|
|
|
112
112
|
the top border off screen.
|
|
113
113
|
- Native preview panes normalize tabs and control bytes before horizontal
|
|
114
114
|
clipping, preventing long preview rows from wrapping and consuming extra
|
|
115
|
-
vertical viewport rows in
|
|
115
|
+
vertical viewport rows in session popups.
|
|
116
116
|
- Native sidebar list scrollbars use the fixed list viewport as their track and
|
|
117
117
|
measure multi-line cards in rendered rows, so the thumb does not shrink or
|
|
118
118
|
jump when card heights vary.
|
|
@@ -179,8 +179,9 @@ Manual UX checks for the Docker sandbox:
|
|
|
179
179
|
- Alt-1 opens with the top border/title visible, not clipped.
|
|
180
180
|
- Vertical borders stay continuous while moving Up/Down.
|
|
181
181
|
- Alt-1 closes the sidebar immediately when pressed again.
|
|
182
|
-
- Alt-2, Alt-
|
|
182
|
+
- Alt-2, Alt-4, and Alt-5 open their matching native popups and close
|
|
183
183
|
on the same Alt key immediately.
|
|
184
|
+
- Alt-3 opens Recent Windows.
|
|
184
185
|
- Arrow keys move selection without leaking `^[[` text into the query.
|
|
185
186
|
|
|
186
187
|
`fzf` is intentionally not installed in the image.
|
|
@@ -47,9 +47,9 @@ native picker engine and is not a public dependency-policy change.
|
|
|
47
47
|
| fzf navigation keys | interactive selection in searchable lists | Covered | native maps modified-key `Ctrl-J` plus `Ctrl-N` to down and `Ctrl-P`/`Ctrl-K` to up when not claimed by a custom action; up/down-family movement is safe on empty lists; raw LF remains Enter for PTY compatibility; `TestNativeInteractiveSupportsFZFNavigationKeys`; `TestNativeInteractiveNavigationKeysAreNoopForEmptyList` |
|
|
48
48
|
| 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` |
|
|
49
49
|
| frame content width | fzf border inner width | Covered | `ContentLayout` uses the frame inner width so separators and rows reach the right border; `TestRendererContentLayoutUsesFrameInnerWidth` |
|
|
50
|
-
| picker-owned app background | native picker frame interior | Covered for renderer-owned cells | `ThemeFromEffective` applies built-in fallback and explicit effective
|
|
51
|
-
| 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; tmux 3.4 per-command `display-popup -s` is used for the popup body style, setting `bg
|
|
52
|
-
| 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 section below the top border, titlebar text/divider/chip gaps inherit the frame
|
|
50
|
+
| picker-owned app background | native picker frame interior | Covered for renderer-owned cells | `ThemeFromEffective` applies built-in fallback and explicit effective `surface` / `chrome_foreground` SGR to the native frame, and frame rows resume the app style after embedded resets so content padding, empty no-footer rows, footer rows, scrollbars, and preview gaps do not leak terminal default background; `TestThemeFromEffectiveFallbackPaintsFrameBackground`; `TestRendererFrameBackgroundResumesAfterContentResetBeforePadding`; `TestNativeInteractiveNoFooterBlankRowsUseThemeBackground`; `TestNativeInteractiveSplitPreviewGapsUseThemeBackground`; `TestNativeInteractiveSettingsAIBadgeStyleLongPreviewClampsFrameRows` |
|
|
51
|
+
| 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; tmux 3.4 per-command `display-popup -s` is used for the popup body style, setting `bg` from `surface` and `fg` from `chrome_foreground` so tmux's blank/pre-draw popup body matches the native picker surface before the app renderer paints; no global `popup-style`, `popup-border-style`, shell pane background, `default-style`, `window-style`, OSC background, or status/window palette options are changed; 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`; `TestAppRunTmuxPopupToggleUsesNativePopupBodyStyleFromEffectiveTheme`; `TestBuildPopupToggleWithPickerBackendStylesNativeOnly`; `TestBuildDisplayPopupArgsAddsBodyStyle`; `TestSessionizerSidebarWidthKeepsFZFMinimum`; `TestSidebarPopupHeightLeavesStatusbarRows`; `TestNotifySidebarWidthMatchesFZFBaseline`; `TestAppRunTmuxPopupToggleKeepsNotifySidebarFZFSizingForNative` |
|
|
52
|
+
| 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 section below the top border, titlebar text/divider/chip gaps inherit the frame `surface` / `chrome_foreground` instead of a separate titlebar overlay ANSI layer, and the native Alt-1 project sidebar opts into `Projects`; `TestRendererRenderFrameWithTitleKeepsDefaultWhenTitleEmpty`; `TestRendererRenderFrameWithTitleUsesTitlebarRow`; `TestRendererContentLayoutWithTitleReservesTitlebarRow`; `TestNativeInteractiveRendersOptionalTitlebar`; `TestSwitchCommandNativeSidebarSetsTitle` |
|
|
53
53
|
| 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` |
|
|
54
54
|
|
|
55
55
|
## Native Surface Architecture
|
|
@@ -75,7 +75,7 @@ native picker engine and is not a public dependency-policy change.
|
|
|
75
75
|
|
|
76
76
|
Native picker frame chrome is normalized in `internal/ui/projmuxpicker`.
|
|
77
77
|
Titlebar text, title dividers, and chip-strip gaps inherit the frame
|
|
78
|
-
|
|
78
|
+
`surface` / `chrome_foreground` instead of applying a second titlebar overlay ANSI layer;
|
|
79
79
|
chip bodies can still carry active/inactive/disabled tones. Search prompt and
|
|
80
80
|
footer separators fill the available frame width, and header, row, footer, and
|
|
81
81
|
preview lines close any active SGR style before padding or frame borders can
|
package/docs/notify-queue.md
CHANGED
|
@@ -106,21 +106,48 @@ table `ID AGE SEV SRC TARGET TEXT`. `--severity` / `--source` are
|
|
|
106
106
|
repeatable filters. Without `--live`, this command reads only the queue and
|
|
107
107
|
preserves the stable JSON array used by scripts.
|
|
108
108
|
|
|
109
|
-
`--ui=sidebar` opens the notify queue as an interactive right-side
|
|
110
|
-
run inside the tmux popup surface.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
and
|
|
117
|
-
|
|
109
|
+
`--ui=sidebar` opens the notify queue as an interactive right-side pane/session
|
|
110
|
+
inbox when run inside the tmux popup surface. The queue source of truth remains
|
|
111
|
+
flat; the sidebar builds a read-only grouped view for display. The first screen
|
|
112
|
+
shows collapsed group rows keyed by pane when available, then window, then
|
|
113
|
+
session/external fallback. Each group row is a fixed three-line card: line 1
|
|
114
|
+
keeps project/session plus agent/provider with newest age, line 2 keeps
|
|
115
|
+
topic/pane-title/task context plus severity/live-state aggregate
|
|
116
|
+
metadata, and line 3 keeps the latest notification preview. Collapsed group
|
|
117
|
+
cards do not promote window/pane ids as primary information. A `+N` badge is
|
|
118
|
+
shown only when the group can unfold, and `N` is the number of child
|
|
119
|
+
notification rows that will appear; one-notification group headers omit both
|
|
120
|
+
the count badge and strong fold marker. Right/Left show and hide child rows for
|
|
121
|
+
foldable groups inside the native sidebar only; this fold state is
|
|
122
|
+
session-local and is not persisted. Right on a childless group refreshes
|
|
123
|
+
without adding rows. Enter on a group row, whether folded or expanded, focuses
|
|
124
|
+
the group's representative pane and acknowledges every visible notification in
|
|
125
|
+
that group only after focus succeeds. Inactive means an `ai:` queue entry points
|
|
126
|
+
to a pane that no longer matches live reply+agent state; it is not a time-age
|
|
127
|
+
TTL state, and Enter still focuses the target when it is routable. If the
|
|
128
|
+
representative target is gone/unroutable, Enter treats the selected pane inbox
|
|
129
|
+
as explicit cleanup and acknowledges/prunes the visible group without focusing,
|
|
130
|
+
including critical notifications. If a live- or inactive-looking representative target
|
|
131
|
+
disappears during focus, Enter uses the same gone-group cleanup policy. Other
|
|
132
|
+
focus failures keep the group pending, show a clear message, and refresh/prune
|
|
133
|
+
the list. Expanded child notification rows are compact event rows with age,
|
|
134
|
+
message preview, and severity/state while keeping the existing focus/ack-one
|
|
135
|
+
behavior. The surface actions
|
|
136
|
+
`NotifySidebar:Ack`, `NotifySidebar:AckGroup`,
|
|
137
|
+
`NotifySidebar:ClearNonCritical`, and `NotifySidebar:ClearAll` are internal
|
|
138
|
+
picker actions; direct launch aliases are edited in Settings, while internal
|
|
139
|
+
picker aliases are adjusted in `keymap.toml` when needed.
|
|
140
|
+
`NotifySidebar:AckGroup` defaults to uppercase `A` and explicitly
|
|
141
|
+
acknowledges every visible notification in the selected group, including
|
|
142
|
+
critical notifications. Runtime footer key guides read the merged keymap and
|
|
143
|
+
show the default alias when present, otherwise the first configured alias, so
|
|
144
|
+
custom aliases do not make the UI stale.
|
|
145
|
+
`NotifySidebar:Ack`, `NotifySidebar:AckGroup`, and
|
|
118
146
|
`NotifySidebar:ClearNonCritical` refresh rows, live state, and selection inside
|
|
119
147
|
the same native picker session; `NotifySidebar:ClearAll` still closes the
|
|
120
|
-
popup and prints a summary. Rows are intentionally compact:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
intentionally does not expose a separate metadata detail view.
|
|
148
|
+
popup and prints a summary. Rows are intentionally compact: hidden queue ids
|
|
149
|
+
remain action values but the sidebar has no search input and intentionally does
|
|
150
|
+
not expose a separate metadata detail view.
|
|
124
151
|
|
|
125
152
|
When a new pending notification is successfully pushed by any app producer
|
|
126
153
|
(`notify push`, reply-ready, reconcile backfill, or bell fallback), open native
|
|
@@ -142,11 +169,20 @@ output becomes `{queue, live, rows, errors}`. Typical states:
|
|
|
142
169
|
queue entry.
|
|
143
170
|
- `live-ai-reply-missing-queue` — a live AI reply pane lacks the derived
|
|
144
171
|
queue entry; run `projmux notify reconcile` to back-fill it.
|
|
145
|
-
- `queue-stale` —
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
172
|
+
- `queue-stale` — preserved machine-readable state for an inactive target:
|
|
173
|
+
an `ai:` queue entry whose pane still EXISTS in the live tmux pane inventory,
|
|
174
|
+
but no longer matches reply+agent state. It is not TTL/time age. Surfaced in
|
|
175
|
+
the sidebar/statusbar as `INACTIVE` / `INA`; Enter still focuses and acks if
|
|
176
|
+
the target is routable.
|
|
177
|
+
- `queue-gone` — the queue entry's target is gone. This is now determined two
|
|
178
|
+
ways: (a) the entry has no routable target (empty session), or (b) the entry
|
|
179
|
+
carries a pane target whose pane id is absent from the real tmux live pane
|
|
180
|
+
inventory (`tmux list-panes -a`). Surfaced as `GONE` / `GON`, and Enter/ack
|
|
181
|
+
cleans it up without focusing. The inventory check is best-effort: when the
|
|
182
|
+
pane inventory cannot be read (tmux error, or an empty/unrecognized reply),
|
|
183
|
+
membership-based GONE is skipped so a missing tmux server never falsely
|
|
184
|
+
dims/gones every row, and only pane-target rows are eligible (window/session-
|
|
185
|
+
only rows keep the empty-session check only).
|
|
150
186
|
- `queue-only` — a non-AI/external queue entry is pending and has no live AI
|
|
151
187
|
reply-pane requirement.
|
|
152
188
|
|
|
@@ -176,7 +212,8 @@ path), then:
|
|
|
176
212
|
- pushes/refreshes one `ai:<session>:<pane>` entry for every pane
|
|
177
213
|
whose attention state is `reply` AND whose agent option is non-empty;
|
|
178
214
|
- reports every existing queue entry whose id starts with `ai:` and whose
|
|
179
|
-
pane no longer matches that condition as stale
|
|
215
|
+
pane no longer matches that condition as inactive/`queue-stale`, without
|
|
216
|
+
acking it.
|
|
180
217
|
|
|
181
218
|
Successful backfill pushes publish the same best-effort open-sidebar refresh
|
|
182
219
|
event as other pending queue additions.
|
package/docs/settings-ia.md
CHANGED
|
@@ -24,16 +24,22 @@ view-first layout:
|
|
|
24
24
|
commands, `Pane navigation`, `Window navigation`, and `Rename` groups or
|
|
25
25
|
equivalent searchable rows.
|
|
26
26
|
- `Settings > Keybindings > Action` keeps the user-facing edit path small:
|
|
27
|
-
action,
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
action label, state, a flat Keys list, Options, and a collapsed
|
|
28
|
+
Troubleshooting row. Keys shows only currently active/effective keys plus
|
|
29
|
+
`+ Add key`. Pressing a key row opens key detail, where Remove key and Test
|
|
30
|
+
key live. Options offers Unbind and Reset to default/Use default when
|
|
31
|
+
state-appropriate. Add key opens the default Press a key flow with Cancel and
|
|
32
|
+
Advanced...; typed key-name entry and raw diagnostics live under Advanced. It
|
|
33
|
+
does not expose Default key, Apply State, Delivery, Advanced Delivery,
|
|
34
|
+
key-role replacement, terminal mapping preview, or terminal mapping apply
|
|
35
|
+
rows as always-visible sections.
|
|
30
36
|
- Terminal delivery remediation lives outside Settings primary flow. The
|
|
31
37
|
supported order is `projmux shell` first, then `projmux setup`, then
|
|
32
38
|
`projmux init` for supported terminal adapters.
|
|
33
39
|
- Rows that cannot safely be edited still stay visible. Mark diagnostic-only
|
|
34
40
|
rows with the delivery path and reason instead of hiding them or turning them
|
|
35
|
-
into unsupported editable
|
|
36
|
-
|
|
41
|
+
into unsupported editable keys. Transport-dependent rows stay visible with
|
|
42
|
+
their default transport key and additive custom-key entry; replacing or
|
|
37
43
|
disabling the transport default is not exposed.
|
|
38
44
|
- `Alt-1..5` are the only guaranteed zero-config launch defaults. `UserN` and
|
|
39
45
|
`CSI-u` are legacy/removal/unsupported targets, not supported fallback
|
|
@@ -42,6 +48,13 @@ view-first layout:
|
|
|
42
48
|
first-class row, action rows use human-readable labels, internal IDs appear
|
|
43
49
|
only in detail/source/keymap contexts, and runtime footers are status hints,
|
|
44
50
|
not key discovery.
|
|
51
|
+
- `Settings > Theme` (Global) is the single theme view. There is no separate
|
|
52
|
+
`Effective theme` item: the Global theme view shows each color token's value
|
|
53
|
+
inline. A token set globally (explicit value or via a global preset) shows its
|
|
54
|
+
set/override/preset summary; an UNSET token shows the resolved fallback value
|
|
55
|
+
with a dim swatch, a `(fallback)` label, and a `fallback` source. Resolver
|
|
56
|
+
warnings render as dim info rows after the token rows. Project `.projmux`
|
|
57
|
+
`[theme]` is never resolved or shown here.
|
|
45
58
|
- `Settings > Notifications` owns notification delivery IA. Desktop notification
|
|
46
59
|
mode, AI desktop notification dedupe duration, delivery source diagnostics,
|
|
47
60
|
AI hook quiet policy, in-app queue status, and
|
|
@@ -64,8 +77,7 @@ view-first layout:
|
|
|
64
77
|
edit catalog `install` values or run agent install/remove commands.
|
|
65
78
|
- `Settings > Session State > Sidebar startup picker` controls the Alt-1
|
|
66
79
|
project-open startup selector. The saved file remains
|
|
67
|
-
`${XDG_CONFIG_HOME:-$HOME/.config}/projmux/sidebar-startup-picker
|
|
68
|
-
stale `labs:sidebar-startup-picker` action opens this Session State detail.
|
|
80
|
+
`${XDG_CONFIG_HOME:-$HOME/.config}/projmux/sidebar-startup-picker`.
|
|
69
81
|
- `Settings > Labs` keeps experimental toggles, but keybindings no longer have a
|
|
70
82
|
visible Labs row. The hidden compatibility action redirects to the
|
|
71
83
|
`Settings > Keybindings` action list, not to a diagnostic default.
|
|
@@ -83,10 +95,6 @@ view-first layout:
|
|
|
83
95
|
and `Notify icon` details. Each detail shows the current mode plus
|
|
84
96
|
immediately selectable off/symbol/emoji preview rows. There is no separate
|
|
85
97
|
`Change` page for icon decoration.
|
|
86
|
-
- `Settings > Appearance` also shows a read-only `Theme font` status row.
|
|
87
|
-
`font_family` and `font_size` are desired values from the effective
|
|
88
|
-
project/global theme, and unsupported terminal paths must say `not applied`
|
|
89
|
-
instead of implying tmux changed the font.
|
|
90
98
|
- `Settings > Appearance > Language / Locale` is the global/user language
|
|
91
99
|
detail. The root row shows the saved `[ui].locale` value and the currently
|
|
92
100
|
effective locale. The detail shows `Current`, `[ui].locale`, optional
|
package/docs/statusbar.md
CHANGED
|
@@ -141,13 +141,35 @@ last collect timestamp when present, falls back to the cache file mtime when
|
|
|
141
141
|
needed, and keeps stale sync metadata muted instead of escalating it to a
|
|
142
142
|
warning color.
|
|
143
143
|
The notification HUD detail surface opens the right-side notification popup
|
|
144
|
-
through the notify sidebar action,
|
|
145
|
-
attention-tinted title. When notification
|
|
146
|
-
`emoji`, the bell appears before the title text.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
render
|
|
150
|
-
|
|
144
|
+
through the notify sidebar action, showing the grouped pane/session inbox with
|
|
145
|
+
collapsed group rows and the same attention-tinted title. When notification
|
|
146
|
+
icon decoration is `symbol` or `emoji`, the bell appears before the title text.
|
|
147
|
+
Foldable group rows show `+N`, where `N` is the number of child notification
|
|
148
|
+
rows shown after Right. One-notification group headers omit the count and do
|
|
149
|
+
not render as strongly foldable. Right/Left show and hide child rows locally
|
|
150
|
+
inside the native sidebar; Right on a childless group refreshes without adding
|
|
151
|
+
rows. Enter on a group row, whether folded or expanded, focuses the group's
|
|
152
|
+
representative pane and acknowledges every visible notification in that group
|
|
153
|
+
only after focus succeeds. Inactive means an `ai:` queue entry no longer
|
|
154
|
+
matches live reply+agent state (its pane still EXISTS in tmux), not that the
|
|
155
|
+
row is old; if the target remains routable, Enter and statusbar clicks still
|
|
156
|
+
focus and then ack. Gone means the target is unroutable (empty session) or the
|
|
157
|
+
row's pane id is absent from the real tmux live pane inventory
|
|
158
|
+
(`tmux list-panes -a`). The inventory check is best-effort: an unreadable or
|
|
159
|
+
empty/unrecognized tmux reply is treated as "unavailable", so a missing tmux
|
|
160
|
+
server never falsely gones routable rows. If the
|
|
161
|
+
representative target is gone/unroutable, Enter cleans up the selected group
|
|
162
|
+
without focusing and acknowledges every visible notification in that group,
|
|
163
|
+
including critical notifications. A
|
|
164
|
+
target-gone focus race follows the same cleanup policy; other focus failures
|
|
165
|
+
keep the group pending and show a clear message before refresh/prune. Enter on
|
|
166
|
+
a child notification preserves the existing focus and ack-one behavior.
|
|
167
|
+
`NotifySidebar:AckGroup` remains the explicit group ack action and acknowledges
|
|
168
|
+
every visible notification in the selected group, including critical
|
|
169
|
+
notifications.
|
|
170
|
+
Internal notify commands use `NotifySidebar:*` IDs in `keymap.toml`; runtime
|
|
171
|
+
footers render key guides from the merged keymap and prefer the default alias
|
|
172
|
+
when it is still configured.
|
|
151
173
|
|
|
152
174
|
Empty `#{mouse_status_range}` (a click on whitespace) falls through to
|
|
153
175
|
`select-window -t @<mouse_window>` when `--mouse-window` is non-empty,
|
|
@@ -180,6 +202,8 @@ them as `display-message` toasts:
|
|
|
180
202
|
|
|
181
203
|
- `notify` click whose focus dispatch exits 2 (target unresolved):
|
|
182
204
|
ack the entry, toast `notify target gone; cleared`.
|
|
205
|
+
- `notify` click whose AI target is inactive because it no longer matches live
|
|
206
|
+
reply+agent state: focus and ack when the target is still routable.
|
|
183
207
|
- Any other focus failure: keep the entry, toast `focus failed:
|
|
184
208
|
<reason>`.
|
|
185
209
|
- `session`, `kube`, or `git` popup launch failure: toast
|
package/docs/testing.md
CHANGED
|
@@ -21,6 +21,10 @@ and humans run the same entrypoints.
|
|
|
21
21
|
`test/e2e/linux-smoke.sh`. It validates a minimal real-tmux workflow:
|
|
22
22
|
sessions, panes, config sourcing, reply-state notify reconciliation, focus
|
|
23
23
|
notify fallback, and status notify rendering.
|
|
24
|
+
- `make deadcode` runs `go tool deadcode` (pinned via the go.mod tool
|
|
25
|
+
directive) over the module and reports unreachable functions, filtering out
|
|
26
|
+
the intentional/MUST-KEEP baseline in `.deadcode-allowlist.txt`; it fails
|
|
27
|
+
only on NEW dead code, and `make fix` runs it after `go fix`.
|
|
24
28
|
|
|
25
29
|
## Docker-Covered Checks
|
|
26
30
|
|
|
@@ -90,7 +94,7 @@ Observe:
|
|
|
90
94
|
|
|
91
95
|
- `Alt-1` opens the project sidebar.
|
|
92
96
|
- `Alt-2` opens the notification sidebar.
|
|
93
|
-
- `Alt-3` opens
|
|
97
|
+
- `Alt-3` opens Recent Windows.
|
|
94
98
|
- `Alt-4` opens the AI split picker.
|
|
95
99
|
- `Alt-5` opens Settings.
|
|
96
100
|
- Pressing the same launch key again closes the popup instead of typing escape
|