@adiontaegerron/claude-multi-terminal 1.0.3 → 1.2.0
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/.claude/settings.local.json +3 -1
- package/README.md +32 -1
- package/index.html +42 -37
- package/main.js +16 -12
- package/package.json +1 -1
- package/renderer.js +811 -15
- package/style.css +236 -90
package/README.md
CHANGED
@@ -9,7 +9,14 @@ A multi-terminal editor for coordinating multiple Claude Code instances. Run mul
|
|
9
9
|
- **Multi-Terminal Support**: Run multiple Claude Code instances in a 2x2 grid layout
|
10
10
|
- **Unified Chat Interface**: Send commands to selected terminals from a single chat interface
|
11
11
|
- **Terminal Selection**: Choose which terminals receive your commands with checkboxes
|
12
|
+
- **Multi-@ Terminal Commands**: Send commands to multiple terminals with various syntaxes:
|
13
|
+
- `@all command` - Send to all terminals
|
14
|
+
- `@term1,term2,term3 command` - Comma-separated terminals
|
15
|
+
- `@term1 @term2 command` - Space-separated terminals
|
16
|
+
- **Smart Autocomplete**: Get terminal suggestions while typing @ anywhere in your message
|
17
|
+
- **Slash Commands**: Built-in commands for terminal management
|
12
18
|
- **Default Prompt**: Set a default prompt to prepend to all messages
|
19
|
+
- **Plan Mode Support**: Automatically enters plan mode with Shift+Tab
|
13
20
|
- **Auto-Start Claude**: Each terminal automatically starts Claude Code
|
14
21
|
- **Rename Terminals**: Double-click terminal titles to rename them
|
15
22
|
- **Responsive Layout**: Adapts to different screen sizes
|
@@ -49,12 +56,36 @@ This will open the multi-terminal editor with all terminals starting in your cur
|
|
49
56
|
4. **Send Commands**: Type in the chat input and click "Send" or press Enter
|
50
57
|
5. **Use Default Prompt**: Expand the "Default Prompt" section to set a prompt that's prepended to all messages
|
51
58
|
|
59
|
+
### Slash Commands
|
60
|
+
|
61
|
+
- `/send <terminal> <command>` - Send command to specific terminal
|
62
|
+
- `/send-all <command>` or `/broadcast <command>` - Send to all terminals
|
63
|
+
- `/list` - List all terminals
|
64
|
+
- `/create [name]` - Create new terminal with optional name
|
65
|
+
- `/close <terminal>` - Close specific terminal
|
66
|
+
- `/return <terminal>` - Submit current input in terminal (press Enter)
|
67
|
+
- `/clear <terminal>` or `/interrupt <terminal>` - Send Ctrl+C to terminal
|
68
|
+
- `/help` - Show available commands
|
69
|
+
|
70
|
+
### @ Terminal Commands
|
71
|
+
|
72
|
+
Send commands directly to terminals using @ syntax:
|
73
|
+
|
74
|
+
- `@Terminal1 ls -la` - Send to single terminal
|
75
|
+
- `@"My Terminal" pwd` - Terminal with spaces in name
|
76
|
+
- `@term1,term2,term3 date` - Multiple terminals (comma-separated)
|
77
|
+
- `@term1 @term2 @term3 whoami` - Multiple terminals (space-separated)
|
78
|
+
- `@all echo "Hello"` - Send to all terminals
|
79
|
+
|
80
|
+
**Autocomplete**: Type `@` anywhere to get terminal suggestions!
|
81
|
+
|
52
82
|
### Tips
|
53
83
|
|
54
84
|
- Each terminal automatically starts Claude Code when created
|
55
|
-
-
|
85
|
+
- Plan mode is activated automatically using Shift+Tab
|
56
86
|
- Double-click terminal titles to rename them for better organization
|
57
87
|
- The application uses your current directory as the working directory for all terminals
|
88
|
+
- Use multi-@ commands to coordinate multiple Claude instances efficiently
|
58
89
|
|
59
90
|
## Development
|
60
91
|
|
package/index.html
CHANGED
@@ -12,49 +12,54 @@
|
|
12
12
|
<button id="new-terminal-btn">New Terminal</button>
|
13
13
|
</div>
|
14
14
|
|
15
|
-
<div id="
|
16
|
-
<div
|
17
|
-
<div id="
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
<div id="chat-sidebar">
|
23
|
-
<div class="chat-header">
|
24
|
-
<h2>Chat</h2>
|
25
|
-
</div>
|
26
|
-
|
27
|
-
<div id="chat-messages">
|
28
|
-
<!-- Chat messages will appear here -->
|
15
|
+
<div id="toolbar-extended">
|
16
|
+
<div class="controls-row">
|
17
|
+
<div id="terminal-selector" class="control-section">
|
18
|
+
<label>Send to:</label>
|
19
|
+
<div id="terminal-checkboxes">
|
20
|
+
<!-- Terminal checkboxes will be added here dynamically -->
|
21
|
+
</div>
|
29
22
|
</div>
|
30
23
|
|
31
|
-
<div id="
|
32
|
-
<div
|
33
|
-
<
|
34
|
-
<
|
35
|
-
<!-- Terminal checkboxes will be added here dynamically -->
|
36
|
-
</div>
|
24
|
+
<div id="default-prompt-section" class="control-section collapsible">
|
25
|
+
<div class="collapsible-header">
|
26
|
+
<button class="collapse-toggle">▶</button>
|
27
|
+
<span>Default Prompt</span>
|
37
28
|
</div>
|
38
|
-
|
39
|
-
|
40
|
-
<
|
41
|
-
<
|
42
|
-
<span>
|
43
|
-
</
|
44
|
-
<div class="collapsible-content" style="display: none;">
|
45
|
-
<textarea id="default-prompt-text" placeholder="Enter default prompt to prepend to all messages..."></textarea>
|
46
|
-
<label>
|
47
|
-
<input type="checkbox" id="use-default-prompt" />
|
48
|
-
<span>Always prepend to messages</span>
|
49
|
-
</label>
|
50
|
-
</div>
|
29
|
+
<div class="collapsible-content" style="display: none;">
|
30
|
+
<textarea id="default-prompt-text" placeholder="Enter default prompt to prepend to all messages..."></textarea>
|
31
|
+
<label>
|
32
|
+
<input type="checkbox" id="use-default-prompt" />
|
33
|
+
<span>Always prepend to messages</span>
|
34
|
+
</label>
|
51
35
|
</div>
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<div class="plan-mode-row">
|
40
|
+
<label class="plan-mode-option">
|
41
|
+
<input type="checkbox" id="use-plan-mode" checked />
|
42
|
+
<span>Send in Plan Mode</span>
|
43
|
+
</label>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
<div class="input-row">
|
47
|
+
<div class="input-wrapper">
|
48
|
+
<div id="input-overlay" class="input-overlay"></div>
|
49
|
+
<textarea id="chat-input" placeholder="Type your message, / for commands, or @terminal for direct send..."></textarea>
|
50
|
+
<div id="command-dropdown" class="command-dropdown" style="display: none;">
|
51
|
+
<div id="command-list" class="command-list">
|
52
|
+
<!-- Command options will be populated here -->
|
53
|
+
</div>
|
56
54
|
</div>
|
57
55
|
</div>
|
56
|
+
<button id="send-message-btn">Send</button>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<div id="terminals-area">
|
61
|
+
<div id="terminals-container">
|
62
|
+
<!-- Terminal instances will be added here dynamically -->
|
58
63
|
</div>
|
59
64
|
</div>
|
60
65
|
</div>
|
package/main.js
CHANGED
@@ -33,7 +33,7 @@ function createWindow() {
|
|
33
33
|
|
34
34
|
mainWindow.on('closed', () => {
|
35
35
|
// Clean up all terminals on window close
|
36
|
-
terminals.forEach(
|
36
|
+
terminals.forEach(termData => termData.pty.kill());
|
37
37
|
terminals.clear();
|
38
38
|
mainWindow = null;
|
39
39
|
});
|
@@ -68,7 +68,10 @@ ipcMain.handle('terminal:create', (event, terminalId) => {
|
|
68
68
|
env: process.env
|
69
69
|
});
|
70
70
|
|
71
|
-
|
71
|
+
// Store terminal
|
72
|
+
terminals.set(terminalId, {
|
73
|
+
pty: ptyProcess
|
74
|
+
});
|
72
75
|
|
73
76
|
// Forward terminal output to renderer
|
74
77
|
ptyProcess.onData((data) => {
|
@@ -86,9 +89,9 @@ ipcMain.handle('terminal:create', (event, terminalId) => {
|
|
86
89
|
|
87
90
|
// Write data to terminal
|
88
91
|
ipcMain.handle('terminal:write', (event, terminalId, data) => {
|
89
|
-
const
|
90
|
-
if (
|
91
|
-
|
92
|
+
const terminalData = terminals.get(terminalId);
|
93
|
+
if (terminalData) {
|
94
|
+
terminalData.pty.write(data);
|
92
95
|
return { success: true };
|
93
96
|
}
|
94
97
|
return { success: false, error: 'Terminal not found' };
|
@@ -96,9 +99,9 @@ ipcMain.handle('terminal:write', (event, terminalId, data) => {
|
|
96
99
|
|
97
100
|
// Resize terminal
|
98
101
|
ipcMain.handle('terminal:resize', (event, terminalId, cols, rows) => {
|
99
|
-
const
|
100
|
-
if (
|
101
|
-
|
102
|
+
const terminalData = terminals.get(terminalId);
|
103
|
+
if (terminalData) {
|
104
|
+
terminalData.pty.resize(cols, rows);
|
102
105
|
return { success: true };
|
103
106
|
}
|
104
107
|
return { success: false, error: 'Terminal not found' };
|
@@ -106,11 +109,12 @@ ipcMain.handle('terminal:resize', (event, terminalId, cols, rows) => {
|
|
106
109
|
|
107
110
|
// Close terminal
|
108
111
|
ipcMain.handle('terminal:close', (event, terminalId) => {
|
109
|
-
const
|
110
|
-
if (
|
111
|
-
|
112
|
+
const terminalData = terminals.get(terminalId);
|
113
|
+
if (terminalData) {
|
114
|
+
terminalData.pty.kill();
|
112
115
|
terminals.delete(terminalId);
|
113
116
|
return { success: true };
|
114
117
|
}
|
115
118
|
return { success: false, error: 'Terminal not found' };
|
116
|
-
});
|
119
|
+
});
|
120
|
+
|