refactor(app): remove debug logging from voice and UI components

This commit is contained in:
Mohamed Boudra
2026-03-13 21:07:18 +07:00
parent 80a2f8052c
commit 502dd2d2e2
28 changed files with 56 additions and 1288 deletions
@@ -18,41 +18,27 @@ export interface AudioCaptureConfig {
*/
async function getActualRecordingUri(createdAt: Date): Promise<string | null> {
try {
console.log('[AudioRecorder] Searching for recording file created at:', createdAt.toISOString());
const audioDir = new Directory(Paths.cache, 'Audio');
console.log('[AudioRecorder] Audio cache directory URI:', audioDir.uri);
console.log('[AudioRecorder] Directory exists:', audioDir.exists);
if (!audioDir.exists) {
console.log('[AudioRecorder] Audio cache directory does not exist');
return null;
}
const files = audioDir.list();
console.log('[AudioRecorder] Found files in Audio cache:', files.length);
if (!files.length) {
console.log('[AudioRecorder] No files found in Audio cache directory');
return null;
}
const validFiles = files
.map(file => {
const info = file.info();
console.log('[AudioRecorder] File info:', {
uri: info.uri,
size: info.size,
creationTime: info.creationTime ? new Date(info.creationTime).toISOString() : null,
});
return info;
})
.filter(f => f.size && f.size > 0);
console.log('[AudioRecorder] Valid files (size > 0):', validFiles.length);
if (validFiles.length === 0) {
console.log('[AudioRecorder] No valid files found (all are zero-byte)');
return null;
}
@@ -62,10 +48,6 @@ async function getActualRecordingUri(createdAt: Date): Promise<string | null> {
for (const file of validFiles) {
if (!file.creationTime || !file.uri) continue;
const diff = Math.abs(file.creationTime - createdAt.getTime());
console.log('[AudioRecorder] Time diff for file:', {
uri: file.uri,
diffMs: diff,
});
if (diff < minDiff) {
closest = file;
minDiff = diff;
@@ -74,15 +56,9 @@ async function getActualRecordingUri(createdAt: Date): Promise<string | null> {
if (closest) {
const resultUri = closest.uri?.slice(0, -1) ?? null;
console.log('[AudioRecorder] Found closest file:', {
uri: resultUri,
size: closest.size,
timeDiffMs: minDiff,
});
return resultUri;
}
console.log('[AudioRecorder] No closest file found');
return null;
} catch (e) {
console.error('[AudioRecorder] Error finding actual recording file:', e);
@@ -208,7 +184,6 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
attemptGuardRef.current.assertCurrent(attemptId);
// Request microphone permissions
console.log('[AudioRecorder] Requesting recording permissions...');
const permissionResponse = await requestRecordingPermissionsAsync();
attemptGuardRef.current.assertCurrent(attemptId);
@@ -217,38 +192,26 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
}
// Configure audio mode for recording
console.log('[AudioRecorder] Configuring audio mode...');
await setAudioModeAsync({
playsInSilentMode: true,
allowsRecording: true,
});
attemptGuardRef.current.assertCurrent(attemptId);
console.log('[AudioRecorder] Starting recording with options:', {
sampleRate: recordingOptions.sampleRate,
numberOfChannels: recordingOptions.numberOfChannels,
bitRate: recordingOptions.bitRate,
});
const startTime = new Date();
setRecordingStartTime(startTime);
attemptGuardRef.current.assertCurrent(attemptId);
// Prepare the recorder before recording (required step)
console.log('[AudioRecorder] Preparing recorder...');
await recorder.prepareToRecordAsync();
attemptGuardRef.current.assertCurrent(attemptId);
console.log('[AudioRecorder] Starting recording...');
await recorder.record();
attemptGuardRef.current.assertCurrent(attemptId);
console.log('[AudioRecorder] Recording started at:', startTime.toISOString());
console.log('[AudioRecorder] Recorder isRecording:', recorder.isRecording);
} catch (error: any) {
setRecordingStartTime(null);
if (error instanceof AttemptCancelledError) {
console.log('[AudioRecorder] Recording start cancelled.');
return;
}
if (error?.message !== 'Recording cancelled') {
@@ -278,15 +241,12 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
// Get URI from recorder
let uri = recorder.uri;
console.log('[AudioRecorder] Initial URI from recorder:', uri);
// Workaround for Expo SDK 54 Android bug - find actual recording file
if (recordingStartTime && (!uri || uri === '')) {
console.log('[AudioRecorder] Using workaround to find actual recording file...');
const actualUri = await getActualRecordingUri(recordingStartTime);
if (actualUri) {
uri = actualUri;
console.log('[AudioRecorder] Found actual recording URI:', uri);
}
}
@@ -299,7 +259,6 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
// Get file info
const file = new File(uri);
const exists = file.exists;
console.log('[AudioRecorder] File exists:', exists);
if (!exists) {
setRecordingStartTime(null);
@@ -309,11 +268,6 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
// Convert URI to Blob
const audioBlob = await uriToBlob(uri);
console.log('[AudioRecorder] Recording converted to blob:', {
size: audioBlob.size,
type: audioBlob.type,
});
// Clean up the temporary file
file.delete();
@@ -163,16 +163,6 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
throw new Error("Microphone capture is not supported in this environment");
}
console.log("[AudioRecorder][Web] Microphone preflight", {
secureContext,
currentOrigin,
isTauri,
hasMediaDevices:
typeof navigator !== "undefined" &&
!!navigator.mediaDevices &&
typeof navigator.mediaDevices.getUserMedia === "function",
});
if (!secureContext && !isTauri) {
throw new Error(
`Microphone access requires HTTPS or localhost. Current origin: ${currentOrigin}`
@@ -6,53 +6,18 @@ import { createAudioEngine } from "@/voice/audio-engine";
import type { DictationAudioSource, DictationAudioSourceConfig } from "./use-dictation-audio-source.types";
let nextDictationAudioSourceInstanceId = 1;
function getDictationTraceStack(): string | undefined {
const stack = new Error().stack;
if (!stack) {
return undefined;
}
return stack
.split("\n")
.slice(2, 7)
.map((line) => line.trim())
.join(" | ");
}
export function useDictationAudioSource(config: DictationAudioSourceConfig): DictationAudioSource {
const onPcmSegmentRef = useRef(config.onPcmSegment);
const onErrorRef = useRef(config.onError);
const [volume, setVolume] = useState(0);
const sourceIdRef = useRef<number | null>(null);
const engineRef = useRef<ReturnType<typeof createAudioEngine> | null>(null);
if (sourceIdRef.current === null) {
sourceIdRef.current = nextDictationAudioSourceInstanceId++;
console.log("[DictationAudioSource] instance_created", {
sourceId: sourceIdRef.current,
stack: getDictationTraceStack(),
});
}
const sourceId = sourceIdRef.current;
console.log("[DictationAudioSource] render", {
sourceId,
hasEngine: Boolean(engineRef.current),
});
const getOrCreateEngine = useCallback(() => {
if (engineRef.current) {
return engineRef.current;
}
console.log("[DictationAudioSource] create_engine", {
sourceId,
stack: getDictationTraceStack(),
});
engineRef.current = createAudioEngine(
{
engineRef.current = createAudioEngine({
onCaptureData: (pcm) => {
onPcmSegmentRef.current(Buffer.from(pcm).toString("base64"));
},
@@ -62,59 +27,33 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
onError: (error) => {
onErrorRef.current?.(error);
},
},
{
traceLabel: `dictation:${sourceId}`,
}
);
});
return engineRef.current;
}, [sourceId]);
}, []);
useEffect(() => {
onPcmSegmentRef.current = config.onPcmSegment;
onErrorRef.current = config.onError;
}, [config.onPcmSegment, config.onError]);
useEffect(() => {
console.log("[DictationAudioSource] mount", {
sourceId,
});
return () => {
console.log("[DictationAudioSource] unmount", {
sourceId,
});
};
}, [sourceId]);
const start = useCallback(async () => {
console.log("[DictationAudioSource] start", {
sourceId,
});
const engine = getOrCreateEngine();
await engine.initialize();
await engine.startCapture();
}, [getOrCreateEngine, sourceId]);
}, [getOrCreateEngine]);
const stop = useCallback(async () => {
console.log("[DictationAudioSource] stop", {
sourceId,
hasEngine: Boolean(engineRef.current),
});
await engineRef.current?.stopCapture();
setVolume(0);
}, [sourceId]);
}, []);
useEffect(() => {
return () => {
const engine = engineRef.current;
engineRef.current = null;
console.log("[DictationAudioSource] destroy_engine", {
sourceId,
hadEngine: Boolean(engine),
});
void engine?.destroy().catch(() => undefined);
};
}, [sourceId]);
}, []);
return {
start,
@@ -163,15 +163,6 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
if (missingNavigator) {
throw new Error("Microphone capture is not supported in this environment");
}
console.log("[DictationAudio][Web] Microphone preflight", {
secureContext,
currentOrigin,
isTauri,
hasMediaDevices:
typeof navigator !== "undefined" &&
!!navigator.mediaDevices &&
typeof navigator.mediaDevices.getUserMedia === "function",
});
if (!secureContext && !isTauri) {
throw new Error(`Microphone access requires HTTPS or localhost. Current origin: ${currentOrigin}`);
}
@@ -13,18 +13,6 @@ interface UseExplorerOpenGestureParams {
onOpen: () => void;
}
const IS_DEV = Boolean((globalThis as { __DEV__?: boolean }).__DEV__);
function logExplorerOpenGesture(
event: string,
details: Record<string, unknown>
): void {
if (!IS_DEV) {
return;
}
console.log(`[ExplorerOpenGesture] ${event}`, details);
}
export function useExplorerOpenGesture({
enabled,
onOpen,
@@ -82,7 +70,6 @@ export function useExplorerOpenGesture({
})
.onStart(() => {
isGesturing.value = true;
runOnJS(logExplorerOpenGesture)("start", { enabled });
})
.onUpdate((event) => {
// Right sidebar: start from closed position (+windowWidth) and move towards 0.
@@ -103,15 +90,6 @@ export function useExplorerOpenGesture({
const shouldOpenByPosition = translateX.value < (windowWidth * 2) / 3;
const shouldOpenByVelocity = event.velocityX < -500;
const shouldOpen = shouldOpenByPosition || shouldOpenByVelocity;
runOnJS(logExplorerOpenGesture)("end", {
translationX: event.translationX,
velocityX: event.velocityX,
panelTranslateX: translateX.value,
windowWidth,
shouldOpenByPosition,
shouldOpenByVelocity,
shouldOpen,
});
if (shouldOpen) {
animateToOpen();
runOnJS(onOpen)();
@@ -302,13 +302,6 @@ export function useSidebarWorkspacesList(options?: {
)
const projects = useMemo(() => {
console.log('[useSidebarWorkspacesList] build_projects', {
serverId,
hasSessionWorkspaces: Boolean(sessionWorkspaces),
workspaceCount: sessionWorkspaces?.size ?? 0,
projectOrderLength: persistedProjectOrder.length,
workspaceOrderScopeCount: Object.keys(persistedWorkspaceOrderByScope).length,
})
if (!sessionWorkspaces || sessionWorkspaces.size === 0 || !serverId) {
return EMPTY_PROJECTS
}
@@ -320,36 +313,6 @@ export function useSidebarWorkspacesList(options?: {
})
}, [persistedProjectOrder, persistedWorkspaceOrderByScope, serverId, sessionWorkspaces])
useEffect(() => {
console.log('[useSidebarWorkspacesList] inputs_changed', {
serverId,
connectionStatus,
hasHydratedWorkspaces,
workspaceCount: sessionWorkspaces?.size ?? 0,
projectOrderLength: persistedProjectOrder.length,
workspaceOrderScopeCount: Object.keys(persistedWorkspaceOrderByScope).length,
})
}, [
connectionStatus,
hasHydratedWorkspaces,
persistedProjectOrder,
persistedWorkspaceOrderByScope,
serverId,
sessionWorkspaces,
])
useEffect(() => {
console.log('[useSidebarWorkspacesList] projects_changed', {
serverId,
projectCount: projects.length,
projectKeys: projects.map((project) => project.projectKey),
workspaceCounts: projects.map((project) => ({
projectKey: project.projectKey,
workspaceCount: project.workspaces.length,
})),
})
}, [projects, serverId])
useEffect(() => {
if (!serverId || projects.length === 0) {
return