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 = {
-