@jx0/jmux 0.5.2 → 0.5.4

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.
Files changed (3) hide show
  1. package/README.md +3 -1
  2. package/package.json +1 -1
  3. package/src/main.ts +72 -7
package/README.md CHANGED
@@ -22,7 +22,9 @@ bun install -g @jx0/jmux
22
22
  jmux
23
23
  ```
24
24
 
25
- Requires [Bun](https://bun.sh) 1.2+, [tmux](https://github.com/tmux/tmux) 3.2+, [fzf](https://github.com/junegunn/fzf), and optionally [git](https://git-scm.com/) for branch display.
25
+ Requires [Bun](https://bun.sh) 1.2+, [tmux](https://github.com/tmux/tmux) 3.2+, [fzf](https://github.com/junegunn/fzf), and optionally [git](https://git-scm.com/) for branch display. jmux will offer to install tmux and fzf for you on first run.
26
+
27
+ New to tmux? See the **[Getting Started guide](docs/getting-started.md)** — no prior tmux knowledge needed.
26
28
 
27
29
  ---
28
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jx0/jmux",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "The terminal workspace for agentic development",
5
5
  "type": "module",
6
6
  "bin": {
package/src/main.ts CHANGED
@@ -12,7 +12,7 @@ import { homedir } from "os";
12
12
 
13
13
  // --- CLI commands (run and exit before TUI) ---
14
14
 
15
- const VERSION = "0.5.2";
15
+ const VERSION = "0.5.4";
16
16
 
17
17
  const HELP = `jmux — the terminal workspace for agentic development
18
18
 
@@ -58,12 +58,6 @@ if (process.argv.includes("-v") || process.argv.includes("--version")) {
58
58
  process.exit(0);
59
59
  }
60
60
 
61
- if (process.env.JMUX) {
62
- console.error("Already running inside jmux.");
63
- process.exit(1);
64
- }
65
- process.env.JMUX = "1";
66
-
67
61
  if (process.argv.includes("--install-agent-hooks")) {
68
62
  installAgentHooks();
69
63
  process.exit(0);
@@ -122,6 +116,14 @@ function installAgentHooks(): void {
122
116
  console.log("will show an orange ! on that session.");
123
117
  }
124
118
 
119
+ // --- Nesting guard (after CLI commands, before TUI) ---
120
+
121
+ if (process.env.JMUX) {
122
+ console.error("Already running inside jmux.");
123
+ process.exit(1);
124
+ }
125
+ process.env.JMUX = "1";
126
+
125
127
  // --- TUI startup ---
126
128
 
127
129
  // Read sidebar width from user config, fall back to default
@@ -164,6 +166,69 @@ for (let i = 2; i < process.argv.length; i++) {
164
166
  process.exit(1);
165
167
  }
166
168
  }
169
+ // Preflight checks — offer to install missing dependencies
170
+ async function preflight(): Promise<void> {
171
+ const missing: string[] = [];
172
+ if (Bun.spawnSync(["tmux", "-V"], { stdout: "pipe", stderr: "pipe" }).exitCode !== 0) {
173
+ missing.push("tmux");
174
+ }
175
+ if (Bun.spawnSync(["fzf", "--version"], { stdout: "pipe", stderr: "pipe" }).exitCode !== 0) {
176
+ missing.push("fzf");
177
+ }
178
+ if (missing.length === 0) return;
179
+
180
+ const isMac = process.platform === "darwin";
181
+ const hasBrew = isMac && Bun.spawnSync(["brew", "--version"], { stdout: "pipe", stderr: "pipe" }).exitCode === 0;
182
+ const hasApt = !isMac && Bun.spawnSync(["apt", "--version"], { stdout: "pipe", stderr: "pipe" }).exitCode === 0;
183
+
184
+ console.log(`\njmux requires ${missing.join(" and ")} to run.\n`);
185
+
186
+ if (hasBrew || hasApt) {
187
+ const pm = hasBrew ? "brew" : "sudo apt";
188
+ const installCmd = `${pm} install ${missing.join(" ")}`;
189
+ console.log(`Install with:\n\n ${installCmd}\n`);
190
+
191
+ // Prompt to install
192
+ process.stdout.write("Install now? [Y/n] ");
193
+ const response = await new Promise<string>((resolve) => {
194
+ process.stdin.setRawMode?.(false);
195
+ process.stdin.resume();
196
+ process.stdin.once("data", (data) => {
197
+ process.stdin.pause();
198
+ resolve(data.toString().trim().toLowerCase());
199
+ });
200
+ });
201
+
202
+ if (response === "" || response === "y" || response === "yes") {
203
+ console.log(`\nRunning: ${installCmd}\n`);
204
+ const args = hasBrew
205
+ ? ["brew", "install", ...missing]
206
+ : ["sudo", "apt", "install", "-y", ...missing];
207
+ const result = Bun.spawnSync(args, { stdout: "inherit", stderr: "inherit" });
208
+ if (result.exitCode !== 0) {
209
+ console.error("\nInstallation failed. Please install manually and try again.");
210
+ process.exit(1);
211
+ }
212
+ console.log("\nDependencies installed. Starting jmux...\n");
213
+ return;
214
+ }
215
+ } else {
216
+ // No package manager detected — just show instructions
217
+ if (isMac) {
218
+ console.log("Install Homebrew first: https://brew.sh");
219
+ console.log(`Then run: brew install ${missing.join(" ")}`);
220
+ } else {
221
+ console.log(`Install with your package manager, e.g.:`);
222
+ console.log(` apt install ${missing.join(" ")}`);
223
+ console.log(` dnf install ${missing.join(" ")}`);
224
+ console.log(` pacman -S ${missing.join(" ")}`);
225
+ }
226
+ }
227
+
228
+ process.exit(1);
229
+ }
230
+ await preflight();
231
+
167
232
  const cols = process.stdout.columns || 80;
168
233
  const rows = process.stdout.rows || 24;
169
234
  const sidebarVisible = cols >= 80;