mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 14:39:42 +02:00
feat(ui): add 20-tab support and Claude CLI settings
- Increase max tab count from 10 to 20 - Fix header to properly expand for multiple tab rows (up to 4 rows) - Add scrollbar for tabs area when many tabs exist - Add Claude CLI startup mode setting (skip permissions/normal/allowed tools) - Reorganize settings modal into sections (CLI, Paths, Features) - Fix case select dropdown to fit content width - Create optimization todos document for future work Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+41
-43
@@ -283,12 +283,32 @@ class ClaudemanApp {
|
||||
}
|
||||
});
|
||||
|
||||
this.eventSource.addEventListener('session:clearTerminal', (e) => {
|
||||
this.eventSource.addEventListener('session:clearTerminal', async (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.id === this.activeSessionId) {
|
||||
// Clear terminal after screen attach to remove initialization blank space
|
||||
this.terminal.clear();
|
||||
this.terminal.reset();
|
||||
// Fetch buffer, clear terminal, write buffer, resize (no Ctrl+L needed)
|
||||
try {
|
||||
const res = await fetch(`/api/sessions/${data.id}/terminal`);
|
||||
const termData = await res.json();
|
||||
|
||||
this.terminal.clear();
|
||||
this.terminal.reset();
|
||||
if (termData.terminalBuffer) {
|
||||
this.terminal.write(termData.terminalBuffer);
|
||||
}
|
||||
|
||||
// Send resize to ensure proper dimensions
|
||||
const dims = this.fitAddon.proposeDimensions();
|
||||
if (dims) {
|
||||
await fetch(`/api/sessions/${data.id}/resize`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ cols: dims.cols, rows: dims.rows })
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('clearTerminal refresh failed:', err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -669,15 +689,6 @@ class ClaudemanApp {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ cols: dims.cols, rows: dims.rows })
|
||||
});
|
||||
// Send Ctrl+L to fix squished display after tab switch
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (session && session.mode !== 'shell') {
|
||||
fetch(`/api/sessions/${sessionId}/input`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ input: '\x0c' })
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update respawn banner
|
||||
@@ -858,7 +869,7 @@ class ClaudemanApp {
|
||||
incrementTabCount() {
|
||||
const input = document.getElementById('tabCount');
|
||||
const current = parseInt(input.value) || 1;
|
||||
input.value = Math.min(10, current + 1);
|
||||
input.value = Math.min(20, current + 1);
|
||||
}
|
||||
|
||||
decrementTabCount() {
|
||||
@@ -869,7 +880,7 @@ class ClaudemanApp {
|
||||
|
||||
async runClaude() {
|
||||
const caseName = document.getElementById('quickStartCase').value || 'testcase';
|
||||
const tabCount = Math.min(10, Math.max(1, parseInt(document.getElementById('tabCount').value) || 1));
|
||||
const tabCount = Math.min(20, Math.max(1, parseInt(document.getElementById('tabCount').value) || 1));
|
||||
|
||||
this.terminal.clear();
|
||||
this.terminal.writeln(`\x1b[1;32m Starting ${tabCount} Claude session(s) in ${caseName}...\x1b[0m`);
|
||||
@@ -947,35 +958,9 @@ class ClaudemanApp {
|
||||
this.terminal.writeln(`\x1b[90m Created session ${i}/${tabCount}: ${sessionName}\x1b[0m`);
|
||||
}
|
||||
|
||||
// Auto-switch to the new session
|
||||
// Auto-switch to the new session using selectSession (does proper refresh)
|
||||
if (firstSessionId) {
|
||||
// IMPORTANT: Clear terminal BEFORE setting activeSessionId
|
||||
// This prevents SSE events from writing during the transition
|
||||
this.terminal.clear();
|
||||
this.terminal.reset();
|
||||
|
||||
// Small delay to ensure terminal is fully reset before SSE events can write
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
// NOW set the active session so SSE events start populating
|
||||
this.activeSessionId = firstSessionId;
|
||||
this.renderSessionTabs();
|
||||
this.renderInnerStatePanel(); // Render Ralph panel if enabled globally
|
||||
|
||||
// Send resize to the new session
|
||||
const dims = this.fitAddon.proposeDimensions();
|
||||
if (dims) {
|
||||
await fetch(`/api/sessions/${firstSessionId}/resize`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ cols: dims.cols, rows: dims.rows })
|
||||
});
|
||||
}
|
||||
// Mark this session as needing Ctrl+L fix once Claude is running
|
||||
this.pendingCtrlL = this.pendingCtrlL || new Set();
|
||||
this.pendingCtrlL.add(firstSessionId);
|
||||
console.log('[DEBUG] Marked session for pending Ctrl+L:', firstSessionId);
|
||||
|
||||
await this.selectSession(firstSessionId);
|
||||
this.loadQuickStartCases();
|
||||
}
|
||||
|
||||
@@ -1664,6 +1649,16 @@ class ClaudemanApp {
|
||||
document.getElementById('appSettingsShowSystemStats').checked = settings.showSystemStats ?? true;
|
||||
document.getElementById('appSettingsShowTokenCount').checked = settings.showTokenCount ?? true;
|
||||
document.getElementById('appSettingsShowMonitor').checked = settings.showMonitor ?? true;
|
||||
// Claude CLI settings
|
||||
const claudeModeSelect = document.getElementById('appSettingsClaudeMode');
|
||||
const allowedToolsRow = document.getElementById('allowedToolsRow');
|
||||
claudeModeSelect.value = settings.claudeMode || 'dangerously-skip-permissions';
|
||||
document.getElementById('appSettingsAllowedTools').value = settings.allowedTools || '';
|
||||
allowedToolsRow.style.display = claudeModeSelect.value === 'allowedTools' ? '' : 'none';
|
||||
// Toggle allowed tools row visibility based on mode selection
|
||||
claudeModeSelect.onchange = () => {
|
||||
allowedToolsRow.style.display = claudeModeSelect.value === 'allowedTools' ? '' : 'none';
|
||||
};
|
||||
document.getElementById('appSettingsModal').classList.add('active');
|
||||
}
|
||||
|
||||
@@ -1681,6 +1676,9 @@ class ClaudemanApp {
|
||||
showSystemStats: document.getElementById('appSettingsShowSystemStats').checked,
|
||||
showTokenCount: document.getElementById('appSettingsShowTokenCount').checked,
|
||||
showMonitor: document.getElementById('appSettingsShowMonitor').checked,
|
||||
// Claude CLI settings
|
||||
claudeMode: document.getElementById('appSettingsClaudeMode').value,
|
||||
allowedTools: document.getElementById('appSettingsAllowedTools').value.trim(),
|
||||
};
|
||||
|
||||
// Save to localStorage
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
</button>
|
||||
<div class="tab-count-group" title="Number of tabs to open (1-10)">
|
||||
<button class="tab-count-btn" onclick="app.decrementTabCount()">−</button>
|
||||
<input type="number" id="tabCount" class="tab-count-input" value="1" min="1" max="10" readonly>
|
||||
<input type="number" id="tabCount" class="tab-count-input" value="1" min="1" max="20" readonly>
|
||||
<button class="tab-count-btn" onclick="app.incrementTabCount()">+</button>
|
||||
</div>
|
||||
<button class="btn-toolbar btn-shell" onclick="app.runShell()" title="Run Shell">
|
||||
@@ -479,7 +479,24 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-section">
|
||||
<div class="settings-section-title">General</div>
|
||||
<div class="settings-section-title">Claude CLI</div>
|
||||
<div class="form-row">
|
||||
<label>Startup Mode</label>
|
||||
<select id="appSettingsClaudeMode" class="form-select">
|
||||
<option value="dangerously-skip-permissions">Skip Permissions (default)</option>
|
||||
<option value="normal">Normal (with prompts)</option>
|
||||
<option value="allowedTools">Allowed Tools Only</option>
|
||||
</select>
|
||||
<span class="form-hint">How Claude CLI is started in screen sessions</span>
|
||||
</div>
|
||||
<div class="form-row" id="allowedToolsRow" style="display: none;">
|
||||
<label>Allowed Tools</label>
|
||||
<input type="text" id="appSettingsAllowedTools" placeholder="Read,Glob,Grep,Bash">
|
||||
<span class="form-hint">Comma-separated list of tools to allow (e.g., Read,Glob,Grep,Bash)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-section">
|
||||
<div class="settings-section-title">Paths & Defaults</div>
|
||||
<div class="form-row">
|
||||
<label>Default CLAUDE.md Template Path</label>
|
||||
<input type="text" id="appSettingsClaudeMdPath" placeholder="/path/to/CLAUDE.md template">
|
||||
@@ -490,6 +507,9 @@
|
||||
<input type="text" id="appSettingsDefaultDir" placeholder="~/projects">
|
||||
<span class="form-hint">Default directory for new sessions.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-section">
|
||||
<div class="settings-section-title">Features</div>
|
||||
<div class="form-row form-row-switch">
|
||||
<label>Enable Ralph Wiggum Tracker</label>
|
||||
<label class="switch">
|
||||
|
||||
+30
-10
@@ -42,9 +42,9 @@ body {
|
||||
/* Compact Header */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: var(--header-height);
|
||||
padding: 0 0.75rem;
|
||||
align-items: flex-start;
|
||||
min-height: var(--header-height);
|
||||
padding: 0.35rem 0.75rem;
|
||||
background: var(--bg-card);
|
||||
border-bottom: 1px solid var(--border);
|
||||
flex-shrink: 0;
|
||||
@@ -56,6 +56,8 @@ body {
|
||||
padding-right: 0.75rem;
|
||||
border-right: 1px solid var(--border);
|
||||
margin-right: 0.5rem;
|
||||
height: var(--header-height);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
@@ -68,12 +70,30 @@ body {
|
||||
/* Session Tabs */
|
||||
.session-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 2px;
|
||||
gap: 4px 2px;
|
||||
flex: 1;
|
||||
overflow-x: auto;
|
||||
padding: 0 0.25rem;
|
||||
overflow-y: auto;
|
||||
max-height: 120px;
|
||||
padding: 0.15rem 0.25rem;
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--border-light);
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar {
|
||||
@@ -1225,9 +1245,9 @@ body {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.4rem center;
|
||||
width: auto;
|
||||
min-width: 60px;
|
||||
max-width: 150px;
|
||||
width: fit-content;
|
||||
min-width: unset;
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
.toolbar-select:hover {
|
||||
|
||||
Reference in New Issue
Block a user