projmux 0.4.8 → 0.4.10
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 +1 -3
- package/README.md +1 -4
- package/docs/agent-workflow.md +3 -3
- package/docs/architecture.md +4 -5
- package/docs/cli.md +22 -27
- package/docs/configuration.md +77 -2
- package/docs/hooks.md +190 -48
- package/docs/install.md +14 -3
- package/docs/keybindings.md +34 -3
- package/docs/native-picker-no-fzf-poc.md +16 -24
- package/docs/native-picker-parity.md +29 -27
- package/docs/picker-ui-plan.md +23 -43
- package/docs/repo-layout.md +6 -3
- package/docs/roadmap.md +23 -9
- package/docs/statusbar.md +33 -16
- package/docs/testing.md +5 -7
- package/docs/usage-tracking.md +13 -0
- package/package.json +5 -5
package/README-ko.md
CHANGED
|
@@ -27,10 +27,8 @@ notification, settings 사이를 오가고 싶을 때 사용합니다.
|
|
|
27
27
|
|
|
28
28
|
- [Node.js](https://nodejs.org/)와 npm: 기본 설치 경로에 필요합니다.
|
|
29
29
|
- [tmux](https://github.com/tmux/tmux/wiki/Installing) **3.4 이상**.
|
|
30
|
-
- [fzf](https://github.com/junegunn/fzf#installation) **0.65.0 이상**.
|
|
31
30
|
|
|
32
|
-
설치 후 `projmux doctor`로 로컬 runtime을 확인하세요.
|
|
33
|
-
junegunn/fzf CLI binary입니다. `npm i fzf`는 다른 JavaScript library입니다.
|
|
31
|
+
설치 후 `projmux doctor`로 로컬 runtime을 확인하세요.
|
|
34
32
|
|
|
35
33
|
## 설치
|
|
36
34
|
|
package/README.md
CHANGED
|
@@ -27,11 +27,8 @@ keys to move between projects, windows, panes, notifications, and settings.
|
|
|
27
27
|
|
|
28
28
|
- [Node.js](https://nodejs.org/) and npm, for the main install path.
|
|
29
29
|
- [tmux](https://github.com/tmux/tmux/wiki/Installing) **3.4 or newer**.
|
|
30
|
-
- [fzf](https://github.com/junegunn/fzf#installation) **0.65.0 or newer**.
|
|
31
30
|
|
|
32
|
-
Run `projmux doctor` after installing to check the local runtime.
|
|
33
|
-
requirement is the junegunn/fzf CLI binary; `npm i fzf` is a different
|
|
34
|
-
JavaScript library.
|
|
31
|
+
Run `projmux doctor` after installing to check the local runtime.
|
|
35
32
|
|
|
36
33
|
## Install
|
|
37
34
|
|
package/docs/agent-workflow.md
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
- `make fmt`: repository formatting for Go, shell snippets, and generated docs where applicable.
|
|
30
30
|
- `make fix`: safe automatic fixes such as `go fix` and repository-approved cleanup steps.
|
|
31
31
|
- `make npm-pack`: local npm binary package staging and `npm pack --dry-run` for the root package plus platform packages.
|
|
32
|
-
- `make test`: fast unit coverage for app-layer AI split native agent launch/selective popup-toggle/settings/status/notification parity including AI pane option metadata, watcher metadata bootstrap for existing panes, capture-backed reply detection, missing-pane watcher shutdown, armed focus-only reply badge clearing, busy attention preservation on focus clear, manual AI topic preservation while watcher status still updates, agent-labeled desktop notification message context with pane-title-first body text, global/project-local post-create hook
|
|
32
|
+
- `make test`: fast unit coverage for app-layer AI split native agent launch/selective popup-toggle/settings/status/notification parity including AI pane option metadata, watcher metadata bootstrap for existing panes, capture-backed reply detection, missing-pane watcher shutdown, armed focus-only reply badge clearing, busy attention preservation on focus clear, manual AI topic preservation while watcher status still updates, agent-labeled desktop notification message context with pane-title-first body text, global/project-local lifecycle hook dispatch for post-create/pre-create/pane-startup/post-attach with project hook and .projmux/config.toml trust-store hashing plus env/settings kill-switch gating, declarative startup/hook run precedence, project config env/kube session environment application, pane-startup command capture/send-keys orchestration, pre-create abort behavior, and shared projmux notification icon paths, and scoped even row/column resizing after shell and agent splits, status-bar git/kube segment parity including branch block styling, statusbar pwd display-only native-framed path popup, no clipboard or tmux buffer copy, and simple Enter-close popup command, statusbar usage native HUD popup alignment/threshold/sync-staleness/fallback coverage without raw CLI popup or popup-toggle stacking, statusbar settings click popup fallback, isolated `projmux shell` tmux app launch/config generation including home-project default session targeting, app-owned project-name statusbar layout, and distinct project badge color, first-run/version-bump shell welcome state and inline update handling, shell startup update prompt actions for fresh installer-aware cached updates, pane/window keybindings, keymap.toml tmux override rendering/stale unbinds, Settings Keybindings root/list/detail/typed edit flows including parse-error rows, invalid chord and typed-cancel guards, disable/reset writes, app config regeneration, live tmux source-file reload, and no-live-tmux save behavior, window rename bindings, pane rename helper/binding, pane-exit rebalance command/hooks, hook-pane and after-select-pane based attention focus hooks, attention badge toggle/clear/list/window rendering, attach/current/kill/pin/preview/prune/sessions/session-popup/settings commands, switch, tag, tmux helper commands, update status/check/apply cache and installer detection including GitHub Release binary asset selection/extraction/replacement, doctor install-missing command selection, and Settings About update status/check action wiring, untitled standalone popup-toggle marker close/config install, direct popup minimum sizing, AI picker minimum width and height, sidebar minimum width and compact badge spacing, preview select writes, popup render output after cycling, switch picker pin action behavior without inline settings rows, nested settings hub sections for AI defaults, project picker filesystem scan/pin actions, Project Root settings source/shadowing/set/current/clear flows, app/keybinding info including Ctrl-M rename forwarding, and About version/source rendering, switch picker focused-session kill, switch picker launcher-key abort bindings, switch explicit project-root, unconfigured-root, and weak managed-root heuristic parity, switch popup hiding new-session candidates while sidebar keeps create-capable rows, switch row project-name display with `~` pinned to the top and live-session-first sorting, pretty-path, preview-context including kube context/namespace, switch settings subcommand flows including add-current-pin, interactive add-pin picker, and settings label/preview polish, native preview wiring, baseline picker surface parity including prompt/footer/header fallback without app-name filler and search-key scoped card matching, sidebar compact action-only key footer, sidebar preview-window/start-position behavior without focus-time session switching, sidebar row/window ANSI styling with pane-aggregated attention badge state and AI topic labels, Alt+2/Alt+3 legacy popup row, preview-window, pane metadata, and pane-snapshot parity, switch read0 card rows with active/inactive title styling, right-side status badges, combined directory/git metadata with muted inactive branch styling, statusbar-matched block window tabs with window attention badges, read0 expect-key action parsing, restored pin/tag card badges, and restrained selected-row marker styling, switch preview metadata without duplicated directory/git rows, preview metadata rendering, popup pane display names for AI agents, AI topics, and shell commands, switch preview cycle bindings, sessions picker preview/cycle/open/kill wiring including attached-session fallback behavior, sessions picker launcher-key abort bindings, popup/switch preview summary formatting, popup sessions tmux entry helpers, switch/popup/session rendering, session identity, candidate discovery, config path derivation, popup preview read-models, and pure state rules including preview, tag, and lifecycle stores.
|
|
33
33
|
- Current focused unit coverage also includes strict notify SOT behavior
|
|
34
34
|
(TTL does not remove rows, focus success acks, reconcile reports stale
|
|
35
35
|
rows), `notify list --live` queue/live explanations, notify sidebar
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
actions, and `focus` dispatch diagnostics for session fallback, unresolved
|
|
38
38
|
targets, window fallback, pane fallback, explicit id failures, and
|
|
39
39
|
notify-only fallback.
|
|
40
|
-
- Picker focused unit coverage includes backend-neutral picker item/action mapping,
|
|
41
|
-
- `make test-integration`: Docker-backed Linux integration smoke with real `tmux`, `
|
|
40
|
+
- Picker focused unit coverage includes backend-neutral picker item/action mapping, native title-focused filtering, numeric selection, shared close actions including raw and CSI-u Ctrl-X native custom actions, deprecated picker backend value normalization, AI picker title chrome and stable search-key ordering, Settings title chrome and root section order, Settings Labs shell without backend choices plus keybinding diagnostic list/detail/probe outcome/init delegation coverage, environment override normalization, compact multi-line metadata gutters with one-column-indented metadata, proportional native scrollbar thumb rendering, multiline partial next/previous item row rendering with rendered-row scrollbar units, fixed split-preview and sidebar list viewports with scrollbar tracks, native up/down-family navigation wrap with empty-list safety and PageUp/PageDown/Home/End clamp regression coverage, native mouse down/follow-drag/release behavior, preview tab/control normalization before width clipping, optional native frame titlebars without same-line rule fill, titled native Alt-1 sidebar chrome, statusbar-preserving sidebar popup height, native-only compact project sidebar popup sizing, and notify sidebar title/popup sizing.
|
|
41
|
+
- `make test-integration`: Docker-backed Linux integration smoke with real `tmux`, `git`, and `stty`; covers `doctor`, tmux config print/install/apply, and notify queue CRUD against isolated HOME/XDG paths.
|
|
42
42
|
- `make test-install-smoke`: Docker-backed source install smoke; covers `make install`, atomic binary replacement, `tmux apply` against a live `projmux` socket, and post-install notify queue initialization.
|
|
43
43
|
- `make test-e2e`: Docker-backed real-tmux workflow smoke for session/pane setup, app config sourcing, reply-state notify reconciliation, focus notify fallback, and status notify rendering with contextual project/state/agent badges. Host-only terminal, WSL, macOS, and GUI notification behavior remains outside Docker; see [docs/testing.md](testing.md).
|
|
44
44
|
|
package/docs/architecture.md
CHANGED
|
@@ -41,11 +41,10 @@ Responsibilities:
|
|
|
41
41
|
- convert failures into typed errors
|
|
42
42
|
|
|
43
43
|
### 3. UI orchestration
|
|
44
|
-
Picker data is modeled independently from
|
|
44
|
+
Picker data is modeled independently from row rendering. The app builds
|
|
45
45
|
backend-neutral `picker.Item` values (`Title`, `Value`, `SearchText`,
|
|
46
|
-
`MetaLines`, `Badges`, `PreviewTarget`) and
|
|
47
|
-
|
|
48
|
-
keeps the external fzf backend available as an explicit fallback.
|
|
46
|
+
`MetaLines`, `Badges`, `PreviewTarget`) and renders them through the native
|
|
47
|
+
picker.
|
|
49
48
|
|
|
50
49
|
Responsibilities:
|
|
51
50
|
- rows for popup and sidebar views
|
|
@@ -180,7 +179,7 @@ single `bind -n MouseDown1Status` covers both lines because tmux fires
|
|
|
180
179
|
| Range id | Line | Click action | Keybinding |
|
|
181
180
|
|----------|------|-------------------------------------------|--------------|
|
|
182
181
|
| session | 0 | popup `projmux sessions --ui=popup` | prefix+s s |
|
|
183
|
-
| pwd | 0 |
|
|
182
|
+
| pwd | 0 | show pane_current_path in a display-only path popup | prefix+s p |
|
|
184
183
|
| kube | 0 | popup `projmux switch --ui=popup` | prefix+s k |
|
|
185
184
|
| git | 0 | popup `projmux switch --ui=popup` | prefix+s g |
|
|
186
185
|
| usage | 1 | popup `projmux usage` | prefix+s u |
|
package/docs/cli.md
CHANGED
|
@@ -60,9 +60,8 @@ sub-verbs are entry hooks invoked by tmux keybindings (e.g.
|
|
|
60
60
|
`sidebar-focus` is wired to the sidebar's focus binding so navigation keeps
|
|
61
61
|
the active session in sync).
|
|
62
62
|
|
|
63
|
-
Settings > Labs
|
|
64
|
-
|
|
65
|
-
as an environment override and takes priority over the saved Labs setting.
|
|
63
|
+
Settings > Labs remains available for experimental settings, but picker backend
|
|
64
|
+
selection has been retired. The native picker is always used.
|
|
66
65
|
|
|
67
66
|
## setup
|
|
68
67
|
|
|
@@ -102,20 +101,16 @@ projmux doctor [--json]
|
|
|
102
101
|
projmux doctor --install-missing [--dry-run] [--include-optional]
|
|
103
102
|
```
|
|
104
103
|
|
|
105
|
-
Runs a dependency check: `tmux ≥ 3.4`, `
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
`projmux setup` for that. For fzf, doctor requires the junegunn/fzf CLI
|
|
116
|
-
executable on `PATH` to report at least 0.65.0 from `fzf --version`; the npm
|
|
117
|
-
package `fzf` is a JavaScript library and is not a valid CLI install path for
|
|
118
|
-
projmux.
|
|
104
|
+
Runs a dependency check: `tmux ≥ 3.4`, `git`, `stty` (POSIX only), and
|
|
105
|
+
`kubectl` (optional). Exit code `0` even when optional deps are missing;
|
|
106
|
+
non-zero only when a required dep is missing or stale. `--json` emits a
|
|
107
|
+
machine-readable array; the default is the human report with suggested install
|
|
108
|
+
commands per platform. `--install-missing` is explicit opt-in and runs
|
|
109
|
+
generated install commands only for missing or stale required dependencies.
|
|
110
|
+
`--dry-run` prints those commands without executing them. `--include-optional`
|
|
111
|
+
also includes optional missing dependencies such as `kubectl` when an install
|
|
112
|
+
command is available. Install flags cannot be combined with `--json`. Doctor
|
|
113
|
+
does not diagnose terminal key delivery; use `projmux setup` for that.
|
|
119
114
|
|
|
120
115
|
## focus
|
|
121
116
|
|
|
@@ -242,19 +237,20 @@ projmux status notify [--max-width N]
|
|
|
242
237
|
|
|
243
238
|
```
|
|
244
239
|
projmux statusbar click <range-id> [--socket <s>] [--mouse-window <id>]
|
|
245
|
-
[--mouse-x N] [--mouse-y N]
|
|
240
|
+
[--client <tty>] [--mouse-x N] [--mouse-y N]
|
|
246
241
|
```
|
|
247
242
|
|
|
248
243
|
Click/keyboard dispatcher for the two-line status bar. Implemented range ids:
|
|
249
|
-
`session pwd kube git usage notify`. The bare `window` /
|
|
244
|
+
`session pwd kube git usage notify settings`. The bare `window` /
|
|
250
245
|
`window|<idx>` token (tmux's built-in window-list range) and the empty
|
|
251
246
|
range fall through to `select-window -t @<mouse_window>` so the native
|
|
252
247
|
click-to-switch tab affordance is preserved on row 0. Unknown range ids are
|
|
253
248
|
non-specialized placeholders and no-op. `session` opens the existing-session
|
|
254
|
-
popup; `pwd`
|
|
255
|
-
|
|
256
|
-
`
|
|
257
|
-
acks the newest
|
|
249
|
+
popup; `pwd` shows the current pane path in a native-framed display-only
|
|
250
|
+
popup; `kube` and `git` open the project switcher popup;
|
|
251
|
+
`settings` toggles the settings popup for the tmux client; `usage` opens the
|
|
252
|
+
detailed `projmux usage` table popup; `notify` focuses and acks the newest
|
|
253
|
+
actionable queue target.
|
|
258
254
|
`MouseDown1Status` errors are
|
|
259
255
|
swallowed and surfaced as `display-message` toasts so a transient
|
|
260
256
|
failure does not raise a tmux error popup. See [statusbar.md](statusbar.md).
|
|
@@ -413,10 +409,9 @@ flags with the top-level `switch` UX:
|
|
|
413
409
|
effective root unless saved. `Workdirs` remains separate: those entries are
|
|
414
410
|
additional search roots, not the primary root. Appearance stores
|
|
415
411
|
`~/.config/projmux/statusbar-decoration` as `off` (default), `symbol`, or
|
|
416
|
-
`emoji` and updates the live tmux option when available. Labs
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
section reads the cached update status without network access;
|
|
412
|
+
`emoji` and updates the live tmux option when available. Labs remains
|
|
413
|
+
available for experimental settings. The About section reads the cached
|
|
414
|
+
update status without network access;
|
|
420
415
|
selecting Check Updates runs `projmux update check`, and Update Now runs
|
|
421
416
|
`projmux update apply`. The same About section also lists the keybinding
|
|
422
417
|
diagnostic path: zero-config first, `setup` for swallowed keys, `init` for
|
package/docs/configuration.md
CHANGED
|
@@ -38,6 +38,68 @@ The saved workdir file is:
|
|
|
38
38
|
It stores one absolute path per line. Lines beginning with `#` are comments.
|
|
39
39
|
The file is read only when no env root list is set.
|
|
40
40
|
|
|
41
|
+
## Keymap File
|
|
42
|
+
|
|
43
|
+
Settings > Keybindings is the normal in-app editor for tmux key chords. It
|
|
44
|
+
lists each action, opens a detail screen, and lets you type `plain` or
|
|
45
|
+
`prefix` tmux chord strings. Saving writes `~/.config/projmux/keymap.toml`,
|
|
46
|
+
rewrites `~/.config/projmux/tmux.conf`, and, when Settings is running inside
|
|
47
|
+
tmux, sources that app config so non-terminal-layer tmux chords take effect
|
|
48
|
+
immediately.
|
|
49
|
+
|
|
50
|
+
Settings > Labs > Diagnose keybindings is the in-app diagnostic/remediation
|
|
51
|
+
surface for the same catalog. It probes one action key at a time through the
|
|
52
|
+
controlling TTY, reports whether the key arrived as a plain tmux chord, CSI-u
|
|
53
|
+
fallback, unexpected sequence, or timeout, and delegates supported terminal
|
|
54
|
+
fallback preview/apply operations to the `projmux init` engine.
|
|
55
|
+
|
|
56
|
+
`~/.config/projmux/keymap.toml` can also be edited by hand. When the file is
|
|
57
|
+
absent, generated tmux config stays on the built-in defaults.
|
|
58
|
+
|
|
59
|
+
Supported schema:
|
|
60
|
+
|
|
61
|
+
```toml
|
|
62
|
+
[bindings.sessionizer-sidebar]
|
|
63
|
+
plain = "M-a"
|
|
64
|
+
prefix = "A"
|
|
65
|
+
|
|
66
|
+
[bindings.new-window]
|
|
67
|
+
plain = "C-t"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Each table is `[bindings.<action-id>]`. Supported keys are:
|
|
71
|
+
|
|
72
|
+
| Key | Meaning |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `plain` | A no-prefix tmux chord such as `M-a`, `C-t`, or `M-S-Left`. |
|
|
75
|
+
| `prefix` | A tmux prefix-table chord such as `A` or `r`. |
|
|
76
|
+
|
|
77
|
+
Set a value to the empty string to disable that chord for the action:
|
|
78
|
+
|
|
79
|
+
```toml
|
|
80
|
+
[bindings.sessionizer-sidebar]
|
|
81
|
+
plain = ""
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
In Settings, `Disable Plain/Prefix chord` writes the empty string override.
|
|
85
|
+
`Reset Plain/Prefix chord` removes that override and returns to the built-in
|
|
86
|
+
default. The Settings writer is deterministic and rewrites the supported
|
|
87
|
+
subset only: `[bindings.<action-id>]` tables with `plain` and `prefix` string
|
|
88
|
+
keys. If the existing file has parse errors or unknown action IDs, Settings
|
|
89
|
+
shows the keymap error row and refuses to overwrite it until the file is fixed.
|
|
90
|
+
|
|
91
|
+
The file currently affects generated tmux config from `projmux tmux
|
|
92
|
+
print-config`, `projmux tmux install`, `projmux tmux print-app-config`,
|
|
93
|
+
`projmux tmux install-app`, and `projmux shell`. Terminal init adapters such as
|
|
94
|
+
Ghostty and Windows Terminal still install the built-in CSI-u fallback map.
|
|
95
|
+
Changing those terminal-layer mappings still requires rerunning `projmux init`
|
|
96
|
+
and restarting the terminal where that terminal requires it.
|
|
97
|
+
|
|
98
|
+
When a chord is overridden, projmux emits unbinds for both the stale default
|
|
99
|
+
chord and the replacement before binding the merged action. Popup and floating
|
|
100
|
+
UI actions still route through `tmux popup-toggle`, so pressing the same
|
|
101
|
+
configured key opens and closes the popup.
|
|
102
|
+
|
|
41
103
|
## Environment Variables
|
|
42
104
|
|
|
43
105
|
| Variable | Purpose |
|
|
@@ -51,7 +113,7 @@ The file is read only when no env root list is set.
|
|
|
51
113
|
| `PROJMUX_USAGE_DEBUG` | When non-empty, prints adapter errors from `projmux status usage` to stderr. |
|
|
52
114
|
| `PROJMUX_USAGE_LIMITS_PATH` | Deprecated. Read but ignored; limits now come from upstream APIs and local Codex rollout state. |
|
|
53
115
|
| `PROJMUX_FOCUS_DEBUG` | When non-empty, `projmux focus` prints one telemetry line to stderr. |
|
|
54
|
-
| `PROJMUX_PICKER_BACKEND` |
|
|
116
|
+
| `PROJMUX_PICKER_BACKEND` | Legacy picker backend override. Any value, including old `fzf` settings, now resolves to the native picker. |
|
|
55
117
|
| `PROJMUX_INSTALLER` | Installer source hint used by update flows. npm installs set this automatically; advanced release installs can set `github-release`. |
|
|
56
118
|
|
|
57
119
|
Example:
|
|
@@ -87,7 +149,8 @@ When the hook is set, projmux invokes it with positional arguments:
|
|
|
87
149
|
summary body urgency app-name tag group icon-path
|
|
88
150
|
```
|
|
89
151
|
|
|
90
|
-
Hook details for new-session lifecycle hooks
|
|
152
|
+
Hook details for new-session lifecycle hooks and project-local
|
|
153
|
+
`.projmux/config.toml` live in [Hooks](hooks.md).
|
|
91
154
|
|
|
92
155
|
## Usage Tracking
|
|
93
156
|
|
|
@@ -100,6 +163,18 @@ ${PROJMUX_USAGE_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/projmux/usage}/
|
|
|
100
163
|
See [Usage tracking](usage-tracking.md) for adapter behavior, throttling, and
|
|
101
164
|
failure handling.
|
|
102
165
|
|
|
166
|
+
## Shell Welcome State
|
|
167
|
+
|
|
168
|
+
`projmux shell` stores its once-per-version welcome marker under:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
${XDG_STATE_HOME:-$HOME/.local/state}/projmux/welcomed-v<version>.json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
If the marker is missing, the next shell launch shows the welcome again. If the
|
|
175
|
+
marker is corrupt or cannot be written, shell startup continues without the
|
|
176
|
+
welcome.
|
|
177
|
+
|
|
103
178
|
## Decoration Mode
|
|
104
179
|
|
|
105
180
|
Settings > Appearance controls optional status and picker decoration:
|
package/docs/hooks.md
CHANGED
|
@@ -1,89 +1,224 @@
|
|
|
1
1
|
# Hooks
|
|
2
2
|
|
|
3
|
-
projmux runs
|
|
4
|
-
|
|
5
|
-
injecting per-session env via `tmux set-environment`,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
hook.
|
|
3
|
+
projmux runs optional user scripts at selected tmux lifecycle points. Hooks are
|
|
4
|
+
the project-agnostic extension point for behavior projmux itself stays out of:
|
|
5
|
+
injecting per-session env via `tmux set-environment`, selecting repository
|
|
6
|
+
tokens, exporting a Kubernetes context, kicking off a background sync, or
|
|
7
|
+
sending an initial pane command.
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
projmux-owned internal tmux hooks such as `pane-focus-in`, `pane-focus-out`,
|
|
10
|
+
`after-select-pane`, and `after-kill-pane` are not exposed as user hook events.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Events
|
|
13
|
+
|
|
14
|
+
| Event | When it runs | Failure behavior | Stdout behavior |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| `pre-create` | Before projmux creates a missing persistent or ephemeral session | Non-zero exit, exec error, or timeout aborts creation | Logged with `[pre-create] ` |
|
|
17
|
+
| `post-create` | After projmux creates a brand-new persistent or ephemeral session | Logged and ignored; creation continues | Logged with `[post-create] ` |
|
|
18
|
+
| `pane-startup` | After `post-create`, once the initial pane of a brand-new session reaches a shell prompt | Logged and ignored; empty output is no-op | Captured as the command to send into the pane |
|
|
19
|
+
| `post-attach` | After projmux switches the current tmux client to an existing session/target from inside tmux | Logged and ignored | Logged with `[post-attach] ` |
|
|
20
|
+
|
|
21
|
+
Deferred Phase A candidates remain future work until their behavior can be
|
|
22
|
+
specified without exposing projmux's internal tmux hook machinery: pane exit,
|
|
23
|
+
window create/rename, and focus-change hook events.
|
|
24
|
+
|
|
25
|
+
## Where Hooks Live
|
|
26
|
+
|
|
27
|
+
Global hooks live under the XDG config directory:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
${XDG_CONFIG_HOME:-$HOME/.config}/projmux/hooks/<event>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For example:
|
|
13
34
|
|
|
14
35
|
```text
|
|
15
36
|
${XDG_CONFIG_HOME:-$HOME/.config}/projmux/hooks/post-create
|
|
37
|
+
${XDG_CONFIG_HOME:-$HOME/.config}/projmux/hooks/pane-startup
|
|
16
38
|
```
|
|
17
39
|
|
|
18
|
-
Project-local hooks
|
|
40
|
+
Project-local hooks are discovered from the lifecycle context's `PROJMUX_CWD`:
|
|
19
41
|
|
|
20
42
|
```text
|
|
21
|
-
<repo>/.projmux
|
|
22
|
-
<repo>/.projmux/hooks
|
|
43
|
+
<repo>/.projmux/<event>
|
|
44
|
+
<repo>/.projmux/hooks/<event>
|
|
45
|
+
<repo>/.projmux/config.toml
|
|
23
46
|
```
|
|
24
47
|
|
|
25
|
-
|
|
26
|
-
have the owner-execute bit set. Anything else is silently skipped — no warning,
|
|
27
|
-
no log. There is no enable flag.
|
|
48
|
+
For example, `pane-startup` discovery checks:
|
|
28
49
|
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
|
|
50
|
+
```text
|
|
51
|
+
<repo>/.projmux/pane-startup
|
|
52
|
+
<repo>/.projmux/hooks/pane-startup
|
|
32
53
|
```
|
|
33
54
|
|
|
34
|
-
|
|
35
|
-
|
|
55
|
+
Each hook file must exist, be a regular file or symlink (not a directory), and
|
|
56
|
+
have the owner-execute bit set. Anything else is silently skipped.
|
|
57
|
+
|
|
58
|
+
For each event, projmux runs at most one project-local file: first
|
|
59
|
+
`.projmux/<event>` if executable, otherwise `.projmux/hooks/<event>` if
|
|
36
60
|
executable. Discovery does not walk parent directories and does not run hooks
|
|
37
61
|
from status, preview, or picker hot paths.
|
|
38
62
|
|
|
39
|
-
|
|
63
|
+
If both a global hook and a project-local hook exist for an event, projmux runs
|
|
64
|
+
the global hook first, then the project-local hook, then any matching
|
|
65
|
+
declarative config command from `.projmux/config.toml`. For `pane-startup`, the
|
|
66
|
+
last non-empty trimmed stdout wins. Config `pane-startup` commands therefore
|
|
67
|
+
override file hooks deterministically.
|
|
68
|
+
|
|
69
|
+
## Project Config
|
|
70
|
+
|
|
71
|
+
Repositories may declare hook behavior in `.projmux/config.toml`. projmux
|
|
72
|
+
supports only this narrow TOML subset in Phase B:
|
|
73
|
+
|
|
74
|
+
```toml
|
|
75
|
+
[startup]
|
|
76
|
+
run = "git status --short"
|
|
77
|
+
|
|
78
|
+
[hooks.pre-create]
|
|
79
|
+
run = "echo checking"
|
|
80
|
+
|
|
81
|
+
[hooks.post-create]
|
|
82
|
+
run = "echo created $PROJMUX_SESSION"
|
|
83
|
+
|
|
84
|
+
[hooks.pane-startup]
|
|
85
|
+
run = "echo make test"
|
|
86
|
+
|
|
87
|
+
[hooks.post-attach]
|
|
88
|
+
run = "echo attached"
|
|
89
|
+
|
|
90
|
+
[env]
|
|
91
|
+
FOO = "bar"
|
|
92
|
+
|
|
93
|
+
[kube]
|
|
94
|
+
context = "dev-cluster"
|
|
95
|
+
namespace = "tools"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Only quoted string values are supported. Unknown sections or keys make the
|
|
99
|
+
config file invalid for this run. Supported hook events are the public lifecycle
|
|
100
|
+
events listed above: `pre-create`, `post-create`, `pane-startup`, and
|
|
101
|
+
`post-attach`. Internal tmux hook names such as `after-select-pane` are rejected.
|
|
102
|
+
Phase C secret interpolation is not implemented; values are used literally.
|
|
103
|
+
|
|
104
|
+
`[hooks.<event>] run` executes through `sh -c` with the same timeout, logging,
|
|
105
|
+
environment, and failure model as file hooks. For `pane-startup`, stdout is
|
|
106
|
+
captured as the pane command.
|
|
107
|
+
|
|
108
|
+
`[startup] run` is a direct shorthand for a startup pane command. It is not
|
|
109
|
+
executed as shell by the hook runner; the string itself is sent to the new pane.
|
|
110
|
+
When both `[hooks.pane-startup] run` and `[startup] run` are present,
|
|
111
|
+
`[startup] run` wins because it is applied last.
|
|
112
|
+
|
|
113
|
+
`[env]` values are added to hook process environments and to newly-created tmux
|
|
114
|
+
session environments. For new sessions, projmux passes them to
|
|
115
|
+
`tmux new-session` as sorted `-e KEY=VALUE` arguments before the first pane is
|
|
116
|
+
created, so the initial shell and `[startup]` command can see them. projmux also
|
|
117
|
+
refreshes the tmux session environment with `tmux set-environment -t <session>
|
|
118
|
+
KEY VALUE` after creation for later panes. projmux's reserved `PROJMUX_*` hook
|
|
119
|
+
variables are appended after `[env]` in hook process environments, so the hook
|
|
120
|
+
contract cannot be overridden by project config.
|
|
121
|
+
|
|
122
|
+
`[kube] context` and `namespace` are reflected as hook and session environment:
|
|
123
|
+
`PROJMUX_KUBE_CONTEXT`, `KUBE_CONTEXT`, `PROJMUX_KUBE_NAMESPACE`, and
|
|
124
|
+
`KUBE_NAMESPACE`. projmux does not synthesize kubeconfig files from these two
|
|
125
|
+
values.
|
|
126
|
+
|
|
127
|
+
## Trust Model
|
|
128
|
+
|
|
129
|
+
Global hooks under `$XDG_CONFIG_HOME` are prompt-free.
|
|
130
|
+
|
|
131
|
+
Project-local hooks and `.projmux/config.toml` are gated by trust-on-first-use
|
|
132
|
+
for every user-facing hook event in this file. A repository hook file or config
|
|
133
|
+
file must be approved before projmux runs or applies it. Approving "always"
|
|
134
|
+
records the file content hash in:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
${XDG_STATE_HOME:-$HOME/.local/state}/projmux/trusted-projects.json
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The trust key is the absolute repository path and each executable hook or config
|
|
141
|
+
path is stored relative to that repository. Each project entry has a
|
|
142
|
+
`trusted_at` timestamp and a `files` map of relative paths to SHA-256 hashes.
|
|
143
|
+
When file content changes, projmux asks again and shows the old and new SHA-256
|
|
144
|
+
hashes. In non-interactive contexts such as tmux run-shell or CI, untrusted or
|
|
145
|
+
changed project-local files fail closed with a warning.
|
|
146
|
+
|
|
147
|
+
Set `PROJMUX_PROJECT_HOOKS=off` to disable project-local hook discovery
|
|
148
|
+
entirely. Project-local hooks can also be disabled from `projmux settings`
|
|
149
|
+
under Labs. The global hook still runs either way.
|
|
150
|
+
|
|
151
|
+
## Pane Startup
|
|
152
|
+
|
|
153
|
+
`pane-startup` runs only for the initial pane created with a new
|
|
154
|
+
projmux-managed session. It runs after `post-create` so `post-create` can seed
|
|
155
|
+
session-level tmux environment before the startup command is sent. It does not
|
|
156
|
+
run when projmux attaches to an existing session or target.
|
|
157
|
+
|
|
158
|
+
Before running `pane-startup`, projmux polls tmux `pane_current_command` for the
|
|
159
|
+
new pane and waits until it reports a shell command. This avoids fixed sleeps as
|
|
160
|
+
the primary readiness mechanism.
|
|
161
|
+
|
|
162
|
+
The hook's trimmed stdout is treated as the command to send into the new pane:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
tmux send-keys -t <pane-id> <command> Enter
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Empty stdout is a no-op. Hook stderr is still forwarded to projmux's stderr with
|
|
169
|
+
the `[pane-startup] ` prefix. If both global and project-local hooks emit a
|
|
170
|
+
command, the project-local command wins because project hooks run after global
|
|
171
|
+
hooks.
|
|
172
|
+
|
|
173
|
+
## Pre Create Abort
|
|
174
|
+
|
|
175
|
+
`pre-create` runs before `tmux new-session` on creation paths. A non-zero exit,
|
|
176
|
+
exec error, or timeout aborts the session creation. If a global `pre-create`
|
|
177
|
+
hook aborts, the project-local `pre-create` hook does not run.
|
|
40
178
|
|
|
41
|
-
|
|
42
|
-
persistent path used by `current` and `switch`) or `CreateEphemeralSession`
|
|
43
|
-
(used by `attach`). It does **not** run when projmux attaches to an existing
|
|
44
|
-
session.
|
|
179
|
+
This is the only Phase A hook event that can block creation.
|
|
45
180
|
|
|
46
|
-
|
|
47
|
-
hook first, then the project-local hook. A failure or timeout in either hook is
|
|
48
|
-
logged once and does not block session creation or the other hook.
|
|
181
|
+
## Post Attach
|
|
49
182
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
183
|
+
`post-attach` is supported only when projmux is already running inside tmux and
|
|
184
|
+
uses `switch-client` to move the current client to an existing session or
|
|
185
|
+
target. Outside tmux, `tmux attach-session` blocks until the user detaches, so
|
|
186
|
+
projmux does not run `post-attach` for outside-tmux attach paths in this phase.
|
|
53
187
|
|
|
54
188
|
## Environment
|
|
55
189
|
|
|
56
|
-
|
|
190
|
+
Hooks inherit projmux's environment, plus:
|
|
57
191
|
|
|
58
192
|
| Variable | Always set | Description |
|
|
59
193
|
| --- | --- | --- |
|
|
60
194
|
| `PROJMUX_SESSION` | yes | tmux session name |
|
|
61
|
-
| `PROJMUX_CWD` | yes |
|
|
62
|
-
| `PROJMUX_SESSION_KIND` | yes | `persistent` or `ephemeral` |
|
|
195
|
+
| `PROJMUX_CWD` | yes | lifecycle working directory; for creation events this is the new session directory |
|
|
196
|
+
| `PROJMUX_SESSION_KIND` | yes | `persistent` or `ephemeral` for creation events; empty for `post-attach` |
|
|
63
197
|
| `PROJMUX_VERSION` | yes | projmux version string |
|
|
64
198
|
| `PROJMUX_SOCKET` | only if projmux used `tmux -L <socket>` | tmux socket name |
|
|
199
|
+
| `PROJMUX_PANE` | only for pane events | tmux pane id such as `%7` |
|
|
65
200
|
|
|
66
201
|
## Examples
|
|
67
202
|
|
|
68
|
-
### Global
|
|
203
|
+
### Global Post Create Stub
|
|
69
204
|
|
|
70
205
|
```bash
|
|
71
206
|
#!/usr/bin/env bash
|
|
72
207
|
echo "session=$PROJMUX_SESSION cwd=$PROJMUX_CWD kind=$PROJMUX_SESSION_KIND"
|
|
73
208
|
```
|
|
74
209
|
|
|
75
|
-
### Project
|
|
210
|
+
### Project Pane Startup Command
|
|
76
211
|
|
|
77
212
|
```bash
|
|
78
213
|
mkdir -p .projmux
|
|
79
|
-
cat > .projmux/
|
|
214
|
+
cat > .projmux/pane-startup <<'EOF'
|
|
80
215
|
#!/usr/bin/env bash
|
|
81
|
-
echo "
|
|
216
|
+
echo "git status --short"
|
|
82
217
|
EOF
|
|
83
|
-
chmod +x .projmux/
|
|
218
|
+
chmod +x .projmux/pane-startup
|
|
84
219
|
```
|
|
85
220
|
|
|
86
|
-
### Per
|
|
221
|
+
### Per Session GH_TOKEN By Repo
|
|
87
222
|
|
|
88
223
|
```bash
|
|
89
224
|
#!/usr/bin/env bash
|
|
@@ -105,14 +240,21 @@ it does not retroactively change the current shell. Open new panes via tmux
|
|
|
105
240
|
## Troubleshooting
|
|
106
241
|
|
|
107
242
|
- **Nothing happens.** Check the execute bit on the global hook
|
|
108
|
-
(`ls -l ~/.config/projmux/hooks
|
|
109
|
-
(`ls -l .projmux
|
|
110
|
-
|
|
111
|
-
|
|
243
|
+
(`ls -l ~/.config/projmux/hooks/<event>`) or the project hook
|
|
244
|
+
(`ls -l .projmux/<event> .projmux/hooks/<event>`). A missing bit makes
|
|
245
|
+
projmux skip hook files silently by design. `.projmux/config.toml` does not
|
|
246
|
+
need an execute bit.
|
|
247
|
+
- **`project hook ... requires trust; skipping in non-interactive context`** or
|
|
248
|
+
**`project config ... requires trust; skipping in non-interactive context`.**
|
|
249
|
+
Run the same projmux command from an interactive terminal to approve the file,
|
|
250
|
+
or set `PROJMUX_PROJECT_HOOKS=off` if project-local execution should be
|
|
251
|
+
disabled.
|
|
252
|
+
- **`projmux: <event> hook: ... timed out after 5s`.** Long-running work
|
|
112
253
|
belongs in a backgrounded child (`(slow-thing &) >/dev/null 2>&1`). The hook
|
|
113
254
|
itself must return within 5s or projmux kills it.
|
|
114
|
-
- **`projmux:
|
|
115
|
-
returned non-zero.
|
|
116
|
-
|
|
117
|
-
- **Lines appear with `[post-create] `
|
|
118
|
-
hook
|
|
255
|
+
- **`projmux: <event> hook: hook ... exited with status N`.** The script
|
|
256
|
+
returned non-zero. For `pre-create`, creation aborts; for other events,
|
|
257
|
+
projmux logs once and moves on.
|
|
258
|
+
- **Lines appear with `[post-create] `, `[pre-create] `, or `[post-attach] `
|
|
259
|
+
prefixes.** Expected; hook stdout/stderr are multiplexed into projmux's
|
|
260
|
+
stderr stream. `pane-startup` stdout is captured as the pane command instead.
|
package/docs/install.md
CHANGED
|
@@ -18,8 +18,20 @@ After installing, run:
|
|
|
18
18
|
projmux doctor
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`doctor` checks that runtime tools such as `tmux` and
|
|
22
|
-
available
|
|
21
|
+
`doctor` checks that runtime tools such as `tmux`, `git`, and `stty` are
|
|
22
|
+
available.
|
|
23
|
+
|
|
24
|
+
Start the tmux app with:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
projmux shell
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The first launch for each projmux version prints a short welcome with the
|
|
31
|
+
current version, detach/exit keys, core app shortcuts, and cached update status
|
|
32
|
+
when available. If an installer-supported update is available, pressing Enter
|
|
33
|
+
at the inline prompt runs `projmux update apply`; answering `n` prints that
|
|
34
|
+
manual command and continues into the shell.
|
|
23
35
|
|
|
24
36
|
## Runtime Tools
|
|
25
37
|
|
|
@@ -27,7 +39,6 @@ Normal use needs:
|
|
|
27
39
|
|
|
28
40
|
- Node.js and npm for the npm install channel.
|
|
29
41
|
- tmux 3.4 or newer.
|
|
30
|
-
- fzf 0.65.0 or newer.
|
|
31
42
|
|
|
32
43
|
Useful optional tools:
|
|
33
44
|
|