diff --git a/CLAUDE.md b/CLAUDE.md index 5c11bca6..a9d44369 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ When user says "COM": 1. Increment version in BOTH `package.json` AND `CLAUDE.md` 2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web` -**Version**: 0.1451 (must match `package.json`) +**Version**: 0.1452 (must match `package.json`) ## Project Overview @@ -194,8 +194,12 @@ screen -r # Attach (Ctrl+A D to detach) curl localhost:3000/api/sessions # Check sessions curl localhost:3000/api/status | jq # Full app state cat ~/.claudeman/state.json | jq # View persisted state +curl localhost:3000/api/subagents # List background agents +curl localhost:3000/api/sessions/:id/run-summary | jq # Session timeline ``` +**Avoid port 3000 during E2E tests** - tests use ports 3183-3190 (see `test/e2e/e2e.config.ts`). + ## Performance Constraints The app must stay fast with 20 sessions and 50 agent windows: diff --git a/package.json b/package.json index 797f8d63..8194e563 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claudeman", - "version": "0.1451", + "version": "0.1452", "description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence", "type": "module", "main": "dist/index.js", diff --git a/src/web/public/app.js b/src/web/public/app.js index 54525a5a..2668b396 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -224,6 +224,9 @@ const KeyboardHandler = { // Focus event handling for scrolling inputs into view document.addEventListener('focusin', this.handleFocusIn.bind(this)); + + // Focusout handler to help reset state when leaving all inputs + document.addEventListener('focusout', this.handleFocusOut.bind(this)); }, /** Handle visualViewport resize - detect keyboard */ @@ -257,9 +260,14 @@ const KeyboardHandler = { this.isKeyboardVisible = visible; this.keyboardHeight = height; - // Update CSS custom property + // Update CSS custom properties document.documentElement.style.setProperty('--keyboard-height', `${height}px`); + // Reset viewport offset when keyboard closes + if (!visible) { + document.documentElement.style.setProperty('--viewport-offset-top', '0px'); + } + // Toggle class for CSS targeting document.body.classList.toggle('keyboard-visible', visible); @@ -280,6 +288,28 @@ const KeyboardHandler = { }, 350); }, + /** Handle focus leaving input elements - help reset keyboard state */ + handleFocusOut(e) { + if (!this.isInputElement(e.target)) return; + + // Small delay to check if focus moved to another input + setTimeout(() => { + const activeEl = document.activeElement; + // If focus left all inputs, ensure keyboard state is reset + if (!this.isInputElement(activeEl)) { + // The visualViewport resize event should handle this, + // but we reset just in case on iOS where it can be flaky + if (this.isKeyboardVisible && window.visualViewport) { + const vv = window.visualViewport; + const heightDiff = this.initialViewportHeight - vv.height; + if (heightDiff < 100) { + this.updateKeyboardState(false, 0); + } + } + } + }, 300); + }, + /** Check if element is an input that triggers keyboard */ isInputElement(el) { if (!el) return false; diff --git a/src/web/public/styles.css b/src/web/public/styles.css index 9563fc62..6a41e433 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -8420,10 +8420,7 @@ kbd { .keyboard-visible .modal-content { /* Don't take full height - resize with keyboard */ height: auto; - max-height: calc(100dvh - var(--keyboard-height) - var(--safe-area-top)); - /* Anchor to top */ - top: var(--safe-area-top); - bottom: auto; + max-height: calc(100dvh - var(--keyboard-height)); } .keyboard-visible .modal-body { @@ -8432,18 +8429,6 @@ kbd { overflow-y: auto; -webkit-overflow-scrolling: touch; } - - /* Ensure modal footer stays visible above keyboard */ - .keyboard-visible .modal-footer, - .keyboard-visible .wizard-footer, - .keyboard-visible .form-actions { - padding-bottom: 0.5rem; - } - - /* Smooth transition for keyboard appearance */ - .modal-content { - transition: max-height 0.2s ease-out, top 0.2s ease-out; - } } /* ============================================================================