dmux 0.0.1 → 1.0.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Justin Schroeder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,29 +1,248 @@
1
- # dmux
1
+ # cmux - AI-Powered tmux Development Sessions
2
2
 
3
- ⚠️ **This is a placeholder package** ⚠️
3
+ cmux is a powerful tmux pane manager that creates parallel development environments with Claude Code AI assistance. Each pane gets its own git worktree and branch, enabling seamless parallel development workflows.
4
4
 
5
- The actual dmux package is currently in development.
5
+ ## Features
6
6
 
7
- ## What is dmux?
7
+ - **🚀 Parallel Development**: Work on multiple features simultaneously in separate panes
8
+ - **🌳 Git Worktree Integration**: Each pane operates in its own isolated git worktree
9
+ - **🤖 AI-Powered**: Automatic branch naming and commit message generation
10
+ - **🎯 Claude Code Integration**: Launch Claude with prompts and auto-accept edits
11
+ - **📦 Project Isolation**: Each project gets its own tmux session
12
+ - **🔄 Smart Merging**: One-command merge workflow with automatic cleanup
8
13
 
9
- dmux (developer mux) will be a sophisticated tmux pane manager that creates AI-powered development sessions. It provides seamless integration between tmux, git worktrees, and AI agents to enable parallel development workflows with automatic branch management and AI assistance.
14
+ ## Prerequisites
10
15
 
11
- ## Key Features (Coming Soon)
12
-
13
- - **Project-specific tmux sessions**: Each project gets its own isolated tmux session
14
- - **Git worktree integration**: Each pane operates in its own git worktree with a dedicated branch
15
- - **AI agent automation**: Automatically launches AI agents with prompts
16
- - **Intelligent merge workflows**: Auto-commits, generates commit messages, and merges worktrees
17
- - **React-based TUI**: Interactive terminal UI for managing panes
16
+ - **tmux** 3.0 or higher
17
+ - **Node.js** 18 or higher
18
+ - **Git** 2.20 or higher (with worktree support)
19
+ - **Claude Code CLI** (`claude` command must be available)
20
+ - **OpenRouter API Key** (optional but recommended for AI features)
18
21
 
19
22
  ## Installation
20
23
 
