From c058395c3e845d7669d11c4aa9f116831c4a00bf Mon Sep 17 00:00:00 2001 From: arkon Date: Mon, 19 Jan 2026 04:55:51 +0100 Subject: [PATCH] feat: improve UI - larger monitor, cleaner close modal, remove toolbar buttons - Monitor panel now 500px wide and 80vh max height - Removed Copy, Clear, Monitor, Kill buttons from toolbar - Redesigned close session modal with cleaner options: - "Remove Tab" keeps screen running - "Kill Claude" terminates completely - Auto-switch to new session when created Co-Authored-By: Claude Opus 4.5 --- CLAUDE.md | 108 ++++++-------------------------------- src/web/public/app.js | 14 +---- src/web/public/index.html | 27 +++++----- src/web/public/styles.css | 65 +++++++++++++++++++++-- 4 files changed, 93 insertions(+), 121 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d97647c4..47a54386 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -344,102 +344,24 @@ npx vitest run -t "should create session" # By pattern ### E2E Testing with agent-browser -For UI testing, we use [agent-browser](https://github.com/vercel-labs/agent-browser) - a fast CLI for browser automation optimized for AI agents. +For UI testing, use [agent-browser](https://github.com/vercel-labs/agent-browser). A full E2E test plan is documented in `.claude/skills/e2e-test.md`. -**Installation:** ```bash -npm install agent-browser --save-dev -npx agent-browser install # Download Chromium -``` +# Setup +npx agent-browser install # Download Chromium (one-time) +npx tsx src/index.ts web & # Start server -**Basic E2E Test Flow:** -```bash -# Start the server -npx tsx src/index.ts web & - -# Open browser +# Basic test flow npx agent-browser open http://localhost:3000 - -# Get page snapshot (shows accessibility tree with element refs) -npx agent-browser snapshot - -# Click elements by reference -npx agent-browser click @e5 # Click element with ref=e5 - -# Or use semantic locators -npx agent-browser find text "Run Claude" click -npx agent-browser find role button click --name "Monitor" - -# Fill inputs -npx agent-browser fill @e32 "my-session-name" - -# Execute JavaScript in page context -npx agent-browser eval "app.sessions.get(app.activeSessionId)" - -# Take screenshots -npx agent-browser screenshot /tmp/test-result.png - -# Close browser +npx agent-browser snapshot # Get accessibility tree with element refs +npx agent-browser click @e5 # Click by element ref +npx agent-browser find text "Run Claude" click # Or use semantic locators +npx agent-browser eval "app.sessions.get(app.activeSessionId)" # Run JS +npx agent-browser screenshot /tmp/test.png npx agent-browser close ``` -**E2E Test Skill (`.claude/skills/e2e-test.md`):** - -A skill file exists that documents the full E2E test plan. Key tests include: - -1. **Initial Load**: Verify header layout (font controls, connection status, tokens) -2. **Font Controls**: Test A-/A+ buttons change font size -3. **Tab Count Stepper**: Test −/+ buttons increment/decrement -4. **Session Creation**: Create session, verify screen wrapping -5. **Session Options Modal**: Open gear icon, verify respawn settings visible -6. **Monitor Panel**: Test Screen Sessions and Background Tasks display - -**Example Test Session:** -```bash -# Clean up previous screens -screen -ls | grep -oP '\d+\.claudeman-[a-z0-9]+' | while read s; do - screen -S "$s" -X quit -done - -# Start fresh server -rm -f ~/.claudeman/screens.json -npx tsx src/index.ts web & -sleep 4 - -# Run tests -npx agent-browser open http://localhost:3000 -npx agent-browser snapshot | head -30 # Check initial state -npx agent-browser click @e5 # Run Claude -sleep 4 -npx agent-browser snapshot # Verify session created - -# Check screen wrapping -screen -ls | grep claudeman # Should show screen session - -# Check session has PID -npx agent-browser eval "app.sessions.get(app.activeSessionId).pid" - -# Test session options -npx agent-browser eval "document.querySelector('[title=\"Session options\"]').click()" -npx agent-browser snapshot | grep -E "Respawn|Enable" # Should show respawn settings - -npx agent-browser screenshot /tmp/test-final.png -npx agent-browser close -``` - -**Key Commands:** -| Command | Description | -|---------|-------------| -| `open ` | Navigate to URL | -| `snapshot` | Get accessibility tree with element refs | -| `snapshot -i` | Interactive elements only | -| `click @ref` | Click element by ref | -| `fill @ref "text"` | Fill input field | -| `eval "js code"` | Execute JavaScript | -| `screenshot path` | Save screenshot | -| `find text/role/label "x" click` | Semantic element location | -| `wait 1000` | Wait milliseconds | -| `close` | Close browser | +**Key test areas:** Initial load, font controls (A-/A+), tab count stepper, session creation with screen wrapping, session options modal, monitor panel. ## Frontend @@ -449,8 +371,8 @@ The web UI (`src/web/public/`) uses vanilla JavaScript with: - **Server-Sent Events**: Real-time updates from `/api/events` - **No build step**: Static files served directly by Fastify -## Pending Tasks +## Notes -**Note to Claude: Do NOT remove or modify this section during /init. These tasks may be actively worked on by other sessions.** - - +- State persists to `~/.claudeman/state.json` and `~/.claudeman/screens.json` +- Cases are created in `~/claudeman-cases/` by default +- Sessions are wrapped in GNU screen for persistence across server restarts diff --git a/src/web/public/app.js b/src/web/public/app.js index 2532b0c7..5d9bfbf9 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -763,20 +763,10 @@ class ClaudemanApp { this.terminal.writeln(`\x1b[90m Created session ${i}/${tabCount}: ${sessionName}\x1b[0m`); } - // Select the first session + // Auto-switch to the new session if (firstSessionId) { - this.activeSessionId = firstSessionId; + await this.selectSession(firstSessionId); this.loadQuickStartCases(); - - // Send resize - 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 }) - }); - } } this.terminal.focus(); diff --git a/src/web/public/index.html b/src/web/public/index.html index 0d0aa185..ce649553 100644 --- a/src/web/public/index.html +++ b/src/web/public/index.html @@ -96,13 +96,7 @@
- - - - -
- - +
@@ -264,17 +258,24 @@ diff --git a/src/web/public/styles.css b/src/web/public/styles.css index 767a433e..05f08887 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -850,7 +850,7 @@ body { } .modal-content.modal-sm { - max-width: 320px; + max-width: 340px; } .modal-warning-text { @@ -859,6 +859,65 @@ body { margin-bottom: 0.5rem; } +/* Close Session Options */ +.close-options { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-bottom: 1rem; +} + +.close-option { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 0.75rem 1rem; + background: var(--bg-hover); + border: 1px solid var(--border); + border-radius: 6px; + cursor: pointer; + transition: all 0.15s; + text-align: left; +} + +.close-option:hover { + background: var(--bg-card); + border-color: var(--accent); +} + +.close-option-danger { + border-color: var(--red); + background: rgba(239, 68, 68, 0.1); +} + +.close-option-danger:hover { + background: rgba(239, 68, 68, 0.2); + border-color: var(--red); +} + +.close-option-title { + font-weight: 500; + font-size: 0.9rem; + color: var(--text); +} + +.close-option-danger .close-option-title { + color: var(--red); +} + +.close-option-desc { + font-size: 0.75rem; + color: var(--text-muted); + margin-top: 0.15rem; +} + +.modal-footer-cancel { + display: flex; + justify-content: center; + padding-top: 0.5rem; + border-top: 1px solid var(--border); +} + .modal-session-name { font-family: 'SF Mono', Monaco, monospace; font-size: 0.8rem; @@ -1420,9 +1479,9 @@ kbd { position: fixed; bottom: var(--toolbar-height); right: 0.5rem; - width: 420px; + width: 500px; max-width: calc(100vw - 1rem); - max-height: 60vh; + max-height: 80vh; background: var(--bg-card); border: 1px solid var(--border); border-bottom: none;