diff --git a/CLAUDE.md b/CLAUDE.md index f2f8220b..a7c66dc9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,7 +35,7 @@ When user says "COM": 1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version 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.1635 (must match `package.json`) +**Version**: 0.1636 (must match `package.json`) ## Project Overview diff --git a/package.json b/package.json index a31af170..10fa8657 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claudeman", - "version": "0.1635", + "version": "0.1636", "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/scripts/claudeman-web.service b/scripts/claudeman-web.service index 5564b993..597c9981 100644 --- a/scripts/claudeman-web.service +++ b/scripts/claudeman-web.service @@ -5,7 +5,7 @@ After=network.target [Service] Type=simple WorkingDirectory=/home/arkon/default/claudeman -ExecStart=/usr/bin/node dist/index.js web +ExecStart=/usr/bin/node dist/index.js web --https Restart=always RestartSec=5 KillMode=process diff --git a/src/web/public/app.js b/src/web/public/app.js index 16e36720..7575caae 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -610,6 +610,13 @@ const VoiceInput = { _accumulatedFinal: '', init() { + this._initRecognition(); + // Always show buttons — if unsupported, toggle() shows a toast + this._showButtons(); + }, + + /** Try to create a SpeechRecognition instance */ + _initRecognition() { const SR = window.SpeechRecognition || window.webkitSpeechRecognition; this.supported = !!SR; if (!this.supported) return; @@ -623,9 +630,6 @@ const VoiceInput = { this.recognition.onresult = (e) => this._onResult(e); this.recognition.onerror = (e) => this._onError(e); this.recognition.onend = () => this._onEnd(); - - // Show voice buttons now that we know it's supported - this._showButtons(); }, toggle() { @@ -637,7 +641,13 @@ const VoiceInput = { }, start() { - if (!this.supported || this.isRecording) return; + if (this.isRecording) return; + // Lazy-init: retry if recognition was cleaned up or not available at page load + if (!this.recognition) this._initRecognition(); + if (!this.supported) { + app.showToast('Voice input not supported in this browser', 'warning'); + return; + } if (!app.activeSessionId) { app.showToast('No active session', 'warning'); return; @@ -798,20 +808,20 @@ const VoiceInput = { desktopBtn.setAttribute('aria-label', isRecording ? 'Stop voice input' : 'Start voice input'); desktopBtn.title = isRecording ? 'Stop voice input (Ctrl+Shift+V)' : 'Voice input (Ctrl+Shift+V)'; } - // Mobile button (inside accessory bar) - const mobileBtn = document.querySelector('[data-action="voice"]'); - if (mobileBtn) { - mobileBtn.classList.toggle('recording', isRecording); - mobileBtn.setAttribute('aria-pressed', String(isRecording)); - mobileBtn.setAttribute('aria-label', isRecording ? 'Stop voice input' : 'Start voice input'); + // Mobile toolbar button (always visible on mobile) + const mobileToolbarBtn = document.getElementById('voiceInputBtnMobile'); + if (mobileToolbarBtn) { + mobileToolbarBtn.classList.toggle('recording', isRecording); + mobileToolbarBtn.setAttribute('aria-pressed', String(isRecording)); + mobileToolbarBtn.setAttribute('aria-label', isRecording ? 'Stop voice input' : 'Start voice input'); } }, _showButtons() { const desktopBtn = document.getElementById('voiceInputBtn'); if (desktopBtn) desktopBtn.style.display = ''; - const mobileBtn = document.querySelector('[data-action="voice"]'); - if (mobileBtn) mobileBtn.style.display = ''; + const mobileToolbarBtn = document.getElementById('voiceInputBtnMobile'); + if (mobileToolbarBtn) mobileToolbarBtn.style.display = ''; }, /** Cleanup on SSE reconnect or page unload */ @@ -863,16 +873,6 @@ const KeyboardAccessoryBar = { -