21
- This placeholder package cannot be installed yet. The full version will be available soon.
24
+ ### 1. Clone and Build
25
+
26
+ ```bash
27
+ # Clone the repository
28
+ git clone <repository-url> ~/cmux
29
+ cd ~/cmux
30
+
31
+ # Install dependencies
32
+ npm install
33
+
34
+ # Build the project
35
+ npm run build
36
+ ```
37
+
38
+ ### 2. Global Installation
39
+
40
+ Choose one of these methods:
41
+
42
+ #### Option A: Symlink (Recommended)
43
+ ```bash
44
+ # Make the script executable
45
+ chmod +x ~/cmux/cmux
46
+
47
+ # Create symlink in a directory that's in your PATH
48
+ sudo ln -s ~/cmux/cmux /usr/local/bin/cmux
49
+ ```
50
+
51
+ #### Option B: Add to PATH
52
+ ```bash
53
+ # Add this line to your ~/.bashrc or ~/.zshrc
54
+ export PATH="$PATH:$HOME/cmux"
55
+
56
+ # Reload your shell configuration
57
+ source ~/.bashrc # or ~/.zshrc
58
+ ```
59
+
60
+ #### Option C: NPM Global Link
61
+ ```bash
62
+ # From the cmux directory
63
+ npm link
64
+ ```
65
+
66
+ ### 3. Configure AI Features (Optional)
67
+
68
+ For AI-powered branch naming and commit messages:
69
+
70
+ ```bash
71
+ # Add to your ~/.bashrc or ~/.zshrc
72
+ export OPENROUTER_API_KEY="your-api-key-here"
73
+ ```
74
+
75
+ Get your API key from [OpenRouter](https://openrouter.ai/).
76
+
77
+ ## Quick Start
78
+
79
+ ### Basic Usage
80
+
81
+ 1. **Start cmux in your project**
82
+ ```bash
83
+ cd /path/to/your/project
84
+ cmux
85
+ ```
86
+
87
+ 2. **Create a new development pane**
88
+ - Press `n` or select "+ New cmux pane"
89
+ - Enter an optional prompt like "fix authentication bug"
90
+ - Claude launches in a new pane with your prompt
91
+
92
+ 3. **Navigate between panes**
93
+ - Use `↑/↓` arrows to select panes
94
+ - Press `j` or `Enter` to jump to a pane
95
+
96
+ 4. **Merge your work**
97
+ - Select the pane you want to merge
98
+ - Press `m` to merge into main branch
99
+ - Confirm to close the pane
100
+
101
+ ## Keyboard Shortcuts
102
+
103
+ | Key | Action |
104
+ |-----|--------|
105
+ | `↑/↓` | Navigate pane list |
106
+ | `Enter` or `j` | Jump to selected pane |
107
+ | `n` | Create new cmux pane |
108
+ | `m` | Merge worktree to main |
109
+ | `x` | Close selected pane |
110
+ | `q` | Quit cmux interface |
111
+ | `ESC` | Cancel current dialog |
112
+
113
+ ## Example Workflow
114
+
115
+ ```bash
116
+ # Start cmux in your project
117
+ cd ~/projects/my-app
118
+ cmux
119
+
120
+ # Create a pane for a new feature
121
+ # Press 'n', enter: "add user dashboard"
122
+ # Claude opens with your prompt
123
+
124
+ # Create another pane for a bug fix
125
+ # Press 'n', enter: "fix memory leak"
126
+ # Work on both simultaneously
127
+
128
+ # When feature is complete
129
+ # Select the pane, press 'm' to merge
130
+
131
+ # Jump between panes as needed
132
+ # Press 'j' on any pane to switch focus
133
+ ```
134
+
135
+ ## How It Works
136
+
137
+ 1. **Session Management**: Each project gets its own tmux session (`cmux-projectname`)
138
+ 2. **Worktree Creation**: New panes create git worktrees in sibling directories
139
+ 3. **Branch Management**: Automatic branch creation with AI-generated names
140
+ 4. **Claude Integration**: Launches Claude with `--accept-edits` for immediate coding
141
+ 5. **Smart Merging**: Auto-commits, generates messages, and cleans up worktrees
142
+
143
+ ## Project Structure
144
+
145
+ When you create panes, cmux organizes your work like this:
146
+
147
+ ```
148
+ my-project/ # Your main repository
149
+ ├── .git/
150
+ └── src/
151
+
152
+ my-project-fix-auth/ # Worktree for "fix authentication"
153
+ ├── .git # Worktree reference
154
+ └── src/ # Independent working copy
155
+
156
+ my-project-add-feature/ # Worktree for "add new feature"
157
+ ├── .git
158
+ └── src/
159
+ ```
160
+
161
+ ## Troubleshooting
162
+
163
+ ### Claude command not found
164
+ Install Claude Code CLI from [Claude Code documentation](https://claude.ai/code).
165
+
166
+ ### API features not working
167
+ ```bash
168
+ # Check your API key
169
+ echo $OPENROUTER_API_KEY
170
+
171
+ # If missing, add to your shell config
172
+ export OPENROUTER_API_KEY="your-key"
173
+ ```
174
+
175
+ ### Panes not appearing
176
+ - Ensure tmux version 3.0+: `tmux -V`
177
+ - Check git version 2.20+: `git --version`
178
+ - Verify write permissions in parent directory
179
+
180
+ ### Screen artifacts
181
+ Press `Ctrl+L` in the affected pane to clear the screen.
182
+
183
+ ## Tips
184
+
185
+ - **Use descriptive prompts** for better AI-generated branch names
186
+ - **Merge frequently** to keep your main branch updated
187
+ - **One feature per pane** for clean separation of work
188
+ - **Close unused panes** with `x` to keep the interface clean
189
+
190
+ ## tmux Configuration for Beginners
191
+
192
+ While cmux handles most tmux operations automatically, having a good tmux configuration can enhance your experience. This isn't the place to learn tmux comprehensively, but here's a helpful configuration to get you started.
193
+
194
+ ### Recommended tmux Configuration
195
+
196
+ Add this to your `~/.tmux.conf` file:
197
+
198
+ ```bash
199
+ # Visual distinction between active and inactive panes
200
+ set -g window-style 'fg=colour247,bg=colour236'
201
+ set -g window-active-style 'fg=default,bg=colour234'
202
+
203
+ # Pane borders
204
+ set -g pane-border-style "fg=colour238 bg=default"
205
+ set -g pane-active-border-style "fg=blue bg=default"
206
+
207
+ # Status bar styling
208
+ set -g status-style 'bg=colour236'
209
+
210
+ # Keyboard shortcuts for pane navigation
211
+ # Hold Ctrl+Shift and use arrow keys to move between panes
212
+ bind -n C-S-Left select-pane -L
213
+ bind -n C-S-Right select-pane -R
214
+ bind -n C-S-Up select-pane -U
215
+ bind -n C-S-Down select-pane -D
216
+
217
+ # Enable mouse support (click panes, resize with mouse)
218
+ set -g mouse on
219
+ ```
220
+
221
+ ### Key Features of This Configuration
222
+
223
+ - **Visual Feedback**: Active panes have a darker background and blue border
224
+ - **Easy Navigation**: Hold `Ctrl+Shift` and use arrow keys to switch between panes instantly
225
+ - **Mouse Support**: Click on panes to focus them, drag borders to resize
226
+
227
+ After adding this configuration, reload tmux:
228
+ ```bash
229
+ tmux source-file ~/.tmux.conf
230
+ ```
231
+
232
+ Or start a new tmux session for the changes to take effect.
233
+
234
+ ## Requirements Summary
235
+
236
+ - tmux ≥ 3.0
237
+ - Node.js ≥ 18
238
+ - Git ≥ 2.20
239
+ - Claude Code CLI
240
+ - OpenRouter API key (optional)
22
241
 
23
- ## Status
242
+ ## Support
24
243
 
25
- Currently in active development. Please check back later for the full release.
244
+ For issues or questions, please check the [full documentation](CLAUDE.md) or open an issue on GitHub.
26
245
 
27
246
  ## License
28
247
 
29
- MIT
248
+ [Your License Here]
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface DmuxAppProps {
3
+ dmuxDir: string;
4
+ panesFile: string;
5
+ projectName: string;
6
+ sessionName: string;
7
+ }
8
+ declare const DmuxApp: React.FC<DmuxAppProps>;
9
+ export default DmuxApp;
10
+ //# sourceMappingURL=DmuxApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DmuxApp.d.ts","sourceRoot":"","sources":["../src/DmuxApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAgBnD,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,QAAA,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAinBnC,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,503 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Text, useInput, useApp } from 'ink';
3
+ import TextInput from 'ink-text-input';
4
+ import { execSync } from 'child_process';
5
+ import fs from 'fs/promises';
6
+ import path from 'path';
7
+ const DmuxApp = ({ dmuxDir, panesFile, projectName, sessionName }) => {
8
+ const [panes, setPanes] = useState([]);
9
+ const [selectedIndex, setSelectedIndex] = useState(0);
10
+ const [showNewPaneDialog, setShowNewPaneDialog] = useState(false);
11
+ const [newPanePrompt, setNewPanePrompt] = useState('');
12
+ const [statusMessage, setStatusMessage] = useState('');
13
+ const [showMergeConfirmation, setShowMergeConfirmation] = useState(false);
14
+ const [mergedPane, setMergedPane] = useState(null);
15
+ const [showCloseOptions, setShowCloseOptions] = useState(false);
16
+ const [selectedCloseOption, setSelectedCloseOption] = useState(0);
17
+ const [closingPane, setClosingPane] = useState(null);
18
+ const [isCreatingPane, setIsCreatingPane] = useState(false);
19
+ const { exit } = useApp();
20
+ // Load panes on mount and refresh periodically
21
+ useEffect(() => {
22
+ loadPanes();
23
+ const interval = setInterval(loadPanes, 2000);
24
+ return () => clearInterval(interval);
25
+ }, []);
26
+ const loadPanes = async () => {
27
+ try {
28
+ const content = await fs.readFile(panesFile, 'utf-8');
29
+ const loadedPanes = JSON.parse(content);
30
+ // Filter out dead panes
31
+ const activePanes = loadedPanes.filter(pane => {
32
+ try {
33
+ execSync(`tmux list-panes -F '#{pane_id}' | grep -q '${pane.paneId}'`, {
34
+ stdio: 'pipe'
35
+ });
36
+ return true;
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ });
42
+ setPanes(activePanes);
43
+ // Save cleaned list
44
+ if (activePanes.length !== loadedPanes.length) {
45
+ await fs.writeFile(panesFile, JSON.stringify(activePanes, null, 2));
46
+ }
47
+ }
48
+ catch {
49
+ setPanes([]);
50
+ }
51
+ };
52
+ const savePanes = async (newPanes) => {
53
+ await fs.writeFile(panesFile, JSON.stringify(newPanes, null, 2));
54
+ setPanes(newPanes);
55
+ };
56
+ const generateSlug = async (prompt) => {
57
+ const apiKey = process.env.OPENROUTER_API_KEY;
58
+ if (!apiKey || !prompt) {
59
+ return `dmux-${Date.now()}`;
60
+ }
61
+ try {
62
+ const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
63
+ method: 'POST',
64
+ headers: {
65
+ 'Content-Type': 'application/json',
66
+ 'Authorization': `Bearer ${apiKey}`,
67
+ },
68
+ body: JSON.stringify({
69
+ model: 'openai/gpt-4o-mini',
70
+ messages: [
71
+ {
72
+ role: 'user',
73
+ content: `Generate a 1-2 word kebab-case slug for this prompt. Only respond with the slug, nothing else: "${prompt}"`
74
+ }
75
+ ],
76
+ max_tokens: 10,
77
+ temperature: 0.3
78
+ })
79
+ });
80
+ if (!response.ok) {
81
+ throw new Error(`OpenRouter API error: ${response.status}`);
82
+ }
83
+ const data = await response.json();
84
+ const slug = data.choices[0].message.content.trim().toLowerCase().replace(/[^a-z0-9-]/g, '');
85
+ return slug || `dmux-${Date.now()}`;
86
+ }
87
+ catch {
88
+ return `dmux-${Date.now()}`;
89
+ }
90
+ };
91
+ const createNewPane = async (prompt) => {
92
+ setIsCreatingPane(true);
93
+ setStatusMessage('Generating slug...');
94
+ const slug = await generateSlug(prompt);
95
+ setStatusMessage('Creating new pane...');
96
+ // Get current directory
97
+ const currentDir = process.cwd();
98
+ // Create worktree path
99
+ const worktreePath = path.join(currentDir, '..', `${path.basename(currentDir)}-${slug}`);
100
+ // Get the original pane ID (where dmux is running) before clearing
101
+ const originalPaneId = execSync('tmux display-message -p "#{pane_id}"', { encoding: 'utf-8' }).trim();
102
+ // Multiple clearing strategies to prevent artifacts
103
+ // 1. Clear screen with ANSI codes
104
+ process.stdout.write('\x1b[2J\x1b[H');
105
+ // 2. Fill with blank lines to push content off screen
106
+ process.stdout.write('\n'.repeat(100));
107
+ // 3. Clear tmux history and send clear command
108
+ try {
109
+ execSync('tmux clear-history', { stdio: 'pipe' });
110
+ execSync('tmux send-keys C-l', { stdio: 'pipe' });
111
+ }
112
+ catch { }
113
+ // Exit Ink app cleanly before creating tmux pane
114
+ exit();
115
+ // Wait for exit to complete
116
+ await new Promise(resolve => setTimeout(resolve, 500));
117
+ // 4. Force tmux to refresh the display
118
+ try {
119
+ execSync('tmux refresh-client', { stdio: 'pipe' });
120
+ }
121
+ catch { }
122
+ // Create new pane
123
+ const paneInfo = execSync(`tmux split-window -h -P -F '#{pane_id}'`, { encoding: 'utf-8' }).trim();
124
+ // Wait for pane creation to settle
125
+ await new Promise(resolve => setTimeout(resolve, 500));
126
+ // Resize panes evenly
127
+ execSync('tmux select-layout even-horizontal', { stdio: 'pipe' });
128
+ // Create git worktree and cd into it
129
+ try {
130
+ execSync(`tmux send-keys -t '${paneInfo}' 'git worktree add "${worktreePath}" -b ${slug}' Enter`, { stdio: 'pipe' });
131
+ execSync(`tmux send-keys -t '${paneInfo}' 'cd "${worktreePath}"' Enter`, { stdio: 'pipe' });
132
+ }
133
+ catch {
134
+ // Continue in current directory if worktree fails
135
+ }
136
+ // Prepare the Claude command
137
+ let claudeCmd;
138
+ if (prompt && prompt.trim()) {
139
+ const escapedPrompt = prompt
140
+ .replace(/\\/g, '\\\\')
141
+ .replace(/"/g, '\\"')
142
+ .replace(/`/g, '\\`')
143
+ .replace(/\$/g, '\\$');
144
+ claudeCmd = `claude "${escapedPrompt}" --permission-mode=acceptEdits`;
145
+ }
146
+ else {
147
+ claudeCmd = `claude --permission-mode=acceptEdits`;
148
+ }
149
+ // Send command to new pane
150
+ const escapedCmd = claudeCmd.replace(/'/g, "'\\''");
151
+ execSync(`tmux send-keys -t '${paneInfo}' '${escapedCmd}'`, { stdio: 'pipe' });
152
+ execSync(`tmux send-keys -t '${paneInfo}' Enter`, { stdio: 'pipe' });
153
+ // Keep focus on the new pane
154
+ execSync(`tmux select-pane -t '${paneInfo}'`, { stdio: 'pipe' });
155
+ // Save pane info
156
+ const newPane = {
157
+ id: `dmux-${Date.now()}`,
158
+ slug,
159
+ prompt: prompt ? (prompt.substring(0, 50) + (prompt.length > 50 ? '...' : '')) : 'No initial prompt',
160
+ paneId: paneInfo,
161
+ worktreePath
162
+ };
163
+ const updatedPanes = [...panes, newPane];
164
+ await fs.writeFile(panesFile, JSON.stringify(updatedPanes, null, 2));
165
+ // Switch back to the original pane (where cmux was running)
166
+ execSync(`tmux select-pane -t '${originalPaneId}'`, { stdio: 'pipe' });
167
+ // Re-launch dmux in the original pane
168
+ execSync(`tmux send-keys -t '${originalPaneId}' 'dmux' Enter`, { stdio: 'pipe' });
169
+ };
170
+ const jumpToPane = (paneId) => {
171
+ try {
172
+ execSync(`tmux select-pane -t '${paneId}'`, { stdio: 'pipe' });
173
+ setStatusMessage('Jumped to pane');
174
+ setTimeout(() => setStatusMessage(''), 2000);
175
+ }
176
+ catch {
177
+ setStatusMessage('Failed to jump - pane may be closed');
178
+ setTimeout(() => setStatusMessage(''), 2000);
179
+ }
180
+ };
181
+ const closePane = async (pane) => {
182
+ try {
183
+ // Kill the tmux pane
184
+ execSync(`tmux kill-pane -t '${pane.paneId}'`, { stdio: 'pipe' });
185
+ // Remove from list
186
+ const updatedPanes = panes.filter(p => p.id !== pane.id);
187
+ await savePanes(updatedPanes);
188
+ setStatusMessage(`Closed pane: ${pane.slug}`);
189
+ setTimeout(() => setStatusMessage(''), 3000);
190
+ }
191
+ catch {
192
+ setStatusMessage('Failed to close pane');
193
+ setTimeout(() => setStatusMessage(''), 2000);
194
+ }
195
+ };
196
+ const mergeAndPrune = async (pane) => {
197
+ if (!pane.worktreePath) {
198
+ setStatusMessage('No worktree to merge');
199
+ setTimeout(() => setStatusMessage(''), 2000);
200
+ return;
201
+ }
202
+ try {
203
+ setStatusMessage('Checking worktree status...');
204
+ // Get current branch
205
+ const mainBranch = execSync('git branch --show-current', { encoding: 'utf-8' }).trim();
206
+ // Check for uncommitted changes in the worktree
207
+ const statusOutput = execSync(`git -C "${pane.worktreePath}" status --porcelain`, { encoding: 'utf-8' });
208
+ if (statusOutput.trim()) {
209
+ setStatusMessage('Generating commit message...');
210
+ // Get the diff for uncommitted changes
211
+ const diffOutput = execSync(`git -C "${pane.worktreePath}" diff HEAD`, { encoding: 'utf-8' });
212
+ const statusDetails = execSync(`git -C "${pane.worktreePath}" status`, { encoding: 'utf-8' });
213
+ // Generate commit message using LLM
214
+ const commitMessage = await generateCommitMessage(`${statusDetails}\n\n${diffOutput}`);
215
+ setStatusMessage('Committing changes...');
216
+ // Stage all changes and commit with generated message
217
+ execSync(`git -C "${pane.worktreePath}" add -A`, { stdio: 'pipe' });
218
+ // Escape the commit message for shell
219
+ const escapedMessage = commitMessage.replace(/'/g, "'\\''");
220
+ execSync(`git -C "${pane.worktreePath}" commit -m '${escapedMessage}'`, { stdio: 'pipe' });
221
+ }
222
+ setStatusMessage('Merging into main...');
223
+ // Merge the worktree branch
224
+ execSync(`git merge ${pane.slug}`, { stdio: 'pipe' });
225
+ // Remove worktree
226
+ execSync(`git worktree remove "${pane.worktreePath}"`, { stdio: 'pipe' });
227
+ // Delete branch
228
+ execSync(`git branch -d ${pane.slug}`, { stdio: 'pipe' });
229
+ // Close the pane
230
+ await closePane(pane);
231
+ setStatusMessage(`Merged ${pane.slug} into ${mainBranch} and closed pane`);
232
+ setTimeout(() => setStatusMessage(''), 3000);
233
+ }
234
+ catch (error) {
235
+ setStatusMessage('Failed to merge - check git status');
236
+ setTimeout(() => setStatusMessage(''), 3000);
237
+ }
238
+ };
239
+ const deleteUnsavedChanges = async (pane) => {
240
+ if (!pane.worktreePath) {
241
+ // No worktree, just close the pane
242
+ await closePane(pane);
243
+ return;
244
+ }
245
+ try {
246
+ setStatusMessage('Removing worktree with unsaved changes...');
247
+ // Force remove worktree (discards uncommitted changes)
248
+ execSync(`git worktree remove --force "${pane.worktreePath}"`, { stdio: 'pipe' });
249
+ // Delete branch
250
+ try {
251
+ execSync(`git branch -D ${pane.slug}`, { stdio: 'pipe' });
252
+ }
253
+ catch {
254
+ // Branch might not exist or have commits, that's ok
255
+ }
256
+ // Close the pane
257
+ await closePane(pane);
258
+ setStatusMessage(`Deleted worktree ${pane.slug} and closed pane`);
259
+ setTimeout(() => setStatusMessage(''), 3000);
260
+ }
261
+ catch (error) {
262
+ setStatusMessage('Failed to delete worktree');
263
+ setTimeout(() => setStatusMessage(''), 3000);
264
+ }
265
+ };
266
+ const handleCloseOption = async (option, pane) => {
267
+ setShowCloseOptions(false);
268
+ setClosingPane(null);
269
+ setSelectedCloseOption(0);
270
+ switch (option) {
271
+ case 0: // Merge & Prune
272
+ await mergeAndPrune(pane);
273
+ break;
274
+ case 1: // Merge Only
275
+ await mergeWorktree(pane);
276
+ break;
277
+ case 2: // Delete Unsaved Changes
278
+ await deleteUnsavedChanges(pane);
279
+ break;
280
+ case 3: // Just Close
281
+ await closePane(pane);
282
+ break;
283
+ }
284
+ };
285
+ const generateCommitMessage = async (changes) => {
286
+ const apiKey = process.env.OPENROUTER_API_KEY;
287
+ if (!apiKey) {
288
+ return 'chore: merge worktree changes';
289
+ }
290
+ try {
291
+ const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
292
+ method: 'POST',
293
+ headers: {
294
+ 'Content-Type': 'application/json',
295
+ 'Authorization': `Bearer ${apiKey}`,
296
+ },
297
+ body: JSON.stringify({
298
+ model: 'openai/gpt-4o-mini',
299
+ messages: [
300
+ {
301
+ role: 'system',
302
+ content: 'You are a git commit message generator. Generate semantic commit messages following conventional commits format (feat:, fix:, docs:, style:, refactor:, test:, chore:). Be concise and specific.'
303
+ },
304
+ {
305
+ role: 'user',
306
+ content: `Generate a semantic commit message for these changes:\n\n${changes.substring(0, 3000)}`
307
+ }
308
+ ],
309
+ max_tokens: 100,
310
+ temperature: 0.3
311
+ })
312
+ });
313
+ if (!response.ok) {
314
+ throw new Error(`OpenRouter API error: ${response.status}`);
315
+ }
316
+ const data = await response.json();
317
+ const message = data.choices[0].message.content.trim();
318
+ return message || 'chore: merge worktree changes';
319
+ }
320
+ catch {
321
+ return 'chore: merge worktree changes';
322
+ }
323
+ };
324
+ const mergeWorktree = async (pane) => {
325
+ if (!pane.worktreePath) {
326
+ setStatusMessage('No worktree to merge');
327
+ setTimeout(() => setStatusMessage(''), 2000);
328
+ return;
329
+ }
330
+ try {
331
+ setStatusMessage('Checking worktree status...');
332
+ // Get current branch
333
+ const mainBranch = execSync('git branch --show-current', { encoding: 'utf-8' }).trim();
334
+ // Check for uncommitted changes in the worktree
335
+ const statusOutput = execSync(`git -C "${pane.worktreePath}" status --porcelain`, { encoding: 'utf-8' });
336
+ if (statusOutput.trim()) {
337
+ setStatusMessage('Staging changes...');
338
+ // Stage all changes first (including untracked files)
339
+ execSync(`git -C "${pane.worktreePath}" add -A`, { stdio: 'pipe' });
340
+ setStatusMessage('Generating commit message...');
341
+ // Get the diff of staged changes (after adding files)
342
+ const diffOutput = execSync(`git -C "${pane.worktreePath}" diff --cached`, { encoding: 'utf-8' });
343
+ const statusDetails = execSync(`git -C "${pane.worktreePath}" status`, { encoding: 'utf-8' });
344
+ // Generate commit message using LLM
345
+ const commitMessage = await generateCommitMessage(`${statusDetails}\n\n${diffOutput}`);
346
+ setStatusMessage('Committing changes...');
347
+ // Escape the commit message for shell
348
+ const escapedMessage = commitMessage.replace(/'/g, "'\\''");
349
+ execSync(`git -C "${pane.worktreePath}" commit -m '${escapedMessage}'`, { stdio: 'pipe' });
350
+ }
351
+ setStatusMessage('Merging into main...');
352
+ // Merge the worktree branch
353
+ execSync(`git merge ${pane.slug}`, { stdio: 'pipe' });
354
+ // Remove worktree
355
+ execSync(`git worktree remove "${pane.worktreePath}"`, { stdio: 'pipe' });
356
+ // Delete branch
357
+ execSync(`git branch -d ${pane.slug}`, { stdio: 'pipe' });
358
+ setStatusMessage(`Merged ${pane.slug} into ${mainBranch}`);
359
+ setTimeout(() => setStatusMessage(''), 3000);
360
+ // Show confirmation dialog to close the pane
361
+ setMergedPane(pane);
362
+ setShowMergeConfirmation(true);
363
+ }
364
+ catch (error) {
365
+ setStatusMessage('Failed to merge - check git status');
366
+ setTimeout(() => setStatusMessage(''), 3000);
367
+ }
368
+ };
369
+ useInput((input, key) => {
370
+ if (isCreatingPane) {
371
+ // Disable input while creating pane
372
+ return;
373
+ }
374
+ if (showNewPaneDialog) {
375
+ if (key.escape) {
376
+ setShowNewPaneDialog(false);
377
+ setNewPanePrompt('');
378
+ }
379
+ else if (key.return) {
380
+ createNewPane(newPanePrompt);
381
+ setShowNewPaneDialog(false);
382
+ setNewPanePrompt('');
383
+ }
384
+ return;
385
+ }
386
+ if (showMergeConfirmation) {
387
+ if (input === 'y' || input === 'Y') {
388
+ if (mergedPane) {
389
+ closePane(mergedPane);
390
+ }
391
+ setShowMergeConfirmation(false);
392
+ setMergedPane(null);
393
+ }
394
+ else if (input === 'n' || input === 'N' || key.escape) {
395
+ setShowMergeConfirmation(false);
396
+ setMergedPane(null);
397
+ }
398
+ return;
399
+ }
400
+ if (showCloseOptions) {
401
+ if (key.escape) {
402
+ setShowCloseOptions(false);
403
+ setClosingPane(null);
404
+ setSelectedCloseOption(0);
405
+ }
406
+ else if (key.upArrow) {
407
+ setSelectedCloseOption(Math.max(0, selectedCloseOption - 1));
408
+ }
409
+ else if (key.downArrow) {
410
+ setSelectedCloseOption(Math.min(3, selectedCloseOption + 1));
411
+ }
412
+ else if (key.return && closingPane) {
413
+ handleCloseOption(selectedCloseOption, closingPane);
414
+ }
415
+ return;
416
+ }
417
+ if (key.upArrow) {
418
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
419
+ }
420
+ else if (key.downArrow) {
421
+ setSelectedIndex(Math.min(panes.length, selectedIndex + 1));
422
+ }
423
+ else if (input === 'q') {
424
+ exit();
425
+ }
426
+ else if (input === 'n' || (key.return && selectedIndex === panes.length)) {
427
+ setShowNewPaneDialog(true);
428
+ }
429
+ else if (input === 'j' && selectedIndex < panes.length) {
430
+ jumpToPane(panes[selectedIndex].paneId);
431
+ }
432
+ else if (input === 'x' && selectedIndex < panes.length) {
433
+ setClosingPane(panes[selectedIndex]);
434
+ setShowCloseOptions(true);
435
+ setSelectedCloseOption(0);
436
+ }
437
+ else if (input === 'm' && selectedIndex < panes.length) {
438
+ mergeWorktree(panes[selectedIndex]);
439
+ }
440
+ else if (key.return && selectedIndex < panes.length) {
441
+ jumpToPane(panes[selectedIndex].paneId);
442
+ }
443
+ });
444
+ return (React.createElement(Box, { flexDirection: "column" },
445
+ React.createElement(Box, { marginBottom: 1 },
446
+ React.createElement(Text, { bold: true, color: "cyan" },
447
+ "dmux - ",
448
+ projectName)),
449
+ panes.map((pane, index) => (React.createElement(Box, { key: pane.id, paddingX: 1, borderStyle: "single", borderColor: selectedIndex === index ? 'cyan' : 'gray', marginBottom: 1 },
450
+ React.createElement(Box, { flexDirection: "column" },
451
+ React.createElement(Box, null,
452
+ React.createElement(Text, { color: selectedIndex === index ? 'cyan' : 'white', bold: true }, pane.slug),
453
+ pane.worktreePath && (React.createElement(Text, { color: "gray" }, " (worktree)"))),
454
+ React.createElement(Text, { color: "gray", dimColor: true }, pane.prompt))))),
455
+ React.createElement(Box, { paddingX: 1, borderStyle: "single", borderColor: selectedIndex === panes.length ? 'green' : 'gray', marginBottom: 1 },
456
+ React.createElement(Text, { color: selectedIndex === panes.length ? 'green' : 'white' }, "+ New dmux pane")),
457
+ showNewPaneDialog && (React.createElement(Box, { borderStyle: "double", borderColor: "cyan", paddingX: 1 },
458
+ React.createElement(Box, { flexDirection: "column" },
459
+ React.createElement(Text, null, "Enter initial Claude prompt (ESC to cancel):"),
460
+ React.createElement(TextInput, { value: newPanePrompt, onChange: setNewPanePrompt, placeholder: "Optional prompt..." })))),
461
+ isCreatingPane && (React.createElement(Box, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginTop: 1 },
462
+ React.createElement(Text, { color: "yellow" },
463
+ React.createElement(Text, { bold: true }, "\u23F3 Creating new pane... "),
464
+ statusMessage))),
465
+ showMergeConfirmation && mergedPane && (React.createElement(Box, { borderStyle: "double", borderColor: "yellow", paddingX: 1, marginTop: 1 },
466
+ React.createElement(Box, { flexDirection: "column" },
467
+ React.createElement(Text, { color: "yellow", bold: true }, "Worktree merged successfully!"),
468
+ React.createElement(Text, null,
469
+ "Close the pane \"",
470
+ mergedPane.slug,
471
+ "\"? (y/n)")))),
472
+ showCloseOptions && closingPane && (React.createElement(Box, { borderStyle: "double", borderColor: "red", paddingX: 1, marginTop: 1 },
473
+ React.createElement(Box, { flexDirection: "column" },
474
+ React.createElement(Text, { color: "red", bold: true },
475
+ "Close pane \"",
476
+ closingPane.slug,
477
+ "\"?"),
478
+ React.createElement(Text, { dimColor: true }, "Select an option (ESC to cancel):"),
479
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
480
+ React.createElement(Box, null,
481
+ React.createElement(Text, { color: selectedCloseOption === 0 ? 'cyan' : 'white' },
482
+ selectedCloseOption === 0 ? '▶ ' : ' ',
483
+ "Merge & Prune - Merge worktree to main and close")),
484
+ React.createElement(Box, null,
485
+ React.createElement(Text, { color: selectedCloseOption === 1 ? 'cyan' : 'white' },
486
+ selectedCloseOption === 1 ? '▶ ' : ' ',
487
+ "Merge Only - Merge worktree but keep pane open")),
488
+ React.createElement(Box, null,
489
+ React.createElement(Text, { color: selectedCloseOption === 2 ? 'cyan' : 'white' },
490
+ selectedCloseOption === 2 ? '▶ ' : ' ',
491
+ "Delete Unsaved - Remove worktree (discard changes)")),
492
+ React.createElement(Box, null,
493
+ React.createElement(Text, { color: selectedCloseOption === 3 ? 'cyan' : 'white' },
494
+ selectedCloseOption === 3 ? '▶ ' : ' ',
495
+ "Just Close - Close pane only")))))),
496
+ statusMessage && (React.createElement(Box, { marginTop: 1 },
497
+ React.createElement(Text, { color: "green" }, statusMessage))),
498
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
499
+ React.createElement(Text, { dimColor: true }, "Commands: [j]ump to pane \u2022 [x] close \u2022 [m]erge worktree \u2022 [n]ew pane \u2022 [q]uit"),
500
+ React.createElement(Text, { dimColor: true }, "Use \u2191\u2193 arrows to navigate, Enter to select"))));
501
+ };
502
+ export default DmuxApp;
503
+ //# sourceMappingURL=DmuxApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DmuxApp.js","sourceRoot":"","sources":["../src/DmuxApp.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'child_process';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs/promises';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { render } from 'ink';
8
+ import React from 'react';
9
+ import DmuxApp from './DmuxApp.js';
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ class Dmux {
12
+ dmuxDir;
13
+ panesFile;
14
+ projectName;
15
+ sessionName;
16
+ constructor() {
17
+ this.dmuxDir = path.join(process.env.HOME, '.dmux');
18
+ // Get project name from current directory
19
+ this.projectName = path.basename(process.cwd());
20
+ // Create unique session name for this project
21
+ this.sessionName = `dmux-${this.projectName}`;
22
+ // Store panes per project
23
+ this.panesFile = path.join(this.dmuxDir, `${this.projectName}-panes.json`);
24
+ }
25
+ async init() {
26
+ await fs.mkdir(this.dmuxDir, { recursive: true });
27
+ if (!await this.fileExists(this.panesFile)) {
28
+ await fs.writeFile(this.panesFile, '[]');
29
+ }
30
+ const inTmux = process.env.TMUX !== undefined;
31
+ if (!inTmux) {
32
+ // Check if project-specific session already exists
33
+ try {
34
+ execSync(`tmux has-session -t ${this.sessionName} 2>/dev/null`, { stdio: 'pipe' });
35
+ console.log(chalk.yellow(`Attaching to existing ${this.sessionName} session...`));
36
+ }
37
+ catch {
38
+ console.log(chalk.yellow(`Creating new tmux session for project: ${this.projectName}...`));
39
+ // Create new session first
40
+ execSync(`tmux new-session -d -s ${this.sessionName}`, { stdio: 'inherit' });
41
+ // Send dmux command to the new session
42
+ execSync(`tmux send-keys -t ${this.sessionName} "dmux" Enter`, { stdio: 'inherit' });
43
+ }
44
+ execSync(`tmux attach-session -t ${this.sessionName}`, { stdio: 'inherit' });
45
+ return;
46
+ }
47
+ // Launch the Ink app
48
+ render(React.createElement(DmuxApp, {
49
+ dmuxDir: this.dmuxDir,
50
+ panesFile: this.panesFile,
51
+ projectName: this.projectName,
52
+ sessionName: this.sessionName
53
+ }));
54
+ }
55
+ async fileExists(path) {
56
+ try {
57
+ await fs.access(path);
58
+ return true;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ }
65
+ const dmux = new Dmux();
66
+ dmux.init().catch(console.error);
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dmux ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('./dist/index.js');
package/package.json CHANGED
@@ -1,18 +1,71 @@
1
1
  {
2
2
  "name": "dmux",
3
- "version": "0.0.1",
4
- "description": "dmux - tmux pane manager with AI agent integration (placeholder package)",
5
- "main": "index.js",
6
- "scripts": {},
7
- "keywords": ["tmux", "pane", "manager", "ai", "development"],
8
- "author": "",
3
+ "version": "1.0.2",
4
+ "description": "Tmux pane manager with AI agent integration for parallel development workflows",
5
+ "type": "module",
6
+ "author": "Justin Schroeder",
9
7
  "license": "MIT",
8
+ "homepage": "https://github.com/justinschroeder/dmux#readme",
10
9
  "repository": {
11
10
  "type": "git",
12
- "url": "https://github.com/yourusername/dmux"
11
+ "url": "git+https://github.com/justinschroeder/dmux.git"
13
12
  },
14
13
  "bugs": {
15
- "url": "https://github.com/yourusername/dmux/issues"
14
+ "url": "https://github.com/justinschroeder/dmux/issues"
16
15
  },
17
- "homepage": "https://github.com/yourusername/dmux#readme"
16
+ "keywords": [
17
+ "tmux",
18
+ "claude",
19
+ "ai",
20
+ "development",
21
+ "worktree",
22
+ "git",
23
+ "terminal",
24
+ "cli"
25
+ ],
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "main": "./dist/index.js",
30
+ "exports": {
31
+ ".": {
32
+ "import": "./dist/index.js",
33
+ "types": "./dist/index.d.ts"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "dmux",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "bin": {
44
+ "dmux": "./dmux"
45
+ },
46
+ "dependencies": {
47
+ "chalk": "^5.3.0",
48
+ "ink": "^5.0.1",
49
+ "ink-text-input": "^6.0.0",
50
+ "react": "^18.2.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^20.10.5",
54
+ "@types/react": "^18.2.45",
55
+ "bumpp": "^10.2.3",
56
+ "npm-run-all2": "^8.0.4",
57
+ "tsx": "^4.7.0",
58
+ "typescript": "^5.3.3"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc",
62
+ "clean": "rm -rf dist",
63
+ "dev": "tsx src/index.ts",
64
+ "start": "node dist/index.js",
65
+ "typecheck": "tsc --noEmit",
66
+ "prerelease": "run-s clean typecheck build",
67
+ "release": "bumpp --commit --push --tag && pnpm publish",
68
+ "release:minor": "bumpp minor --commit --push --tag && pnpm publish",
69
+ "release:major": "bumpp major --commit --push --tag && pnpm publish"
70
+ }
18
71
  }
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- console.log('dmux - Package coming soon! This is a placeholder to reserve the npm package name.');
2
- console.log('dmux will be a tmux pane manager with AI agent integration.');
3
- console.log('For more information, please check back later.');