projmux 0.6.5 → 0.6.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.
- package/docs/agent-workflow.md +23 -15
- package/docs/ai-agent-shortcuts.md +20 -1
- package/docs/cli.md +109 -44
- package/docs/configuration.md +71 -34
- package/docs/hooks.md +38 -1
- package/docs/install.md +8 -8
- package/docs/keybindings.md +36 -17
- package/docs/native-picker-parity.md +13 -7
- package/docs/notify-queue.md +45 -9
- package/docs/npm-distribution.md +5 -3
- package/docs/session-restore.md +8 -4
- package/docs/settings-ia.md +21 -8
- package/docs/statusbar.md +25 -2
- package/docs/testing.md +125 -0
- package/docs/theme-palette.md +13 -3
- package/docs/upgrading.md +10 -4
- package/docs/usage-tracking.md +42 -13
- package/package.json +7 -7
package/docs/configuration.md
CHANGED
|
@@ -87,16 +87,17 @@ language.
|
|
|
87
87
|
## Keymap File
|
|
88
88
|
|
|
89
89
|
Settings > Keybindings is the normal in-app editor for action keys. It lists
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
`Type key chord`. Saving writes safe tmux plain chords to
|
|
90
|
+
actions with current keybinding summaries, opens a simple detail screen, and
|
|
91
|
+
offers `Add alias` plus reset. Saving writes safe tmux plain chords to
|
|
93
92
|
`~/.config/projmux/keymap.toml`, rewrites `~/.config/projmux/tmux.conf`, and,
|
|
94
93
|
when Settings is running inside tmux, sources that app config so tmux-level
|
|
95
94
|
chords take effect immediately.
|
|
96
95
|
|
|
97
96
|
Raw sequences that cannot be safely represented as a tmux plain chord are not
|
|
98
|
-
persisted. Use Settings to save a safe direct alias
|
|
99
|
-
the
|
|
97
|
+
persisted. Use Settings to save a safe direct alias. When key delivery needs
|
|
98
|
+
terminal-layer remediation, first try the key in `projmux shell`, then run
|
|
99
|
+
`projmux setup` from the raw terminal, then use `projmux init` for supported
|
|
100
|
+
terminal adapters.
|
|
100
101
|
|
|
101
102
|
`~/.config/projmux/keymap.toml` can also be edited by hand. When the file is
|
|
102
103
|
absent, generated tmux config stays on the built-in defaults.
|
|
@@ -126,21 +127,27 @@ do not break. Settings preserves existing prefix entries when rewriting the
|
|
|
126
127
|
file, but does not create new prefix keys, and generated tmux config no longer
|
|
127
128
|
binds the old action prefix chords.
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
Settings > Keybindings names `AISplitPickerToggle` as the AI split popup
|
|
131
|
+
picker toggle. That action opens or closes the picker UI and is separate from
|
|
132
|
+
the direct AI pane actions, `ai-split-right` and `ai-split-down`. The direct
|
|
133
|
+
actions create a new managed AI pane each time they run, leaving existing AI
|
|
134
|
+
panes in place. `right` and `down` choose where the new pane is created.
|
|
135
|
+
|
|
136
|
+
Use an empty `keys` list to disable direct plain aliases for the action when
|
|
137
|
+
editing the file by hand:
|
|
130
138
|
|
|
131
139
|
```toml
|
|
132
140
|
[bindings.ProjectSidebarToggle]
|
|
133
141
|
keys = []
|
|
134
142
|
```
|
|
135
143
|
|
|
136
|
-
In Settings,
|
|
137
|
-
|
|
144
|
+
In Settings, reset removes the saved override and returns to the built-in
|
|
145
|
+
default. Legacy popup IDs such as
|
|
138
146
|
`sessionizer-sidebar` still read, but new writes use canonical toggle names
|
|
139
147
|
such as `ProjectSidebarToggle`, `NotifySidebarToggle`, `SessionPopupToggle`,
|
|
140
148
|
`AISplitPickerToggle`, `SettingsToggle`, and `ProjectSwitcherToggle`. Internal
|
|
141
149
|
popup commands use `Surface:Action` IDs and have surface-local conflict
|
|
142
|
-
domains
|
|
143
|
-
targets.
|
|
150
|
+
domains and remain visible in Settings when catalogued.
|
|
144
151
|
|
|
145
152
|
The Settings writer is deterministic and rewrites the supported saved subset
|
|
146
153
|
only. If the existing file has parse errors or unknown action IDs, Settings
|
|
@@ -149,7 +156,8 @@ shows the keymap error row and refuses to overwrite it until the file is fixed.
|
|
|
149
156
|
The file currently affects generated tmux config from `projmux tmux
|
|
150
157
|
print-config`, `projmux tmux install`, `projmux tmux print-app-config`,
|
|
151
158
|
`projmux tmux install-app`, and `projmux shell`. Terminal init adapters such as
|
|
152
|
-
Ghostty and Windows Terminal install built-in plain-byte mappings where needed
|
|
159
|
+
Ghostty and Windows Terminal install built-in plain-byte mappings where needed;
|
|
160
|
+
they do not read `keymap.toml` or copy saved aliases into terminal configs.
|
|
153
161
|
Changing terminal-layer mappings still requires rerunning `projmux init` and
|
|
154
162
|
restarting the terminal where that terminal requires it.
|
|
155
163
|
|
|
@@ -176,9 +184,18 @@ field with source labels: `project`, `global`, or `fallback`.
|
|
|
176
184
|
Renderer adapters can apply an already resolved `EffectiveTheme` to native
|
|
177
185
|
picker frame background/foreground SGR and tmux status/window `colourN`
|
|
178
186
|
background tokens. Settings and native project picker surfaces load global and
|
|
179
|
-
project `[theme]` values through the shared effective-theme source.
|
|
180
|
-
|
|
181
|
-
|
|
187
|
+
project `[theme]` values through the shared effective-theme source. Native
|
|
188
|
+
picker frames also apply the built-in fallback `background`/`foreground` tokens
|
|
189
|
+
so picker-owned padding, empty rows, footer rows, and preview gaps do not
|
|
190
|
+
inherit the terminal default background.
|
|
191
|
+
|
|
192
|
+
Native picker popups launched through `projmux tmux popup-toggle` also pass a
|
|
193
|
+
per-popup tmux 3.4 `display-popup -s` body style using the effective theme
|
|
194
|
+
`background`/`foreground` tmux tokens. This styles only the tmux popup body
|
|
195
|
+
before the native renderer draws. It does not set global `popup-style` or
|
|
196
|
+
`popup-border-style`, and it does not change shell pane backgrounds,
|
|
197
|
+
`default-style`, `window-style`, OSC terminal backgrounds, or the general
|
|
198
|
+
status/window palette.
|
|
182
199
|
|
|
183
200
|
Resolver schema shape:
|
|
184
201
|
|
|
@@ -270,11 +287,12 @@ user/global preference in this release.
|
|
|
270
287
|
| `PROJMUX_FOCUS_DEBUG` | When non-empty, `projmux focus` prints one telemetry line to stderr. |
|
|
271
288
|
| `PROJMUX_PICKER_BACKEND` | Legacy picker backend override. Any value, including old `fzf` settings, now resolves to the native picker. |
|
|
272
289
|
| `PROJMUX_INSTALLER` | Installer source hint used by update flows. npm installs set this automatically; advanced release installs can set `github-release`. |
|
|
290
|
+
| `PROJMUX_SHELL_UPDATE_CHECK_TIMEOUT_MS` | Timeout in milliseconds for the best-effort release check attempted by `projmux shell` when the update cache is missing or stale. Invalid, zero, or negative values use the default. |
|
|
273
291
|
|
|
274
292
|
## Welcome State
|
|
275
293
|
|
|
276
|
-
`projmux shell`
|
|
277
|
-
directory, normally:
|
|
294
|
+
`projmux shell` still reads and rewrites legacy per-version welcome state under
|
|
295
|
+
the projmux state directory for attach-popup compatibility, normally:
|
|
278
296
|
|
|
279
297
|
```text
|
|
280
298
|
${XDG_STATE_HOME:-$HOME/.local/state}/projmux/welcomed-v<version>.json
|
|
@@ -292,11 +310,21 @@ The current schema is:
|
|
|
292
310
|
}
|
|
293
311
|
```
|
|
294
312
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
313
|
+
This file no longer suppresses the shell-entry welcome. `skip_version` and
|
|
314
|
+
`last_welcomed_version` remain readable for legacy state and pending attach
|
|
315
|
+
popup compatibility, but the automatic shell prompt now uses release skip state
|
|
316
|
+
instead.
|
|
317
|
+
|
|
318
|
+
Update prompt skips are stored by latest release tag under the update cache
|
|
319
|
+
directory:
|
|
320
|
+
|
|
321
|
+
```text
|
|
322
|
+
${XDG_CACHE_HOME:-$HOME/.cache}/projmux/update-skip.json
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
When `tag_name` matches the fresh cached latest release tag, `projmux shell`
|
|
326
|
+
continues without offering the update actions. A newer latest tag makes the
|
|
327
|
+
prompt eligible again.
|
|
300
328
|
|
|
301
329
|
Example:
|
|
302
330
|
|
|
@@ -398,11 +426,13 @@ only a generic in-app queue/sidebar/statusbar row; it does not fire OS toast,
|
|
|
398
426
|
The OS-level dispatch carries three modes. The in-app notify queue, the
|
|
399
427
|
statusbar segment, and the attention badge stay live regardless of which
|
|
400
428
|
mode is active — only the toast / notify-send / auto-raise fan-out is
|
|
401
|
-
gated here.
|
|
429
|
+
gated here. The same mode also gates `projmux focus` post-switch osfocus
|
|
430
|
+
dispatch: only `raise` asks the host terminal to come forward after a
|
|
431
|
+
successful tmux focus.
|
|
402
432
|
|
|
403
433
|
| Mode | On push | On click |
|
|
404
434
|
| --- | --- | --- |
|
|
405
|
-
| `none` | no toast | n/a |
|
|
435
|
+
| `off` / `none` | no toast | n/a |
|
|
406
436
|
| `notify` | toast / notify-send fires | no click action |
|
|
407
437
|
| `raise` | toast / notify-send fires AND the host terminal is auto-raised via the osfocus chain | toast click invokes `projmux focus --uri` via the `projmux://` handler |
|
|
408
438
|
|
|
@@ -410,30 +440,37 @@ Click activation is wired only for `raise`. The `projmux://` URI handler is
|
|
|
410
440
|
registered on the first `raise` Notify of each tmux server (gated by the
|
|
411
441
|
`@projmux_uri_protocol_registered_v6` marker). The
|
|
412
442
|
mode only controls whether a toast fires at all and whether to follow it
|
|
413
|
-
up with an on-push auto-raise.
|
|
443
|
+
up with an on-push auto-raise. `off` / `none` and `notify` also suppress
|
|
444
|
+
the focus-triggered osfocus raise after `projmux focus`.
|
|
414
445
|
|
|
415
446
|
Resolution order (highest priority first):
|
|
416
447
|
|
|
417
|
-
1. `PROJMUX_DESKTOP_NOTIFY_MODE` env (`none` / `notify` / `raise`).
|
|
448
|
+
1. `PROJMUX_DESKTOP_NOTIFY_MODE` env (`off` / `none` / `notify` / `raise`).
|
|
418
449
|
2. `PROJMUX_DESKTOP_NOTIFY` env (legacy `on` / `off`; `on` → `notify`,
|
|
419
450
|
`off` → `none`).
|
|
420
|
-
3.
|
|
421
|
-
|
|
451
|
+
3. Saved Settings config
|
|
452
|
+
`${XDG_CONFIG_HOME:-$HOME/.config}/projmux/desktop-notify-mode`
|
|
453
|
+
(`off` / `notify` / `raise`).
|
|
454
|
+
4. Tmux global option `@projmux_desktop_notify_mode`.
|
|
455
|
+
5. Tmux global option `@projmux_desktop_notify` (legacy `1` / `0`, same
|
|
422
456
|
mapping as the env above).
|
|
423
|
-
|
|
457
|
+
6. Default = `raise` when running inside WSL with `$WT_SESSION` set
|
|
424
458
|
(Windows Terminal × WSL is the measured-working cell for osfocus
|
|
425
459
|
raise today); otherwise `notify`.
|
|
426
460
|
|
|
427
461
|
Migration is intentionally read-time. Users with the previous legacy
|
|
428
462
|
toggle set keep their behavior — `@projmux_desktop_notify=0` resolves to
|
|
429
463
|
`none`, `@projmux_desktop_notify=1` resolves to `notify`. The first
|
|
430
|
-
Settings press through the new row writes
|
|
431
|
-
|
|
464
|
+
Settings press through the new row writes `desktop-notify-mode`, mirrors the
|
|
465
|
+
new value into `@projmux_desktop_notify_mode` when tmux is live, and leaves the
|
|
466
|
+
legacy key unused. No eager rewrite of tmux state.
|
|
432
467
|
|
|
433
468
|
Toggle from Settings > Notifications > `Desktop notifications`. The
|
|
434
469
|
Settings info row labels the effective source as `env`, `env (legacy)`,
|
|
435
470
|
`setting`, `setting (legacy)`, or `default` so users see which rung of
|
|
436
|
-
the cascade pinned the value.
|
|
471
|
+
the cascade pinned the value. `projmux tmux apply` regenerates the live tmux
|
|
472
|
+
option from the saved Settings file; when that file is missing, apply writes
|
|
473
|
+
only the default for the current host.
|
|
437
474
|
|
|
438
475
|
Hook details for new-session lifecycle hooks and project-local
|
|
439
476
|
`.projmux/config.toml` live in [Hooks](hooks.md).
|
|
@@ -542,8 +579,8 @@ while `on` and `off` take precedence. Auto-save only updates the latest
|
|
|
542
579
|
snapshot. Named snapshots are manual and are never updated by auto-save.
|
|
543
580
|
|
|
544
581
|
Project open from the Alt-1 sidebar defaults to opening a closed project as an
|
|
545
|
-
`Empty session`. The optional `Settings >
|
|
546
|
-
enables the native sidebar `Start project` step. Rows appear as `Latest
|
|
582
|
+
`Empty session`. The optional `Settings > Session State > Sidebar startup
|
|
583
|
+
picker` toggle enables the native sidebar `Start project` step. Rows appear as `Latest
|
|
547
584
|
snapshot`, named snapshot rows, `Empty session`, and `Back`. `Latest snapshot`
|
|
548
585
|
is the snapshot auto-save that changes as auto-save runs; named snapshots are
|
|
549
586
|
fixed snapshots. Rows include saved-at date/time metadata when projmux can
|
|
@@ -562,7 +599,7 @@ Default `projmux shell` no longer opens a startup picker or replays session-stat
|
|
|
562
599
|
snapshots before attach. It still derives the default app session identity and
|
|
563
600
|
startup directory from the current project context when available; otherwise it
|
|
564
601
|
uses the `home` target and home directory. Session-state restore selection is
|
|
565
|
-
limited to the
|
|
602
|
+
limited to the Session State sidebar startup picker.
|
|
566
603
|
|
|
567
604
|
Settings > Session State is global settings only: global auto-save, auto-save
|
|
568
605
|
interval, and storage/retention policy. Settings > Project > Session State
|
package/docs/hooks.md
CHANGED
|
@@ -206,7 +206,11 @@ desktop sender and receives positional arguments
|
|
|
206
206
|
`summary body urgency app-name tag group icon-path`. That `urgency` value is
|
|
207
207
|
the OS notification urgency, not the notify-queue severity. AI approval,
|
|
208
208
|
input, selection, and confirmation rows can stay critical in the queue and UI
|
|
209
|
-
while the desktop notification hook receives `normal`.
|
|
209
|
+
while the desktop notification hook receives `normal`. Live AI status badges
|
|
210
|
+
are a third surface: permission/input-required panes use the action-required
|
|
211
|
+
amber-orange status role, response-complete panes use success green, and
|
|
212
|
+
in-progress panes use progress yellow. They do not inherit the critical queue
|
|
213
|
+
severity, and permission/input status badges do not use red.
|
|
210
214
|
|
|
211
215
|
## Codex Hooks Engine
|
|
212
216
|
|
|
@@ -602,6 +606,39 @@ Codex and are managed from `Settings > Notifications > Hook quiet policy`.
|
|
|
602
606
|
They only affect ingest delivery; `projmux ai integrate claude` still uses the
|
|
603
607
|
catalog `install` field for installed hook events.
|
|
604
608
|
|
|
609
|
+
## Antigravity Hook Ingest
|
|
610
|
+
|
|
611
|
+
`projmux ai ingest antigravity-hook < payload.json` is available for manual
|
|
612
|
+
Antigravity CLI `agy` hook/statusline payloads. Projmux does not provide
|
|
613
|
+
`projmux ai integrate antigravity`, does not install Antigravity hooks, and
|
|
614
|
+
does not mutate Antigravity user config. The Delivery sources diagnostic
|
|
615
|
+
therefore reports Antigravity as a read-only unsupported/manual row. If users
|
|
616
|
+
wire it by hand, use an absolute `projmux` command path or a known cwd because
|
|
617
|
+
relative command paths failed the Phase 0b smoke.
|
|
618
|
+
|
|
619
|
+
The default known Antigravity catalog records only observed Phase 0b signals
|
|
620
|
+
and marks them `install: false`:
|
|
621
|
+
|
|
622
|
+
| Event/signal | Behavior |
|
|
623
|
+
| --- | --- |
|
|
624
|
+
| `PostInvocation` | marks the matched pane hook-active and writes a quiet ingest diagnostic; no notify queue entry is pushed |
|
|
625
|
+
| `Stop` | pushes a completion row, or a critical error row when `error` is present or `terminationReason` is non-normal |
|
|
626
|
+
| `Statusline` with `tool_confirmation_pending=true` | pushes a critical approval row; this is only active when a statusline/manual status payload is wired to ingest |
|
|
627
|
+
| `Statusline` without `tool_confirmation_pending=true` | marks the matched pane hook-active and writes a quiet ingest diagnostic |
|
|
628
|
+
| unknown events | mark the matched pane hook-active and write quiet ingest diagnostics only |
|
|
629
|
+
|
|
630
|
+
Antigravity notify rows use `agent=antigravity` metadata. Accepted fields
|
|
631
|
+
include `conversationId`/`conversation_id`, `cwd`, `workspace.path`,
|
|
632
|
+
`transcriptPath`, `terminationReason`, `error`, `fullyIdle`, `agent_state`,
|
|
633
|
+
`context_window`, and nested `statusline.tool_confirmation_pending`.
|
|
634
|
+
Antigravity ingest uses `conversationId` as pane thread metadata for matching
|
|
635
|
+
and as session-state resume metadata. Session restore uses
|
|
636
|
+
`agy --conversation <uuid>` only when that id is present and UUID-shaped;
|
|
637
|
+
otherwise preview and doctor render `resume unavailable`. Antigravity usage
|
|
638
|
+
quota HUD support remains unsupported because the stable usage signal is
|
|
639
|
+
`context-window-only` statusline data, not 5-hour/weekly quota data. Raw
|
|
640
|
+
payloads or transcript contents are not stored.
|
|
641
|
+
|
|
605
642
|
## Ingest Debug Log
|
|
606
643
|
|
|
607
644
|
Every `projmux ai ingest ...` path appends compact JSONL diagnostics to
|
package/docs/install.md
CHANGED
|
@@ -28,14 +28,14 @@ projmux shell
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Each `projmux shell` launch prints a short welcome with the current version,
|
|
31
|
-
detach/exit keys,
|
|
32
|
-
Press Enter to continue
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
detach/exit keys, a bootstrap reminder, and cached release status when
|
|
32
|
+
available. Press Enter to continue into the shell.
|
|
33
|
+
|
|
34
|
+
If an update is available, the same shell-entry prompt uses one action
|
|
35
|
+
vocabulary: Enter continues, `u` upgrades by invoking `projmux update apply`,
|
|
36
|
+
and `s` skips that latest release tag until a newer tag appears. For `source`
|
|
37
|
+
or unknown installer sources, `u` prints installer guidance and then continues
|
|
38
|
+
shell entry.
|
|
39
39
|
|
|
40
40
|
To revisit the guide later, run `projmux welcome`, or use Settings > About >
|
|
41
41
|
Welcome inside the app to open it in a visible viewer. Set `PROJMUX_WELCOME=off` before
|
package/docs/keybindings.md
CHANGED
|
@@ -12,8 +12,7 @@ supported fallback guidance.
|
|
|
12
12
|
The recommended path when a key does not fire:
|
|
13
13
|
|
|
14
14
|
1. Try the key inside `projmux shell`.
|
|
15
|
-
2.
|
|
16
|
-
tmux, to see which bytes reach the process.
|
|
15
|
+
2. Run `projmux setup` outside tmux to see which bytes reach the process.
|
|
17
16
|
3. For supported terminals, preview `projmux init [terminal]`; add `--apply`
|
|
18
17
|
only after reviewing the merge.
|
|
19
18
|
4. For unsupported terminals, configure plain Meta bytes or add a tmux alias in
|
|
@@ -34,7 +33,7 @@ These shortcuts are the guaranteed launch defaults. They need no tmux prefix.
|
|
|
34
33
|
| `Alt-1` | Project sidebar |
|
|
35
34
|
| `Alt-2` | Notify sidebar |
|
|
36
35
|
| `Alt-3` | Existing session popup |
|
|
37
|
-
| `Alt-4` | AI split picker |
|
|
36
|
+
| `Alt-4` | AI split popup picker |
|
|
38
37
|
| `Alt-5` | Settings |
|
|
39
38
|
|
|
40
39
|
The tmux prefix remains the upstream default `Ctrl-b`. Inside a running
|
|
@@ -47,14 +46,31 @@ keymap actions, pane switching, window switching, and rename actions remain
|
|
|
47
46
|
visible. Transport-dependent rows show the default transport key separately
|
|
48
47
|
from editable plain aliases.
|
|
49
48
|
|
|
49
|
+
The Settings flow is intentionally simple: the root is one action list with
|
|
50
|
+
current key summaries, and each action detail shows the action, current
|
|
51
|
+
keybinding/aliases, `Add alias`, and reset. Diagnostic/probe/init workflows are
|
|
52
|
+
not first-class Settings tabs; use `projmux setup` and `projmux init` from the
|
|
53
|
+
terminal when key delivery needs remediation.
|
|
54
|
+
|
|
50
55
|
Optional direct aliases can be added for actions such as:
|
|
51
56
|
|
|
52
57
|
| Canonical action | Meaning |
|
|
53
58
|
| --- | --- |
|
|
54
59
|
| `ProjectSwitcherToggle` | Project switcher popup |
|
|
60
|
+
| `AISplitPickerToggle` | AI split popup picker; pressing again closes the picker popup |
|
|
61
|
+
| `ai-split-right` | Open a new direct AI split to the right |
|
|
62
|
+
| `ai-split-down` | Open a new direct AI split below |
|
|
55
63
|
| `new-window` | New tmux window in the current pane directory |
|
|
56
64
|
| `rename-window` | Rename the current tmux window |
|
|
57
65
|
|
|
66
|
+
`AISplitPickerToggle` is the `Alt-4` popup picker toggle. It opens or closes
|
|
67
|
+
the picker UI where the user chooses the AI split mode. It is separate from
|
|
68
|
+
the direct `ai-split-right` and `ai-split-down` actions.
|
|
69
|
+
|
|
70
|
+
The direct AI split actions create a new managed AI pane each time they run.
|
|
71
|
+
Existing AI panes are left in place; the requested direction controls where the
|
|
72
|
+
new pane is created.
|
|
73
|
+
|
|
58
74
|
Pane switching is catalogued as transport-dependent and the generated app tmux
|
|
59
75
|
config binds `M-Left`, `M-Right`, `M-Up`, and `M-Down` to `select-pane`
|
|
60
76
|
movement. Previous/next window remain transport-dependent and the generated app
|
|
@@ -67,19 +83,20 @@ without storing or replacing the transport default. Rename actions no longer
|
|
|
67
83
|
have a built-in terminal fallback; use tmux's prefix rename flow or configure
|
|
68
84
|
an explicit safe alias where the action is editable.
|
|
69
85
|
|
|
70
|
-
##
|
|
86
|
+
## Product Requirements
|
|
71
87
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
88
|
+
Settings > Keybindings stays a discovery surface. It must continue to expose
|
|
89
|
+
launch toggles, sidebar keymap actions, picker-local actions, pane switching,
|
|
90
|
+
window switching, and rename actions. The primary Settings flow is not the
|
|
91
|
+
terminal remediation surface: replace-primary, disable-default, typed fallback,
|
|
92
|
+
terminal mapping preview/apply, and init execution rows stay out of the action
|
|
93
|
+
detail.
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
Windows Terminal and Ghostty-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
95
|
+
The product model does not support `UserN` or `CSI-u` as fallback guidance.
|
|
96
|
+
Windows Terminal and Ghostty adapters use built-in plain Meta/control bytes or
|
|
97
|
+
xterm modifier sequences where possible. If a key cannot be represented that
|
|
98
|
+
way, leave it as a non-editable unsupported or diagnostic row instead of
|
|
99
|
+
preserving a User-key or CSI-u fallback.
|
|
83
100
|
|
|
84
101
|
## Picker Actions
|
|
85
102
|
|
|
@@ -126,13 +143,15 @@ Legacy popup IDs such as `sessionizer-sidebar`, `notify-sidebar`,
|
|
|
126
143
|
`session-popup`, `ai-split-picker-right`, `ai-split-settings`, and
|
|
127
144
|
`sessionizer` still read. Settings and new docs show the canonical toggle
|
|
128
145
|
names: `ProjectSidebarToggle`, `NotifySidebarToggle`, `SessionPopupToggle`,
|
|
129
|
-
`AISplitPickerToggle`, `SettingsToggle`, and `ProjectSwitcherToggle`.
|
|
146
|
+
`AISplitPickerToggle`, `SettingsToggle`, and `ProjectSwitcherToggle`. Direct
|
|
147
|
+
AI split actions keep their command IDs, `ai-split-right` and `ai-split-down`,
|
|
148
|
+
so Settings can distinguish them from the `Alt-4` popup picker toggle.
|
|
130
149
|
|
|
131
150
|
## Diagnose: `projmux setup`
|
|
132
151
|
|
|
133
152
|
Run `projmux setup` outside tmux to find out which projmux keys reach the raw
|
|
134
|
-
terminal.
|
|
135
|
-
|
|
153
|
+
terminal. Settings > Keybindings remains the action/alias editor; setup is the
|
|
154
|
+
terminal delivery diagnostic.
|
|
136
155
|
|
|
137
156
|
| Status | Meaning |
|
|
138
157
|
| --- | --- |
|
|
@@ -32,6 +32,7 @@ native picker engine and is not a public dependency-policy change.
|
|
|
32
32
|
| close `--bind key:abort` | Esc, Ctrl-C, Alt-N, Ctrl-Alt-S variants | Covered | `CloseActions`; `TestNativeRunnerUsesSharedCloseActions` |
|
|
33
33
|
| terminal modified-key encoding | legacy parser fixtures, Ghostty/kitty-style modified keys | Covered | native handles app-specific parser fixtures, generic modified letters/digits, and non-text keys such as Enter/Esc/Backspace/Tab; this is backend parity, not product fallback guidance; `TestNativeInteractiveSupportsCSIuAppKeyBindings` |
|
|
34
34
|
| `execute-silent(...)+refresh-preview` | switch/session preview cycling | Covered for command execution and rerender loop | `pickercompat.PickerOptions`/`pickercompat.OptionsFromPicker`; `TestNativeInteractiveRunsCustomActionCommandAndRefreshes`; `TestPickerOptionsMapsCompatBindingsToContractActions`; Docker no-fzf e2e sends `Right` and `Alt-Down` before selection |
|
|
35
|
+
| action-local/event-backed mutable refresh | notify sidebar `a` ack and `x` non-critical clear; notify sidebar queue-write event refresh; switch sidebar `Ctrl-X` kill | Covered for in-session row/live-state refresh without picker restart | `picker.Action.Mutate` returns a `DeferredUpdate`, notify queue-write events trigger the same `DeferredUpdate` path after an event arrives, and both reuse the native frame diff renderer plus value-then-clamp selection preservation; `TestNativeInteractiveCustomActionMutatesItemsAndRefreshes`; `TestNativeInteractiveCustomActionRefreshPreservesSelectedValue`; `TestNativeInteractiveDeferredUpdateTriggerRefreshesRepeatedly`; notify sidebar app tests assert one picker invocation with refreshed rows/live state and event subscription; switch sidebar kill app tests assert one native picker invocation with refreshed rows/preview and previous-live-session guard preservation |
|
|
35
36
|
| `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
37
|
| `start:pos(N)` | switch sidebar initial row | Covered | `pickercompat.PickerOptions`/`pickercompat.OptionsFromPicker`; `TestPickerOptionsFromCompatPickerMapsStartPosToInitialIndex`; `TestPickerOptionsMapsCompatBindingsToContractActions` |
|
|
37
38
|
| `--preview` | switch, sessions | Covered by command output | `nativePreviewLines`; `TestNativeInteractiveRendersSelectedPreview` |
|
|
@@ -46,8 +47,9 @@ native picker engine and is not a public dependency-policy change.
|
|
|
46
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` |
|
|
47
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` |
|
|
48
49
|
| frame content width | fzf border inner width | Covered | `ContentLayout` uses the frame inner width so separators and rows reach the right border; `TestRendererContentLayoutUsesFrameInnerWidth` |
|
|
49
|
-
|
|
|
50
|
-
|
|
|
50
|
+
| picker-owned app background | native picker frame interior | Covered for renderer-owned cells | `ThemeFromEffective` applies built-in fallback and explicit effective background/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`/`fg` from the same effective theme tmux background/foreground tokens 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 background/foreground instead of a separate titlebar overlay ANSI layer, and the native Alt-1 project sidebar opts into `Projects`; `TestRendererRenderFrameWithTitleKeepsDefaultWhenTitleEmpty`; `TestRendererRenderFrameWithTitleUsesTitlebarRow`; `TestRendererContentLayoutWithTitleReservesTitlebarRow`; `TestNativeInteractiveRendersOptionalTitlebar`; `TestSwitchCommandNativeSidebarSetsTitle` |
|
|
51
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` |
|
|
52
54
|
|
|
53
55
|
## Native Surface Architecture
|
|
@@ -72,9 +74,11 @@ native picker engine and is not a public dependency-policy change.
|
|
|
72
74
|
## Frame Chrome ANSI
|
|
73
75
|
|
|
74
76
|
Native picker frame chrome is normalized in `internal/ui/projmuxpicker`.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
Titlebar text, title dividers, and chip-strip gaps inherit the frame
|
|
78
|
+
background/foreground instead of applying a second titlebar overlay ANSI layer;
|
|
79
|
+
chip bodies can still carry active/inactive/disabled tones. Search prompt and
|
|
80
|
+
footer separators fill the available frame width, and header, row, footer, and
|
|
81
|
+
preview lines close any active SGR style before padding or frame borders can
|
|
78
82
|
inherit it. This phase does not add popup modes or change the `popup-toggle`
|
|
79
83
|
contract; native popups still rely on the existing borderless tmux popup path.
|
|
80
84
|
|
|
@@ -107,8 +111,10 @@ contract; native popups still rely on the existing borderless tmux popup path.
|
|
|
107
111
|
the right-side preview layout instead of inline preview, asserts the stored
|
|
108
112
|
preview cursor, selects `bravo-web`, and asserts tmux reports the selected
|
|
109
113
|
session's active target on the expected window with the expected pane path.
|
|
110
|
-
- `notify sidebar`: native routing is unit-covered;
|
|
111
|
-
|
|
114
|
+
- `notify sidebar`: native routing is unit-covered; app tests cover
|
|
115
|
+
queue-write event subscription and picker tests cover repeated
|
|
116
|
+
event-triggered deferred refresh. Docker no-fzf e2e pushes a notification,
|
|
117
|
+
presses printable expect key `a`, and verifies the row is acked.
|
|
112
118
|
|
|
113
119
|
## Experimental Boundaries
|
|
114
120
|
|
package/docs/notify-queue.md
CHANGED
|
@@ -13,6 +13,7 @@ via `projmux focus`, and feeds the HUD pill rendered by
|
|
|
13
13
|
```
|
|
14
14
|
${XDG_STATE_HOME:-$HOME/.local/state}/projmux/notify.json
|
|
15
15
|
${XDG_STATE_HOME:-$HOME/.local/state}/projmux/notify.json.lock
|
|
16
|
+
${XDG_STATE_HOME:-$HOME/.local/state}/projmux/notify-queue-events/refresh-*.sock
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
The lock file is acquired via `O_CREATE|O_EXCL` with bounded retry
|
|
@@ -24,6 +25,13 @@ The queue file is a pretty-printed JSON array of `Notification`
|
|
|
24
25
|
objects, sorted newest-first on read. `expires_at` is freshness metadata;
|
|
25
26
|
expired entries are not filtered or deleted by `list`.
|
|
26
27
|
|
|
28
|
+
Open native notify sidebars also create per-process Unix datagram sockets for
|
|
29
|
+
queue-write refresh events. If the state-dir socket path would exceed Unix
|
|
30
|
+
socket path limits, projmux uses a short per-state-dir temp runtime path for
|
|
31
|
+
the socket directory. These sockets are transient UI delivery endpoints only:
|
|
32
|
+
they are not queue state, do not change the JSON schema, and are removed when
|
|
33
|
+
the sidebar exits.
|
|
34
|
+
|
|
27
35
|
## Data model
|
|
28
36
|
|
|
29
37
|
`internal/core/notify`:
|
|
@@ -58,11 +66,17 @@ exit code 2.
|
|
|
58
66
|
routing/debug context such as `agent`, `thread_id`, `turn_id`, `cwd`,
|
|
59
67
|
`model`, and `client`; Claude hook rows also carry event-specific keys such as
|
|
60
68
|
`tool_name`, `tool_input.command`, `error_type`, `subagent_type`, and
|
|
61
|
-
`teammate_name`.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
`teammate_name`. Antigravity manual hook rows carry `agent=antigravity`,
|
|
70
|
+
`conversation_id`, `termination_reason`, `fully_idle`,
|
|
71
|
+
`tool_confirmation_pending`, `agent_state`, and `context_window` when present.
|
|
72
|
+
The same `conversation_id` can seed session-state restore via
|
|
73
|
+
`agy --conversation <uuid>` when it is UUID-shaped; Antigravity quota usage
|
|
74
|
+
remains unsupported because `context_window` is not 5-hour/weekly quota data.
|
|
75
|
+
Tmux bell fallback rows carry `agent=bell`, `event=bell`, and tmux target
|
|
76
|
+
context such as pane title, command, session, window, pane, and socket.
|
|
77
|
+
`notify list --json` includes this metadata as the structured data channel
|
|
78
|
+
while human table/sidebar output keeps the compact text body. Existing entries
|
|
79
|
+
without metadata remain valid.
|
|
66
80
|
|
|
67
81
|
## CLI surface
|
|
68
82
|
|
|
@@ -100,11 +114,22 @@ pane and acks the row after focus succeeds. The surface actions
|
|
|
100
114
|
are edited in Settings, while internal picker aliases are adjusted in
|
|
101
115
|
`keymap.toml` when needed. Runtime footer key guides read the merged keymap
|
|
102
116
|
and show the default alias when present, otherwise the first configured alias,
|
|
103
|
-
so custom aliases do not make the UI stale.
|
|
117
|
+
so custom aliases do not make the UI stale. `NotifySidebar:Ack` and
|
|
118
|
+
`NotifySidebar:ClearNonCritical` refresh rows, live state, and selection inside
|
|
119
|
+
the same native picker session; `NotifySidebar:ClearAll` still closes the
|
|
120
|
+
popup and prints a summary. Rows are intentionally compact: the visible label keeps
|
|
104
121
|
notification text first, then age, project, window, and pane metadata; hidden
|
|
105
122
|
queue ids remain action values but the sidebar has no search input and
|
|
106
123
|
intentionally does not expose a separate metadata detail view.
|
|
107
124
|
|
|
125
|
+
When a new pending notification is successfully pushed by any app producer
|
|
126
|
+
(`notify push`, reply-ready, reconcile backfill, or bell fallback), open native
|
|
127
|
+
notify sidebars receive a best-effort queue-write event and rerun the same
|
|
128
|
+
`DeferredUpdate` row/live-state refresh path used by `a` ack and `x`
|
|
129
|
+
non-critical clear. Event delivery errors are ignored after the queue write:
|
|
130
|
+
the push still succeeds, and reopening the sidebar remains the recovery path
|
|
131
|
+
for seeing the latest queue.
|
|
132
|
+
|
|
108
133
|
`--live` adds a non-mutating explanation view that reads
|
|
109
134
|
`tmux list-panes -a` and compares the queue with live reply-state panes. It
|
|
110
135
|
does not push, ack, or otherwise repair anything. Human output keeps the
|
|
@@ -153,6 +178,9 @@ path), then:
|
|
|
153
178
|
- reports every existing queue entry whose id starts with `ai:` and whose
|
|
154
179
|
pane no longer matches that condition as stale, without acking it.
|
|
155
180
|
|
|
181
|
+
Successful backfill pushes publish the same best-effort open-sidebar refresh
|
|
182
|
+
event as other pending queue additions.
|
|
183
|
+
|
|
156
184
|
Soft-fails when tmux is not running (returns a populated `errors`
|
|
157
185
|
field rather than a non-zero exit) so the post-install hook does not
|
|
158
186
|
break. Run this as the recovery path when the on-disk queue has drifted
|
|
@@ -180,7 +208,10 @@ an entry with:
|
|
|
180
208
|
When the pane leaves the reply state (manual `attention clear`,
|
|
181
209
|
`status set idle`, or a window close), `AckReplyReady` intentionally does not
|
|
182
210
|
remove the entry. The user consumes it through explicit ack. Store errors are
|
|
183
|
-
swallowed so the live tmux UI never blocks on disk IO.
|
|
211
|
+
swallowed so the live tmux UI never blocks on disk IO. After a successful
|
|
212
|
+
queue write and same-pane non-critical compaction, the producer publishes the
|
|
213
|
+
same best-effort notify-sidebar queue-write refresh event used by
|
|
214
|
+
`projmux notify push`.
|
|
184
215
|
|
|
185
216
|
Manual `projmux attention toggle` on a pane without an agent option
|
|
186
217
|
does NOT push — the queue is intentionally AI-driven; reconcile honours
|
|
@@ -200,7 +231,9 @@ tmux and writes an info/source-ai row with:
|
|
|
200
231
|
Unlike reply-ready reconcile, bell ingest does not require AI pane metadata.
|
|
201
232
|
It is intentionally available for arbitrary CLIs that only signal attention
|
|
202
233
|
through BEL or OSC 9. Repeated bells from the same pane are suppressed for 5
|
|
203
|
-
seconds before a later bell refreshes the stable queue id.
|
|
234
|
+
seconds before a later bell refreshes the stable queue id. Successful
|
|
235
|
+
non-deduped bell queue writes publish the same best-effort open-sidebar
|
|
236
|
+
refresh event as other pending queue additions.
|
|
204
237
|
|
|
205
238
|
## Consumer (status-bar click)
|
|
206
239
|
|
|
@@ -230,8 +263,11 @@ Outcomes:
|
|
|
230
263
|
|
|
231
264
|
The same consume policy is shared by notify-sidebar Enter and OS
|
|
232
265
|
click-to-focus Toast callbacks after a real tmux focus dispatch succeeds.
|
|
266
|
+
OS Toast click-to-focus is only registered when Desktop notification mode is
|
|
267
|
+
`raise`; the in-app sidebar/statusbar consume path works in every mode.
|
|
233
268
|
Pane focus hooks and attention clear paths remain live-attention-only and do
|
|
234
|
-
not ack the notify queue
|
|
269
|
+
not ack the notify queue; their response-complete badge consume is limited to
|
|
270
|
+
live tmux pane badge/state options. Non-critical AI completion producers also compact
|
|
235
271
|
older same-pane non-critical AI rows after replacing/pushing their latest row,
|
|
236
272
|
so reply-ready/stop/bell-style completion rows stay latest-state centered
|
|
237
273
|
without changing the queue schema or TTL contract.
|
package/docs/npm-distribution.md
CHANGED
|
@@ -31,13 +31,15 @@ make npm-pack
|
|
|
31
31
|
or:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
scripts/package-npm.sh --version
|
|
34
|
+
scripts/package-npm.sh --version 1.2.3 --out /tmp/projmux-npm --pack
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
The script stages package directories under `dist/npm` by default. It builds
|
|
38
38
|
the Go binary for each supported platform, copies package metadata and docs,
|
|
39
|
-
updates package versions in the staged copies,
|
|
40
|
-
|
|
39
|
+
updates package versions in the staged copies, generates root
|
|
40
|
+
`optionalDependencies` for the supported platform packages using the same
|
|
41
|
+
version, verifies the staged metadata is internally consistent, then runs
|
|
42
|
+
`npm pack --dry-run` when `--pack` is set.
|
|
41
43
|
|
|
42
44
|
## Publish Order
|
|
43
45
|
|
package/docs/session-restore.md
CHANGED
|
@@ -51,8 +51,12 @@ CLI for inspection/actions.
|
|
|
51
51
|
Agent restore direct-starts supported resume commands when creating fresh tmux
|
|
52
52
|
panes, matching the `projmux ai split` wrapper shape: the wrapper prepends the
|
|
53
53
|
agent binary directory to `PATH`, changes to the saved cwd, sets the terminal
|
|
54
|
-
and tmux pane title from the saved agent topic, then execs `codex resume <id
|
|
55
|
-
|
|
54
|
+
and tmux pane title from the saved agent topic, then execs `codex resume <id>`,
|
|
55
|
+
`claude --resume <id>`, or `agy --conversation <uuid>`. Antigravity restore
|
|
56
|
+
uses only the stable statusline `conversation_id` or hook `conversationId`
|
|
57
|
+
metadata captured as the pane resume id; missing or non-UUID Antigravity ids
|
|
58
|
+
render as `resume unavailable` rather than falling back silently to a shell
|
|
59
|
+
recipe. This avoids typing agent resumes with
|
|
56
60
|
`tmux send-keys`. The restore wrapper is still a non-interactive shell command
|
|
57
61
|
tail, so it does not replay the original pane's interactive shell startup,
|
|
58
62
|
environment, shell functions, aliases, or live process state. Startup recipes
|
|
@@ -74,7 +78,7 @@ when building `Named snapshot` candidates; new primary surfaces should describe
|
|
|
74
78
|
the restore unit as a snapshot, not as a separate layout or preset feature.
|
|
75
79
|
|
|
76
80
|
Project open from the Alt-1 sidebar defaults to opening a closed project as an
|
|
77
|
-
`Empty session`. `Settings >
|
|
81
|
+
`Empty session`. `Settings > Session State > Sidebar startup picker` is an opt-in toggle;
|
|
78
82
|
when it is on, closed project open advances inside the sidebar to the native
|
|
79
83
|
`Start project` step. Rows are ordered `Latest snapshot`, named snapshot rows,
|
|
80
84
|
`Empty session`, then `Back`. `Latest snapshot` is the auto-saved snapshot that
|
|
@@ -98,5 +102,5 @@ directly without a startup picker or trust gate.
|
|
|
98
102
|
Default `projmux shell` no longer opens a compatibility startup picker and no
|
|
99
103
|
longer accepts startup selector flags for session-state restore. It always
|
|
100
104
|
follows the normal empty attach path after resolving the target app session name
|
|
101
|
-
and startup directory. Use `Settings >
|
|
105
|
+
and startup directory. Use `Settings > Session State > Sidebar startup picker` for
|
|
102
106
|
interactive Latest snapshot / Named snapshot / Empty session selection.
|