projmux 0.6.3 → 0.6.5

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.
@@ -11,6 +11,16 @@ projmux session-state restore --dry-run [--session <name>]
11
11
  projmux session-state delete [--session <name>]
12
12
  ```
13
13
 
14
+ Snapshots preserve source metadata, not a final display label. Window records
15
+ keep `window_name`; pane records keep `pane_title`, recipe fields, AI topic
16
+ metadata (`@projmux_ai_topic`), and resume metadata when available. There is no
17
+ `display_label` field in the snapshot schema. After restore, pane borders and
18
+ app window tabs are display-time tmux policy: the app config derives both from
19
+ the active pane's visible label expression, while raw shell or terminal titles
20
+ remain metadata that may change independently. Branch names continue to appear
21
+ in the statusbar git segment; branch-based shell title overwrites are not the
22
+ canonical Projmux window naming source.
23
+
14
24
  The primary inspection surface is `Projects > Sessions > State`. It shows a
15
25
  read-only overview first: latest snapshot status, named snapshots, window ->
16
26
  pane structure, cwd, recipe, and agent resume health. Mutation belongs one
@@ -74,7 +84,16 @@ metadata when available. `Back` returns to the project list without creating,
74
84
  replaying, or opening a session. After the startup mode is selected, project
75
85
  hook/config trust is evaluated if needed; approval continues the selected path
76
86
  and deny/cancel aborts before session create, snapshot replay, or startup
77
- command. Existing sessions switch directly without a startup picker.
87
+ command. The Alt-1 sidebar does not render trust approve/deny rows inline:
88
+ before trust is requested, projmux snapshots the sidebar query/selection
89
+ context and hands the selected open continuation to a detached tmux job. That
90
+ job closes the sidebar popup state for the client and opens the shared `Trust
91
+ project hooks` popup as a client-scoped decision surface, so no code relies on
92
+ the self-closing sidebar popup process continuing after `display-popup -C`.
93
+ Deny/cancel or trust-popup errors return to the sidebar near the same
94
+ query/selection with a visible status message; only a missing/invalid context
95
+ may fall back to a closed popup plus tmux message. Existing sessions switch
96
+ directly without a startup picker or trust gate.
78
97
 
79
98
  Default `projmux shell` no longer opens a compatibility startup picker and no
80
99
  longer accepts startup selector flags for session-state restore. It always
@@ -17,6 +17,23 @@ view-first layout:
17
17
  first, then the edit actions, then the explanatory hints.
18
18
  - `Settings > Keybindings` is the single entry point for keybinding work. The
19
19
  page is split into four chips: `Bindings`, `Diagnostic`, `Probe`, and `Init`.
20
+ - `Settings > Keybindings > Bindings` is a keybinding discovery surface, not
21
+ only a launch-toggle editor. It must show `Toggle Project Sidebar` with the
22
+ guaranteed `Alt-1` / `M-1` default, plus sidebar-local commands, picker-local
23
+ commands, `Pane navigation`, `Window navigation`, and `Rename` groups or
24
+ equivalent searchable rows.
25
+ - Rows that cannot safely be edited still stay visible. Mark diagnostic-only
26
+ rows with the delivery path and reason instead of hiding them or turning them
27
+ into unsupported editable aliases. Transport-dependent rows stay visible with
28
+ a separate default transport key and additive plain-alias entry; replacing or
29
+ disabling the transport default is not exposed.
30
+ - `Alt-1..5` are the only guaranteed zero-config launch defaults. `UserN` and
31
+ `CSI-u` are legacy/removal/unsupported targets, not supported fallback
32
+ guidance for Settings, setup, init, or docs.
33
+ - The launcher checkout policy applies in Settings: the project sidebar is a
34
+ first-class row, action rows use human-readable labels, internal IDs appear
35
+ only in detail/source/keymap contexts, and runtime footers are status hints,
36
+ not key discovery.
20
37
  - `Settings > Notifications` owns notification delivery IA. Desktop notification
21
38
  mode, AI desktop notification dedupe duration, delivery source diagnostics,
22
39
  AI hook quiet policy, in-app queue status, and
@@ -54,6 +71,17 @@ view-first layout:
54
71
  and `Notify icon` details. Each detail shows the current mode plus
55
72
  immediately selectable off/symbol/emoji preview rows. There is no separate
56
73
  `Change` page for icon decoration.
74
+ - `Settings > Appearance` also shows a read-only `Theme font` status row.
75
+ `font_family` and `font_size` are desired values from the effective
76
+ project/global theme, and unsupported terminal paths must say `not applied`
77
+ instead of implying tmux changed the font.
78
+ - `Settings > Appearance > Language / Locale` is the global/user language
79
+ detail. The root row shows the saved `[ui].locale` value and the currently
80
+ effective locale. The detail shows `Current`, `[ui].locale`, optional
81
+ `PROJMUX_LOCALE` env override, and direct choices for `auto`, `en-US`, and
82
+ `ko-KR`. When `auto` is active it must show the detected source (`LC_ALL`,
83
+ `LC_MESSAGES`, `LANG`, or fallback). Unsupported locale tags must remain
84
+ visible as warnings and fall back to `en-US`.
57
85
 
58
86
  Hooks remain the reference pattern for this IA:
59
87
 
@@ -68,8 +96,8 @@ Hooks remain the reference pattern for this IA:
68
96
 
69
97
  Shell bootstrap UX is phase-split:
70
98
 
71
- - Phase 1 is complete in this branch: `projmux welcome`, the About-screen
72
- Welcome entry, and `pending_attach_welcome` state make the guide revisit-able.
73
- - Phase 2 is complete in this branch: the generated projmux shell tmux config
74
- runs the low-noise `projmux welcome --popup` attach hook, which claims the
75
- pending marker once and displays the welcome guide after attach.
99
+ - `projmux welcome` remains the stdout revisit command.
100
+ - `Settings > About > Welcome` opens a visible native viewer independent of
101
+ shell skip state.
102
+ - Shell `skip_version` state applies only to the automatic `projmux shell`
103
+ prompt; it does not hide manual revisit surfaces.
package/docs/statusbar.md CHANGED
@@ -5,6 +5,10 @@ clickable status bar. The same dispatcher (`projmux statusbar click`)
5
5
  handles both mouse clicks and the keyboard chord, so adding a new
6
6
  segment only requires one wiring point.
7
7
 
8
+ The built-in fallback colors used by the statusbar are semantic tokens in
9
+ `internal/theme/palette.go`; see [theme-palette.md](theme-palette.md) for the
10
+ truecolor to tmux 256-color mapping policy and palette inventory.
11
+
8
12
  ## Layout
9
13
 
10
14
  ```
