feat: voice mic, pixel life layer, enhanced transcript-debug UX

VoiceMicButton component, PixelLife aquatic layer, improved UserMessageBubble
with voice display, AgentBadge terminal switcher, ChatContainer voice integration,
FloatingTranscriptDebug ocean life enhancements, and terminal registry support.
Remove traefik config.
This commit is contained in:
2026-02-20 12:12:53 -06:00
parent b7f03a777b
commit 220d595568
19 changed files with 2221 additions and 358 deletions

View File

@@ -5,6 +5,7 @@ import Toolbar from './components/Toolbar.vue'
import TorchButton from './components/TorchButton.vue'
import FloatingTerminal from './components/FloatingTerminal.vue'
import FloatingResponse from './components/FloatingResponse.vue'
import { initWhisperSocket } from './services/whisperSocket'
import FloatingVoice from './components/FloatingVoice.vue'
import FloatingTranscriptDebug from './components/FloatingTranscriptDebug.vue'
import AgentBar from './components/AgentBar.vue'
@@ -70,6 +71,8 @@ function clearDebugLogs() {
const terminalRef = ref<InstanceType<typeof FloatingTerminal> | null>(null)
const responseRef = ref<InstanceType<typeof FloatingResponse> | null>(null)
const voiceRef = ref<InstanceType<typeof FloatingVoice> | null>(null)
const transcriptDebugRef = ref<InstanceType<typeof FloatingTranscriptDebug> | null>(null)
const mousePos = ref({ x: 0, y: 0 })
const canvasStore = useCanvasStore()
const projectCanvasStore = useProjectCanvasStore()
const { totalPending, modalVisible, connect: connectApproval, disconnect: disconnectApproval, fetchPending: fetchApprovalPending } = useGlobalApproval()
@@ -104,6 +107,21 @@ function hardRefresh() {
location.reload()
}
function trackMouse(e: MouseEvent) {
mousePos.value = { x: e.clientX, y: e.clientY }
}
function handleGlobalKeydown(e: KeyboardEvent) {
if (e.ctrlKey && e.key === 'e') {
e.preventDefault()
if (transcriptDebugRef.value) {
transcriptDebugRef.value.openAtCursor(mousePos.value.x, mousePos.value.y)
} else {
showTranscriptDebug.value = !showTranscriptDebug.value
}
}
}
// Voice FAB push-to-talk handlers
function handleVoiceFabClick() {
// If touch just ended, ignore click
@@ -273,6 +291,9 @@ onMounted(async () => {
connectApproval()
fetchApprovalPending()
// Initialize Whisper WebSocket connection early
initWhisperSocket()
// Fire torch connection early (don't await yet)
const torchReady = initTorch()
@@ -342,6 +363,12 @@ onMounted(async () => {
}
})
// Track mouse for Ctrl+E cursor-based opening
document.addEventListener('mousemove', trackMouse)
// Global keyboard shortcut: Ctrl+E toggles Transcript Debug
document.addEventListener('keydown', handleGlobalKeydown)
// Detect virtual keyboard on mobile
if (window.visualViewport) {
const initialHeight = window.visualViewport.height
@@ -357,6 +384,8 @@ onMounted(async () => {
})
onUnmounted(() => {
document.removeEventListener('mousemove', trackMouse)
document.removeEventListener('keydown', handleGlobalKeydown)
destroyTorch()
disconnectApproval()
if (statusReconnectTimeout) clearTimeout(statusReconnectTimeout)
@@ -577,7 +606,7 @@ watch(() => route.name, (newPage) => {
<FloatingVoice ref="voiceRef" v-model="showVoice" />
<!-- Floating Transcript Debug -->
<FloatingTranscriptDebug v-model="showTranscriptDebug" />
<FloatingTranscriptDebug ref="transcriptDebugRef" v-model="showTranscriptDebug" />
<!-- Global Hooks Approval Modal -->
<HooksApprovalModal />