feat: add terminal type selection in directory picker

Add CSS styling for the terminal type dropdown that was already
implemented in the JavaScript but wasn't visible due to missing styles.

The dropdown allows users to choose between:
- Standard Shell (bash/zsh) - default
- Claude Code CLI - runs claude --dangerously-skip-permissions

When Claude Code CLI is selected:
- Session picker is skipped (not needed)
- Terminal automatically launches with claude --dangerously-skip-permissions
- Mode is automatically set to 'session'

Changes:
- Add .terminal-type-selection, .terminal-type-select styles to terminal.css
- Match existing modal styling (background, borders, focus states)
- JavaScript was already implemented from previous work

Resolves: "Claude Code CLI still not appears under terminal > new terminal"

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
uroma
2026-01-19 18:22:11 +00:00
Unverified
parent df10f31f6c
commit 9e289cb0a1
2 changed files with 98 additions and 16 deletions

View File

@@ -284,12 +284,14 @@
}
.recent-directories,
.custom-directory {
.custom-directory,
.terminal-type-selection {
margin-bottom: 20px;
}
.recent-directories label,
.custom-directory label {
.custom-directory label,
.terminal-type-selection label {
display: block;
font-size: 13px;
font-weight: 600;
@@ -298,6 +300,28 @@
text-transform: uppercase;
}
.terminal-type-select {
width: 100%;
padding: 10px 12px;
background: #1a1a1a;
border: 1px solid #333;
border-radius: 6px;
color: #e0e0e0;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
}
.terminal-type-select:hover {
border-color: #555;
}
.terminal-type-select:focus {
outline: none;
border-color: #4a9eff;
box-shadow: 0 0 0 3px rgba(74, 158, 255, 0.1);
}
.directory-list {
display: flex;
flex-direction: column;

View File

@@ -166,19 +166,25 @@ class TerminalManager {
sessionId = null,
mode = 'mixed',
silent = false,
skipSessionPicker = false
skipSessionPicker = false,
terminalType = null
} = options;
// Show directory picker if no working directory provided
const selectedDir = workingDir || await this.showDirectoryPicker();
const selection = workingDir
? { directory: workingDir, terminalType: terminalType || 'standard' }
: await this.showDirectoryPicker();
if (!selectedDir) {
if (!selection) {
return null;
}
const { directory: selectedDir, terminalType: selectedTerminalType } = selection;
// If no session provided and not skipping picker, show session picker
let sessionSelection = null;
if (!sessionId && !skipSessionPicker) {
if (!sessionId && !skipSessionPicker && selectedTerminalType !== 'claude-cli') {
// Skip session picker if Claude Code CLI terminal is selected
sessionSelection = await this.showSessionPicker();
// If user cancelled session picker, still create terminal but without session
// sessionSelection will be null or { sessionId: string, source: 'web'|'local' } or { sessionId: 'new', source: 'new' }
@@ -213,21 +219,36 @@ class TerminalManager {
// Switch to new terminal
this.switchToTerminal(terminalId);
// Auto-launch Claude CLI if session was selected
if (sessionSelection && sessionSelection.sessionId) {
// Handle terminal type specific initialization
if (selectedTerminalType === 'claude-cli') {
// Wait a moment for terminal to be ready
await new Promise(resolve => setTimeout(resolve, 500));
// Launch Claude CLI with skip permissions flag
await this.launchCommand(terminalId, 'claude --dangerously-skip-permissions\n');
await this.setMode(terminalId, 'session');
if (!silent) {
showToast('Claude Code CLI terminal created', 'success');
}
} else if (sessionSelection && sessionSelection.sessionId) {
// Auto-launch Claude CLI if session was selected
if (sessionSelection.sessionId !== 'new') {
await this.launchClaudeCLI(terminalId, sessionSelection.sessionId, sessionSelection.source);
} else {
// Launch Claude CLI without session for new session
await this.launchClaudeCLI(terminalId, null, 'new');
}
}
if (!silent) {
const sessionMsg = sessionSelection && sessionSelection.sessionId && sessionSelection.sessionId !== 'new'
? ` with ${sessionSelection.source === 'local' ? 'local' : ''} session ${sessionSelection.sessionId.substring(0, 12)}`
: sessionSelection && sessionSelection.sessionId === 'new' ? ' (New Session)' : '';
showToast(`Terminal created${sessionMsg}`, 'success');
if (!silent) {
const sessionMsg = sessionSelection && sessionSelection.sessionId && sessionSelection.sessionId !== 'new'
? ` with ${sessionSelection.source === 'local' ? 'local' : ''} session ${sessionSelection.sessionId.substring(0, 12)}`
: sessionSelection && sessionSelection.sessionId === 'new' ? ' (New Session)' : '';
showToast(`Terminal created${sessionMsg}`, 'success');
}
} else {
if (!silent) {
showToast('Terminal created', 'success');
}
}
return terminalId;
@@ -281,6 +302,17 @@ class TerminalManager {
<label>Custom Path</label>
<input type="text" class="directory-input" placeholder="Enter absolute path..." value="${escapeHtml(recentDirs[0])}">
</div>
<div class="terminal-type-selection">
<label>Terminal Type</label>
<select class="terminal-type-select">
<option value="standard">Standard Shell (bash/zsh)</option>
<option value="claude-cli">Claude Code CLI (with --dangerously-skip-permissions)</option>
</select>
<small style="display: block; margin-top: 0.5rem; color: var(--text-secondary);">
Standard Shell: Regular terminal with bash/zsh<br>
Claude Code CLI: Automatically starts with claude --dangerously-skip-permissions
</small>
</div>
</div>
<div class="modal-footer">
<button class="btn-secondary btn-cancel">Cancel</button>
@@ -293,8 +325,10 @@ class TerminalManager {
setTimeout(() => modal.classList.add('visible'), 10);
const input = modal.querySelector('.directory-input');
const terminalTypeSelect = modal.querySelector('.terminal-type-select');
const createBtn = modal.querySelector('.btn-create');
let selectedDir = recentDirs[0];
let selectedTerminalType = 'standard';
// Handle directory selection
modal.querySelectorAll('.directory-item').forEach(item => {
@@ -311,17 +345,22 @@ class TerminalManager {
selectedDir = input.value;
});
// Handle terminal type selection
terminalTypeSelect.addEventListener('change', () => {
selectedTerminalType = terminalTypeSelect.value;
});
// Handle enter key
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
resolve(selectedDir);
resolve({ directory: selectedDir, terminalType: selectedTerminalType });
cleanup();
}
});
// Handle create
createBtn.addEventListener('click', () => {
resolve(selectedDir);
resolve({ directory: selectedDir, terminalType: selectedTerminalType });
cleanup();
});
@@ -583,6 +622,25 @@ class TerminalManager {
}
}
/**
* Launch a command in the terminal
*/
async launchCommand(terminalId, command) {
const terminal = this.terminals.get(terminalId);
if (!terminal || !terminal.ws || terminal.ws.readyState !== WebSocket.OPEN) {
console.error('[TerminalManager] Terminal not ready for command launch');
return;
}
// Send command to terminal
terminal.ws.send(JSON.stringify({
type: 'input',
data: command
}));
console.log(`[TerminalManager] Launched command in terminal ${terminalId}: ${command.trim()}`);
}
/**
* Extract project name from session metadata
*/