@@ -37,10 +41,17 @@ row 1 [#S] #{pane_current_path} ⎈ <ctx>/<ns> <git>  %H:%M
37
41
  branch or detached commit,
38
42
  then compact state indicators when available: `*` for local changes,
39
43
  `+N` for staged entries, and `↑N`/`↓N` for ahead/behind counts. Each
40
- state token gets its own compact foreground color while preserving the
41
- existing branch block background. Window tab indexes stay left of each tab,
44
+ state token gets its own compact foreground color on the same muted branch
45
+ block; the indicators drop bold styling so git state remains readable
46
+ without dominating the status row. Window tab indexes stay left of each tab,
42
47
  and tab titles are centered in a fixed-width trim so long active pane names
43
48
  do not resize the status row.
49
+ - The settings chip keeps its label padding inside the `settings` range
50
+ and inside the chip background. The compact app chip renders `` with
51
+ the extra right-side icon padding painted by the same background, while
52
+ the standalone ` projmux` label keeps symmetric one-cell label padding.
53
+ The chip does not append an extra default-styled trailing space after
54
+ `#[default]`, so the painted button reaches the status row's right edge.
44
55
  - Both HUD segments degrade gracefully when the cell budget is tight; see
45
56
  [notify-queue.md](notify-queue.md) and [usage-tracking.md](usage-tracking.md)
46
57
  for the per-segment tier ladder.
@@ -75,6 +86,11 @@ The notify segment renders the newest queued item as a single notification
75
86
  block: project, state (`NEED`/`INFO`/`WARN`/`CRIT`), optional agent, text,
76
87
  age, and `+N` for older pending entries. Window/pane ids are not shown in the
77
88
  compact status segment.
89
+ The compact age text is locale-formatted through `internal/i18n` (`2m ago` in
90
+ `en-US`, `36초 전` in `ko-KR`). AI notify body text uses catalog-owned category
91
+ labels while preserving agent names, commands, paths, URLs, and provider
92
+ payload excerpts. The `+N` older-entry count remains a numeric compact badge so
93
+ it does not expand the status segment.
78
94
  When the notify block is wider than its cell budget, clipping shrinks the body
79
95
  text first and appends an ellipsis while preserving project, state, agent, age,
80
96
  and count metadata. If the segment is still too wide, the age is dropped next
@@ -85,8 +101,8 @@ not inherit notification styling.
85
101
  `usage` opens a native-framed detail HUD for the compact usage bar. It reads
86
102
  the cached usage state in-process, keeps the existing `projmux usage` CLI
87
103
  output shape unchanged for external consumers, aligns model/window rows with
88
- right-aligned numeric values, dims unavailable values, and colors rows at the
89
- same alert thresholds as the popup: amber at 80% and red at 95%.
104
+ right-aligned numeric values, dims unavailable values, keeps stale sync/age
105
+ metadata muted, and colors only threshold values: amber at 80% and red at 95%.
90
106
  Session State inspection lives under `Projects > Sessions > State`; global
91
107
  Settings > Session State is settings-only and the statusbar no longer exposes a
92
108
  duplicate State button.
@@ -99,15 +115,16 @@ popup command prints one quoted payload and waits for a plain Enter read so it
99
115
  does not leave terminal key state behind. The usage popup uses the same
100
116
  single-payload print and plain Enter-close pattern. It shows the authoritative
101
117
  last collect timestamp when present, falls back to the cache file mtime when
102
- needed, and colors that sync line amber once it is more than 60 seconds old.
103
- The notification HUD detail surface (`Alt-2` / `User2`) opens the right-side
104
- notification popup with newest-first rows and an amber title. When notification
105
- icon decoration is `symbol` or `emoji`, the bell appears before the title text.
106
- Selecting a row still focuses and acknowledges that notification. Pressing `x`
107
- bulk-clears non-critical rows without focusing, keeps the popup open, and
108
- refreshes the remaining rows from the queue. Pressing `a` acknowledges the
109
- selected row without focusing and preserves the selection position where
110
- possible.
118
+ needed, and keeps stale sync metadata muted instead of escalating it to a
119
+ warning color.
120
+ The notification HUD detail surface opens the right-side notification popup
121
+ through the notify sidebar action, with newest-first rows and an
122
+ attention-tinted title. When notification icon decoration is `symbol` or
123
+ `emoji`, the bell appears before the title text.
124
+ Selecting a row still focuses and acknowledges that notification. Internal
125
+ notify commands use `NotifySidebar:*` IDs in `keymap.toml`; runtime footers
126
+ render key guides from the merged keymap and prefer the default alias when it
127
+ is still configured.
111
128
 
112
129
  Empty `#{mouse_status_range}` (a click on whitespace) falls through to
113
130
  `select-window -t @<mouse_window>` when `--mouse-window` is non-empty,
@@ -174,6 +191,9 @@ updates the matching live tmux option
174
191
  (`@projmux_statusbar_decoration_cwd`, `_git`, or `_notify`) when run inside
175
192
  tmux. The legacy `~/.config/projmux/statusbar-decoration` and
176
193
  `@projmux_statusbar_decoration` remain fallback defaults for older configs.
194
+ Appearance also shows the effective desired theme font. This is a status row,
195
+ not a font editor: tmux status strings and ANSI output cannot force terminal
196
+ font family or size, so unsupported environments report `not applied`.
177
197
 
178
198
  To add a new clickable segment:
179
199
 
package/docs/testing.md CHANGED
@@ -44,8 +44,9 @@ execution should not need network access after the image is built.
44
44
  The Docker suites do not replace checks that depend on a real host terminal,
45
45
  desktop shell, or OS integration:
46
46
 
47
- - terminal emulator key delivery and swallowing for `Alt-1..5`, `Ctrl-N`, and
48
- CSI-u chords
47
+ - terminal emulator key delivery and swallowing for guaranteed `Alt-1..5`
48
+ launch keys, optional user-configured direct aliases, and transport-dependent
49
+ chords
49
50
  - Windows Terminal and WSL interop
50
51
  - macOS host path, shell, and GUI behavior
51
52
  - desktop notification click callbacks
@@ -0,0 +1,174 @@
1
+ # Theme Palette
2
+
3
+ This document records the built-in fallback palette that native projmux UI
4
+ surfaces use before project or global theme settings exist. The source of
5
+ truth in code is `internal/theme/palette.go`.
6
+
7
+ ## Scope
8
+
9
+ The fallback palette is a semantic token layer. Theme settings resolve project
10
+ and global config into the resolver-facing token inventory below, then fall
11
+ back to the built-in values from `internal/theme/palette.go`.
12
+
13
+ - Native picker truecolor SGR tokens.
14
+ - Native sidebar and chip-strip 256-color SGR tokens.
15
+ - Tmux statusbar and generated-config color tokens.
16
+ - Settings/action/state/trust/attention helper tokens.
17
+
18
+ Renderer adapters apply resolver-backed background/foreground colors to native
19
+ picker frame chrome and to tmux status/window background tokens when an
20
+ `EffectiveTheme` is supplied by the caller. Fallback-sourced fields still
21
+ render through the historical constants so built-in default output remains
22
+ byte-identical. Settings and native project picker surfaces load `[theme]`
23
+ values from global and project config through the shared effective-theme source.
24
+ Theme marketplace/import/export and Visual palette reselection remain out of
25
+ scope.
26
+
27
+ ## Resolver Token Inventory
28
+
29
+ The public resolver inventory is intentionally smaller than the current
30
+ renderer literal inventory. Surface-specific renderers map their detailed roles
31
+ onto these stable names:
32
+
33
+ | Token | Meaning | Shared surfaces |
34
+ | --- | --- | --- |
35
+ | `background` | base popup/sidebar/status surface background | native picker, frame titlebar, notify sidebar, settings popup, statusbar |
36
+ | `surface` | raised or inactive chrome surface | frame titlebar, chips, switch cards, settings popup |
37
+ | `surface_active` | selected/current row or active chip surface | native picker current row, frame chips, statusbar active window |
38
+ | `foreground` | primary readable text | native picker, titlebar, statusbar, notify sidebar, settings popup |
39
+ | `muted` | secondary text, divider, disabled or stale details | picker metadata, titlebar rule, notify age/stale, settings descriptions |
40
+ | `accent` | pointer, primary action, highlight, active affordance | native picker pointer/highlight, settings actions, chips |
41
+ | `critical` | destructive/error/critical state | settings remove/quit, notify critical badge, statusbar critical usage |
42
+ | `warning` | progress, pending, warning, busy state | AI busy/thinking indicators, notify pending title, usage warning |
43
+
44
+ Renderer-only role names such as `accent.ai`, `state.progress`, `git.branch`,
45
+ and trust colors remain in `internal/theme/palette.go` until Phase 2+ maps each
46
+ surface to the resolver tokens. The key product contract for this phase is that
47
+ native picker, frame titlebar, chips, statusbar, notify sidebar, and settings
48
+ popup all consume a shared effective token set instead of independently
49
+ choosing colors.
50
+
51
+ Font is not part of this universal token inventory. `font_family` and
52
+ `font_size` are resolved as terminal capability/profile hints: projmux can
53
+ store and display the desired value, but tmux/ANSI rendering cannot force a
54
+ font family or size across terminal emulators. In environments without a
55
+ supported terminal font adapter, projmux reports the desired font as
56
+ `not applied` instead of treating storage as a successful font change.
57
+
58
+ ## Mapping Policy
59
+
60
+ Native picker rows can emit truecolor SGR, while tmux statusbar/config strings
61
+ must use tmux color specs. The resolver therefore carries both forms for each
62
+ color token.
63
+
64
+ Rules:
65
+
66
+ - Truecolor tokens keep exact `#RRGGBB` values and can be converted to
67
+ foreground/background SGR fragments such as `38;2;R;G;B` or `48;2;R;G;B`.
68
+ - Tmux tokens keep `colourN` strings where tmux owns rendering.
69
+ - The built-in `projmux-dark` fallback uses the established ANSI and tmux
70
+ tokens from `internal/theme/palette.go` to preserve current output.
71
+ - Explicit `#RRGGBB` overrides keep exact truecolor and derive the closest
72
+ xterm 256-color `colourN` token for tmux surfaces.
73
+ - Native chip/sidebar badge tokens use 256-color SGR when they intentionally
74
+ mirror tmux colors.
75
+ - Output compatibility wins inside this baseline. For example, the kube
76
+ segment keeps tmux's named `red` and `blue` behind semantic tokens until that
77
+ segment gets a separate redesign.
78
+ - Renderers should reference semantic names instead of spelling color literals
79
+ directly. Test fixtures may still pin rendered escape strings.
80
+
81
+ ## Resolver Contract
82
+
83
+ Theme resolution is field-by-field after validating each layer:
84
+
85
+ 1. Project `.projmux/config.toml`
86
+ 2. Global `~/.config/projmux/config.toml`
87
+ 3. Built-in fallback preset `projmux-dark`
88
+
89
+ Rules:
90
+
91
+ - Project values override global values for the same field.
92
+ - Missing or `inherit` project values fall back to global values.
93
+ - Missing global values fall back to built-in values.
94
+ - A preset fills missing color tokens in its own layer.
95
+ - Explicit color tokens in the same layer override preset colors.
96
+ - An unknown preset invalidates only that layer and emits a warning.
97
+ - An invalid color, `font_family`, or `font_size` invalidates only that layer
98
+ and emits a warning.
99
+ - Every effective field reports `project`, `global`, or `fallback` as its
100
+ source label.
101
+
102
+ Built-in preset config values are:
103
+
104
+ - `projmux-dark`
105
+ - `midnight`
106
+ - `forest`
107
+ - `rose`
108
+ - `high-contrast`
109
+
110
+ ## Fallback Inventory
111
+
112
+ Chrome and text:
113
+
114
+ | Role | Native SGR | Tmux |
115
+ | --- | --- | --- |
116
+ | `surface.active` | `48;2;44;56;61` with selected white text | window active `colour240` / `colour231` |
117
+ | `surface.raised` | `48;2;24;34;38` with `216;224;228` text | window inactive `colour235` / `colour245` |
118
+ | `text.primary` | `216;224;228` | `colour231` or `colour254` for identity text |
119
+ | `text.secondary` | `164;176;182` | `colour245` |
120
+ | `text.muted` | `117;132;140` or ANSI dim | `colour244`, `colour238`, `colour240` for low-signal blocks |
121
+
122
+ Accents and state:
123
+
124
+ | Role | Native SGR | Tmux |
125
+ | --- | --- | --- |
126
+ | `accent.identity` | not emitted directly today | `colour60` bg / `colour254` fg |
127
+ | `accent.action` | `141;205;142`, strong `122;199;173` | `colour29` bg / `colour230` fg |
128
+ | `accent.attention` | notify HUD background/project family | `colour53`, project `colour90` |
129
+ | `accent.ai` | notify agent `colour37` family | `colour37` bg / `colour121` fg |
130
+ | `state.progress` | `255;204;102`; switch attention/busy dot and pending notify title/bell/badge `colour220` | `colour220` |
131
+ | `state.warning` | usage/status popup ANSI 256 wrapper | `colour214` |
132
+ | `state.danger` | `255;107;107` | `colour160` |
133
+ | `state.success` | settings/trust green families | `colour72`, `colour151` |
134
+ | `state.ahead` | switch/git metadata and notify age ANSI 256 wrapper | `colour153` |
135
+ | `git.branch` | switch/sidebar branch badge uses the statusbar git branch block colors | `colour30` bg / `colour231` fg |
136
+
137
+ Surface-specific tokens:
138
+
139
+ | Surface | Tokens |
140
+ | --- | --- |
141
+ | Native picker | current row, titlebar, rule, pointer, highlight, muted text, chip active/inactive/disabled |
142
+ | Statusbar row 1 | session identity, cwd secondary text, divider, git branch block, git dirty/staged/ahead/behind, settings action chip, clock |
143
+ | Notify HUD/sidebar | line bg/fg, project badge, info/warn/crit/stale/gone badges, AI agent badge, count/age text |
144
+ | Usage HUD/popup | OK/warning/critical/over-limit bars and numbers, empty cells, muted sync age |
145
+ | Settings | add/type/open action, destructive remove/quit, back/cancel, info/read-only, dim description, root action/dim rows, trust trusted/stale/untrusted |
146
+ | Switch picker cards | path metadata, active/inactive git branch badges aligned with statusbar git branch block colors, statusbar-like window tabs, inline attention/progress dots |
147
+
148
+ ## Current Literal Inventory
149
+
150
+ After the Phase 3 token pass, raw color values intentionally remain in:
151
+
152
+ - `internal/theme/palette.go`, the fallback palette source of truth.
153
+ - Unit and golden fixtures that assert exact rendered output.
154
+ - `internal/app/welcome.go`, which is outside the Visual palette baseline
155
+ Phase 3 scope and should move only in welcome/update policy work.
156
+ - Older switch picker test fixtures that pin legacy compatibility output.
157
+
158
+ The converted implementation paths include:
159
+
160
+ - `internal/ui/projmuxpicker/ansi.go`
161
+ - `internal/ui/projmuxpicker/frame.go`
162
+ - `internal/app/tmux.go`
163
+ - `internal/app/status.go`
164
+ - `internal/app/statusbar.go`
165
+ - `internal/app/statusbar_decoration.go`
166
+ - `internal/app/notify.go`
167
+ - `internal/app/settings.go`
168
+ - `internal/app/settings_render.go`
169
+ - `internal/app/trust.go`
170
+ - `internal/app/usage.go`
171
+ - `internal/core/usage/hud.go`
172
+ - `internal/ui/render/switch.go`
173
+ - `internal/ui/render/popup.go`
174
+ - `internal/ui/render/switch_preview.go`