@eldrforge/kodrdriv 0.0.14 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -9
- package/dist/arguments.js +306 -55
- package/dist/arguments.js.map +1 -1
- package/dist/audio/devices.js +284 -0
- package/dist/audio/devices.js.map +1 -0
- package/dist/audio/index.js +31 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/audio/processor.js +766 -0
- package/dist/audio/processor.js.map +1 -0
- package/dist/audio/types.js +16 -0
- package/dist/audio/types.js.map +1 -0
- package/dist/audio/validation.js +35 -0
- package/dist/audio/validation.js.map +1 -0
- package/dist/commands/audio-commit.js +64 -248
- package/dist/commands/audio-commit.js.map +1 -1
- package/dist/commands/audio-review.js +90 -701
- package/dist/commands/audio-review.js.map +1 -1
- package/dist/commands/commit.js +18 -18
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/release.js +14 -15
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/review.js +152 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/select-audio.js +265 -0
- package/dist/commands/select-audio.js.map +1 -0
- package/dist/constants.js +86 -68
- package/dist/constants.js.map +1 -1
- package/dist/content/diff.js +155 -1
- package/dist/content/diff.js.map +1 -1
- package/dist/content/issues.js +256 -0
- package/dist/content/issues.js.map +1 -0
- package/dist/content/releaseNotes.js +90 -0
- package/dist/content/releaseNotes.js.map +1 -0
- package/dist/main.js +9 -2
- package/dist/main.js.map +1 -1
- package/dist/prompt/instructions/commit.md +18 -15
- package/dist/prompt/instructions/release.md +6 -5
- package/dist/prompt/instructions/{audio-review.md → review.md} +24 -18
- package/dist/prompt/prompts.js +87 -19
- package/dist/prompt/prompts.js.map +1 -1
- package/dist/types.js +27 -3
- package/dist/types.js.map +1 -1
- package/dist/util/general.js +7 -1
- package/dist/util/general.js.map +1 -1
- package/dist/util/openai.js +34 -3
- package/dist/util/openai.js.map +1 -1
- package/dist/util/stdin.js +61 -0
- package/dist/util/stdin.js.map +1 -0
- package/package.json +6 -6
- package/.kodrdriv/config.yaml +0 -20
- package/.kodrdriv/context/content.md +0 -7
- package/RELEASE_NOTES.md +0 -14
- package/docs/index.html +0 -17
- package/docs/package.json +0 -36
- package/docs/pnpm-lock.yaml +0 -3441
- package/docs/public/README.md +0 -132
- package/docs/public/advanced-usage.md +0 -188
- package/docs/public/code-icon.svg +0 -4
- package/docs/public/commands.md +0 -116
- package/docs/public/configuration.md +0 -274
- package/docs/public/examples.md +0 -352
- package/docs/public/kodrdriv-logo.svg +0 -62
- package/docs/src/App.css +0 -387
- package/docs/src/App.tsx +0 -60
- package/docs/src/components/DocumentPage.tsx +0 -56
- package/docs/src/components/ErrorMessage.tsx +0 -15
- package/docs/src/components/LoadingSpinner.tsx +0 -14
- package/docs/src/components/MarkdownRenderer.tsx +0 -56
- package/docs/src/components/Navigation.css +0 -73
- package/docs/src/components/Navigation.tsx +0 -36
- package/docs/src/index.css +0 -61
- package/docs/src/main.tsx +0 -10
- package/docs/src/test/setup.ts +0 -1
- package/docs/src/vite-env.d.ts +0 -10
- package/docs/tsconfig.node.json +0 -13
- package/docs/vite.config.ts +0 -15
- package/docs/vitest.config.ts +0 -15
- package/eslint.config.mjs +0 -83
- package/nodemon.json +0 -14
- package/output/kodrdriv/250701-1442-release-notes.md +0 -3
- package/pnpm-workspace.yaml +0 -5
- package/tsconfig.tsbuildinfo +0 -1
- package/vite.config.ts +0 -90
- package/vitest.config.ts +0 -24
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.js","sources":["../../src/audio/processor.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-vars */\nimport fs from 'fs/promises';\nimport path from 'path';\nimport os from 'os';\nimport { DEFAULT_OUTPUT_DIRECTORY } from '../constants';\nimport { getLogger } from '../logging';\nimport { run } from '../util/child';\nimport { getOutputPath, getTimestampedAudioFilename, getTimestampedTranscriptFilename } from '../util/general';\nimport { transcribeAudio } from '../util/openai';\nimport { create as createStorage } from '../util/storage';\nimport { audioDeviceConfigExists, loadAudioDeviceFromHomeConfig } from '../commands/select-audio';\nimport { detectBestAudioDevice, listAudioDevices } from './devices';\nimport { AudioProcessingOptions, AudioProcessingResult } from './types';\nimport { validateAudioFile } from './validation';\n\n/**\n * Main audio processor class that handles recording, processing, and transcription\n */\nexport class AudioProcessor {\n private readonly logger = getLogger();\n\n /**\n * Process audio from either a file or by recording new audio\n * @param options Audio processing options\n * @returns AudioProcessingResult with transcript and file paths\n */\n async processAudio(options: AudioProcessingOptions): Promise<AudioProcessingResult> {\n // Check if audio device is configured (only for recording, not for file processing)\n if (!options.file && options.preferencesDirectory && !await audioDeviceConfigExists(options.preferencesDirectory)) {\n throw new Error('No audio device configured. Please run \"kodrdriv select-audio\" first to configure your audio device.');\n }\n\n if (options.dryRun) {\n if (options.file) {\n this.logger.info('DRY RUN: Would process audio file: %s', options.file);\n } else {\n this.logger.info('DRY RUN: Would start audio recording');\n }\n this.logger.info('DRY RUN: Would transcribe audio and return transcript');\n return {\n transcript: '',\n cancelled: false\n };\n }\n\n if (options.file) {\n // Process existing audio file\n return await this.processAudioFile(options.file, options);\n } else {\n // Record new audio\n return await this.recordAndTranscribeAudio(options);\n }\n }\n\n /**\n * Process an existing audio file\n */\n private async processAudioFile(filePath: string, options: AudioProcessingOptions): Promise<AudioProcessingResult> {\n this.logger.info('🎯 Processing audio file: %s', filePath);\n\n // Validate the audio file\n await validateAudioFile(filePath);\n\n // Transcribe the audio\n this.logger.info('🎯 Transcribing audio...');\n this.logger.info('⏳ This may take a few seconds depending on audio length...');\n const transcription = await transcribeAudio(filePath);\n const audioContext = transcription.text;\n this.logger.info('✅ Audio transcribed successfully');\n this.logger.debug('Transcription: %s', audioContext);\n\n // Save transcript to output directory\n let transcriptFilePath: string | undefined;\n if (options.outputDirectory) {\n transcriptFilePath = await this.saveTranscript(audioContext, filePath, options.outputDirectory);\n }\n\n if (!audioContext.trim()) {\n this.logger.warn('No audio content was transcribed.');\n return {\n transcript: '',\n audioFilePath: filePath,\n transcriptFilePath,\n cancelled: false\n };\n }\n\n this.logger.info('📝 Audio transcribed successfully');\n return {\n transcript: audioContext,\n audioFilePath: filePath,\n transcriptFilePath,\n cancelled: false\n };\n }\n\n /**\n * Record and transcribe new audio\n */\n private async recordAndTranscribeAudio(options: AudioProcessingOptions): Promise<AudioProcessingResult> {\n const outputDirectory = options.outputDirectory || DEFAULT_OUTPUT_DIRECTORY;\n const storage = createStorage({ log: this.logger.info });\n await storage.ensureDirectory(outputDirectory);\n\n // Create a deterministic temp directory inside the configured output directory\n const tempDir = path.join(outputDirectory, 'tmp');\n await fs.mkdir(tempDir, { recursive: true });\n\n // Use a timestamped filename to avoid collisions if multiple recordings run quickly\n const audioFilePath = path.join(tempDir, `recording-${Date.now()}.wav`);\n\n // Recording state variables\n let recordingProcess: any = null;\n let recordingFinished = false;\n let recordingCancelled = false;\n let recordingFailed = false;\n let countdownInterval: NodeJS.Timeout | null = null;\n let remainingSeconds = 30;\n let intendedRecordingTime = 30;\n const maxRecordingTime = options.maxRecordingTime || 300; // 5 minutes default\n const extensionTime = 30; // 30 seconds per extension\n\n // Cleanup functions that need to be accessible in finally block\n let keyHandler: ((data: Buffer | string) => void) | null = null;\n const originalRawMode = false;\n const sigintHandler: (() => void) | null = null;\n\n const cleanupKeyboardHandling = () => {\n try {\n if (keyHandler) {\n process.stdin.removeListener('data', keyHandler);\n keyHandler = null;\n }\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(originalRawMode);\n }\n process.stdin.pause();\n } catch (e) {\n // Ignore cleanup errors\n }\n };\n\n try {\n this.logger.info('🎤 Starting recording... Speak now!');\n this.logger.info('📋 Controls: ENTER=done, E=extend+30s, C/Ctrl+C=cancel');\n\n // List available audio devices in debug mode\n if (options.debug) {\n await listAudioDevices();\n }\n\n // Recording control functions\n const updateCountdownDisplay = () => {\n const maxMinutes = Math.floor(maxRecordingTime / 60);\n const intendedMinutes = Math.floor(intendedRecordingTime / 60);\n const intendedSeconds = intendedRecordingTime % 60;\n process.stdout.write(`\\r⏱️ Recording: ${remainingSeconds}s left (${intendedMinutes}:${intendedSeconds.toString().padStart(2, '0')}/${maxMinutes}:00 max) [ENTER=done, E=+30s, C=cancel]`);\n };\n\n const extendRecording = () => {\n const newTotal = intendedRecordingTime + extensionTime;\n if (newTotal <= maxRecordingTime) {\n intendedRecordingTime = newTotal;\n remainingSeconds += extensionTime;\n this.logger.info(`🔄 Extended recording by ${extensionTime}s (total: ${Math.floor(intendedRecordingTime / 60)}:${(intendedRecordingTime % 60).toString().padStart(2, '0')})`);\n updateCountdownDisplay();\n } else {\n const canExtend = maxRecordingTime - intendedRecordingTime;\n if (canExtend > 0) {\n intendedRecordingTime = maxRecordingTime;\n remainingSeconds += canExtend;\n this.logger.info(`🔄 Extended recording by ${canExtend}s (maximum reached: ${Math.floor(maxRecordingTime / 60)}:${(maxRecordingTime % 60).toString().padStart(2, '0')})`);\n updateCountdownDisplay();\n } else {\n this.logger.warn(`⚠️ Cannot extend: maximum recording time (${Math.floor(maxRecordingTime / 60)}:${(maxRecordingTime % 60).toString().padStart(2, '0')}) reached`);\n }\n }\n };\n\n const stopRecording = async () => {\n if (!recordingFinished && !recordingCancelled) {\n recordingFinished = true;\n if (countdownInterval) {\n clearInterval(countdownInterval);\n countdownInterval = null;\n }\n process.stdout.write('\\r⏱️ Recording finished! \\n');\n if (recordingProcess && recordingProcess.kill) {\n recordingProcess.kill('SIGTERM');\n }\n this.logger.info('🛑 Recording stopped');\n }\n };\n\n const cancelRecording = async () => {\n if (!recordingFinished && !recordingCancelled) {\n recordingCancelled = true;\n if (countdownInterval) {\n clearInterval(countdownInterval);\n countdownInterval = null;\n }\n process.stdout.write('\\r❌ Recording cancelled! \\n');\n if (recordingProcess && recordingProcess.kill) {\n recordingProcess.kill('SIGTERM');\n }\n this.logger.info('❌ Audio recording cancelled by user');\n }\n };\n\n // Set up keyboard input handling\n let keyHandler: ((data: Buffer | string) => void) | null = null;\n let originalRawMode = false;\n\n const setupKeyboardHandling = () => {\n // Ensure stdin is properly configured\n if (!process.stdin.readable) {\n this.logger.warn('stdin is not readable, keyboard controls may not work');\n return;\n }\n\n // Save original stdin state\n originalRawMode = process.stdin.isRaw || false;\n\n try {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding('utf8');\n\n keyHandler = (data: Buffer | string) => {\n const key = data.toString();\n const keyCode = key.charCodeAt(0);\n\n if (options.debug) {\n this.logger.debug('Key pressed: code=%d, char=%s', keyCode, JSON.stringify(key));\n }\n\n if (keyCode === 13 || keyCode === 10) { // ENTER key (CR or LF)\n process.stdout.write('\\r✅ ENTER pressed - stopping recording... \\n');\n stopRecording();\n } else if (key.toLowerCase() === 'e') { // 'e' or 'E' key\n extendRecording();\n } else if (key.toLowerCase() === 'c' || keyCode === 3) { // 'c', 'C', or Ctrl+C\n process.stdout.write('\\r❌ Cancelling recording... \\n');\n cancelRecording();\n }\n };\n\n process.stdin.on('data', keyHandler);\n } catch (error: any) {\n this.logger.warn('Failed to setup keyboard handling: %s', error.message);\n this.logger.info('You may need to use Ctrl+C to stop recording');\n }\n };\n\n // Start countdown display\n const startCountdown = () => {\n updateCountdownDisplay();\n countdownInterval = setInterval(() => {\n remainingSeconds--;\n if (remainingSeconds > 0) {\n updateCountdownDisplay();\n } else {\n process.stdout.write('\\r⏱️ Recording: Time\\'s up! \\n');\n if (countdownInterval) {\n clearInterval(countdownInterval);\n countdownInterval = null;\n }\n stopRecording();\n }\n }, 1000);\n };\n\n // Set up recording command\n recordingProcess = await this.setupRecording(audioFilePath, maxRecordingTime, options);\n\n if (options.debug) {\n this.logger.debug('setupRecording returned: %s', recordingProcess ? 'process object' : 'null');\n }\n\n // Handle SIGINT for cleanup\n process.on('SIGINT', cancelRecording);\n\n // Start keyboard handling and countdown if we have a recording process\n if (recordingProcess) {\n setupKeyboardHandling();\n startCountdown();\n\n // Create a promise that resolves when user manually stops recording\n const manualStopPromise = new Promise<void>((resolve) => {\n const checkInterval = setInterval(() => {\n if (recordingFinished || recordingCancelled) {\n clearInterval(checkInterval);\n resolve();\n }\n }, 100);\n });\n\n // Create a promise that waits for the recording process to finish\n const recordingProcessPromise = new Promise<void>((resolve, reject) => {\n if (!recordingProcess) {\n resolve();\n return;\n }\n\n const processStartTime = Date.now();\n\n recordingProcess.on('exit', (code: number | null, signal: NodeJS.Signals | null) => {\n const processRunTime = Date.now() - processStartTime;\n\n if (options.debug) {\n this.logger.debug('Recording process exited with code %s, signal %s after %dms', code, signal, processRunTime);\n }\n\n // If the process exits very quickly with an error code, it likely failed to start recording\n if (code !== 0 && processRunTime < 2000) { // Less than 2 seconds\n this.logger.debug('Recording process failed early - runtime: %dms, exit code: %s', processRunTime, code);\n recordingFailed = true;\n }\n\n resolve();\n });\n\n recordingProcess.on('error', (error: Error) => {\n this.logger.error('Recording process error: %s', error.message);\n recordingFailed = true;\n reject(error);\n });\n });\n\n // Wait for either the recording to finish naturally or manual stop\n try {\n await Promise.race([recordingProcessPromise, manualStopPromise]);\n\n if (recordingFinished && recordingProcess && !recordingProcess.killed) {\n recordingProcess.kill('SIGTERM');\n await new Promise(resolve => setTimeout(resolve, 200));\n if (!recordingProcess.killed) {\n recordingProcess.kill('SIGKILL');\n }\n }\n\n if (!recordingCancelled && !recordingFinished) {\n if (countdownInterval) {\n clearInterval(countdownInterval);\n countdownInterval = null;\n }\n process.stdout.write('\\r⏱️ Recording completed! \\n');\n this.logger.info('✅ Recording completed automatically');\n }\n } catch (error: any) {\n if (!recordingCancelled && !recordingFinished) {\n if (countdownInterval) {\n clearInterval(countdownInterval);\n countdownInterval = null;\n }\n if (error.signal === 'SIGTERM' || error.signal === 'SIGKILL') {\n this.logger.debug('Recording process terminated as expected');\n } else {\n this.logger.warn('Recording process ended unexpectedly: %s', error.message);\n }\n }\n }\n\n // Clean up keyboard input and process listeners\n cleanupKeyboardHandling();\n if (sigintHandler) {\n process.removeListener('SIGINT', sigintHandler);\n }\n }\n\n // If recording was cancelled, return early\n if (recordingCancelled) {\n return {\n transcript: '',\n cancelled: true\n };\n }\n\n // If recording failed (process exited with error too quickly), fail the command\n if (recordingFailed) {\n this.logger.error('❌ Audio recording failed to start or exited with an error');\n this.logger.info('This usually means the audio device is busy, not accessible, or ffmpeg configuration is incorrect');\n this.logger.info('💡 Try running \"kodrdriv select-audio\" to choose a different audio device');\n\n throw new Error('Audio recording failed - cannot proceed with audio-commit command');\n }\n\n // Wait for the recording file to be fully written\n if (recordingFinished) {\n await new Promise(resolve => setTimeout(resolve, 500));\n }\n\n // Check if recording process failed early (before we try to verify the file)\n try {\n // Verify audio file was created\n await this.verifyAudioFile(audioFilePath);\n } catch (verifyError: any) {\n // If the file doesn't exist, the recording process likely failed\n this.logger.error('❌ Recording process failed - no audio file was created: %s', verifyError.message);\n this.logger.info('This can happen if the audio device is busy, not accessible, or if ffmpeg is not properly configured');\n this.logger.info('💡 Try running \"kodrdriv select-audio\" to choose a different audio device');\n\n throw new Error(`Audio recording failed - ${verifyError.message}`);\n }\n\n // Transcribe the audio\n const audioContext = await this.transcribeRecordedAudio(audioFilePath);\n\n // Save files to output directory\n const { audioOutputPath, transcriptOutputPath } = await this.saveRecordedFiles(\n audioFilePath, audioContext, outputDirectory\n );\n\n if (!audioContext.trim()) {\n this.logger.warn('No audio content was transcribed.');\n return {\n transcript: '',\n audioFilePath: audioOutputPath,\n transcriptFilePath: transcriptOutputPath,\n cancelled: false\n };\n }\n\n this.logger.info('📝 Audio recorded and transcribed successfully');\n return {\n transcript: audioContext,\n audioFilePath: audioOutputPath,\n transcriptFilePath: transcriptOutputPath,\n cancelled: false\n };\n\n } catch (error: any) {\n this.logger.error('Audio recording/transcription failed: %s', error.message);\n // Re-throw the error so the command fails properly\n throw error;\n } finally {\n // Cleanup is handled comprehensively in the cleanup function\n await this.cleanup(countdownInterval, recordingProcess, tempDir, recordingFailed || options.keepTemp);\n }\n }\n\n /**\n * Set up recording command based on platform\n */\n private async setupRecording(audioFilePath: string, maxRecordingTime: number, options: AudioProcessingOptions): Promise<any> {\n let recordCommand: string;\n let argsForSpawn: string[] | undefined;\n\n if (process.platform === 'darwin') {\n // macOS - try ffmpeg first\n try {\n await run('which ffmpeg');\n const homeDeviceConfig = options.preferencesDirectory ?\n await loadAudioDeviceFromHomeConfig(options.preferencesDirectory) : null;\n const audioDevice = options.audioDevice || homeDeviceConfig?.audioDevice || await detectBestAudioDevice();\n\n // Get the correct input format for this device\n const { getDeviceInputFormat } = await import('./devices');\n const inputFormat = await getDeviceInputFormat(audioDevice);\n\n if (!inputFormat) {\n throw new Error(`Unable to find working format for audio device ${audioDevice}`);\n }\n\n // Build argument list explicitly. If the detected inputFormat is wrapped in\n // quotes (e.g. \":0\"), remove those quotes for the spawn call. The shell would\n // normally strip them, but child_process.spawn passes the string verbatim to\n // the executable, which causes ffmpeg to treat the quotes as part of the\n // device name leading to failures such as \"Video device not found\".\n\n const strippedInputFormat = inputFormat.startsWith('\"') && inputFormat.endsWith('\"')\n ? inputFormat.slice(1, -1)\n : inputFormat;\n\n // Determine audio parameters based on stored capabilities (if available)\n const channels = options.audioDevice ? undefined : homeDeviceConfig?.channels; // user may override manually via options\n const sampleRate = options.audioDevice ? undefined : homeDeviceConfig?.sampleRate;\n\n const ffmpegAudioArgs: string[] = ['-c:a', 'pcm_s16le', '-vn'];\n\n if (channels) {\n ffmpegAudioArgs.push('-ac', String(channels));\n } else {\n // Default to mono when channel count is unknown to reduce size\n ffmpegAudioArgs.push('-ac', '1');\n }\n\n if (sampleRate) {\n ffmpegAudioArgs.push('-ar', String(sampleRate));\n }\n\n const ffmpegArgs = [\n '-f', 'avfoundation',\n '-i', strippedInputFormat,\n ...ffmpegAudioArgs,\n '-t', String(maxRecordingTime),\n '-y', audioFilePath\n ];\n\n // Store for later spawn\n recordCommand = `ffmpeg ${ffmpegArgs.join(' ')}`;\n argsForSpawn = ffmpegArgs;\n\n // Log the exact command being executed\n this.logger.info(`🔧 Executing recording command: ${recordCommand}`);\n\n if (options.audioDevice) {\n this.logger.info(`🎙️ Using audio device ${audioDevice} (from configuration) with format ${inputFormat}`);\n } else if (homeDeviceConfig) {\n this.logger.info(`🎙️ Using audio device ${audioDevice} (${homeDeviceConfig.audioDeviceName}) with format ${inputFormat}`);\n } else {\n this.logger.info(`🎙️ Using audio device ${audioDevice} (auto-detected) with format ${inputFormat}`);\n }\n } catch {\n // Try sox/rec as fallback\n try {\n await run('which rec');\n recordCommand = `rec -c 1 -t wav \"${audioFilePath}\" trim 0 ${maxRecordingTime}`;\n this.logger.info(`🔧 Executing recording command (sox fallback): ${recordCommand}`);\n } catch {\n throw new Error('MANUAL_RECORDING_NEEDED');\n }\n }\n } else if (process.platform === 'win32') {\n // Windows - use ffmpeg\n try {\n await run('where ffmpeg');\n recordCommand = `ffmpeg -f dshow -i audio=\"Microphone\" -ac 1 -c:a pcm_s16le -vn -t ${maxRecordingTime} -y \"${audioFilePath}\"`;\n this.logger.info(`🔧 Executing recording command: ${recordCommand}`);\n } catch {\n throw new Error('MANUAL_RECORDING_NEEDED');\n }\n } else {\n // Linux - use arecord or ffmpeg\n try {\n await run('which arecord');\n recordCommand = `arecord -f cd -t wav -d ${maxRecordingTime} \"${audioFilePath}\"`;\n this.logger.info(`🔧 Executing recording command: ${recordCommand}`);\n } catch {\n try {\n await run('which ffmpeg');\n recordCommand = `ffmpeg -f alsa -i default -ac 1 -c:a pcm_s16le -vn -t ${maxRecordingTime} -y \"${audioFilePath}\"`;\n this.logger.info(`🔧 Executing recording command: ${recordCommand}`);\n } catch {\n throw new Error('MANUAL_RECORDING_NEEDED');\n }\n }\n }\n\n try {\n // Ensure the output directory exists (equivalent to `mkdir -p`)\n await fs.mkdir(path.dirname(audioFilePath), { recursive: true });\n\n // Use spawn instead of exec for better process control\n const { spawn } = await import('child_process');\n\n // If argsForSpawn was prepared (preferred path), use it; otherwise fall back to splitting\n const command = 'ffmpeg';\n const args = argsForSpawn ?? recordCommand.split(' ').slice(1);\n\n this.logger.debug(`🔧 Spawning process: ${command} with args: ${JSON.stringify(args)}`);\n\n const recordingProcess = spawn(command, args, {\n stdio: ['ignore', 'ignore', 'pipe'], // Ignore stdin/stdout, capture stderr\n detached: false\n });\n\n // Enhanced error handling and stderr capture\n let stderrBuffer = '';\n\n recordingProcess.on('error', (error) => {\n this.logger.error('Recording process error: %s', error.message);\n this.logger.error('Full error details: %s', JSON.stringify(error));\n });\n\n recordingProcess.stderr?.on('data', (data) => {\n const output = data.toString().trim();\n stderrBuffer += output + '\\n';\n\n if (options.debug) {\n this.logger.debug('Recording process stderr: %s', output);\n } else {\n // In non-debug mode, still capture critical errors\n if (output.toLowerCase().includes('error') ||\n output.toLowerCase().includes('failed') ||\n output.toLowerCase().includes('permission') ||\n output.toLowerCase().includes('busy') ||\n output.toLowerCase().includes('device')) {\n this.logger.warn('Recording process stderr: %s', output);\n }\n }\n });\n\n // Enhanced exit handling with stderr output\n recordingProcess.on('exit', (code, signal) => {\n if (code !== 0) {\n this.logger.error('🚨 Recording process exited with error code %s, signal %s', code, signal);\n if (stderrBuffer.trim()) {\n this.logger.error('🚨 Recording process stderr output:\\n%s', stderrBuffer);\n }\n } else if (options.debug) {\n this.logger.debug('Recording process exited successfully with code %s', code);\n }\n });\n\n return recordingProcess;\n } catch (error: any) {\n if (error.message === 'MANUAL_RECORDING_NEEDED') {\n this.showManualRecordingInstructions(audioFilePath);\n await this.waitForManualRecording();\n return null;\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Show instructions for manual recording\n */\n private showManualRecordingInstructions(audioFilePath: string): void {\n this.logger.warn('⚠️ Automatic recording not available on this system.');\n this.logger.warn('📱 Please record audio manually using your system\\'s built-in tools:');\n this.logger.warn('');\n\n if (process.platform === 'darwin') {\n this.logger.warn('🍎 macOS options:');\n this.logger.warn(' 1. Use QuickTime Player: File → New Audio Recording');\n this.logger.warn(' 2. Use Voice Memos app');\n this.logger.warn(' 3. Install ffmpeg: brew install ffmpeg');\n this.logger.warn(' 4. Install sox: brew install sox');\n } else if (process.platform === 'win32') {\n this.logger.warn('🪟 Windows options:');\n this.logger.warn(' 1. Use Voice Recorder app');\n this.logger.warn(' 2. Install ffmpeg: https://ffmpeg.org/download.html');\n } else {\n this.logger.warn('🐧 Linux options:');\n this.logger.warn(' 1. Install alsa-utils: sudo apt install alsa-utils');\n this.logger.warn(' 2. Install ffmpeg: sudo apt install ffmpeg');\n }\n\n this.logger.warn('');\n this.logger.warn(`💾 Save your recording as: ${audioFilePath}`);\n this.logger.warn('🎵 Recommended format: WAV, 44.1kHz, mono or stereo');\n this.logger.warn('');\n this.logger.warn('⌨️ Press ENTER when you have saved the audio file...');\n }\n\n /**\n * Wait for user to complete manual recording\n */\n private async waitForManualRecording(): Promise<void> {\n return new Promise(resolve => {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n const enterHandler = (key: Buffer) => {\n if (key[0] === 13) { // Enter key\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdin.removeListener('data', enterHandler);\n resolve();\n }\n };\n process.stdin.on('data', enterHandler);\n });\n }\n\n /**\n * Verify that the audio file was created successfully\n */\n private async verifyAudioFile(audioFilePath: string): Promise<void> {\n try {\n await fs.access(audioFilePath);\n const stats = await fs.stat(audioFilePath);\n if (stats.size === 0) {\n throw new Error('Audio file is empty');\n }\n this.logger.info('✅ Audio file created successfully (%d bytes)', stats.size);\n } catch (error: any) {\n throw new Error(`Failed to create audio file: ${error.message}`);\n }\n }\n\n /**\n * Transcribe recorded audio\n */\n private async transcribeRecordedAudio(audioFilePath: string): Promise<string> {\n this.logger.info('🎯 Transcribing audio...');\n this.logger.info('⏳ This may take a few seconds depending on audio length...');\n const transcription = await transcribeAudio(audioFilePath);\n const audioContext = transcription.text;\n this.logger.info('✅ Audio transcribed successfully');\n this.logger.debug('Transcription: %s', audioContext);\n return audioContext;\n }\n\n /**\n * Save transcript file\n */\n private async saveTranscript(audioContext: string, sourceFilePath: string, outputDirectory: string): Promise<string | undefined> {\n if (!audioContext.trim()) return undefined;\n\n try {\n this.logger.info('💾 Saving transcript...');\n const storage = createStorage({ log: this.logger.info });\n await storage.ensureDirectory(outputDirectory);\n\n const transcriptOutputFilename = getTimestampedTranscriptFilename();\n const transcriptOutputPath = getOutputPath(outputDirectory, transcriptOutputFilename);\n const transcriptContent = `# Audio Transcript\\n\\n**Source:** ${sourceFilePath}\\n**Processed:** ${new Date().toISOString()}\\n\\n**Transcript:**\\n\\n${audioContext}`;\n await storage.writeFile(transcriptOutputPath, transcriptContent, 'utf-8');\n this.logger.debug('Saved transcript: %s', transcriptOutputPath);\n return transcriptOutputPath;\n } catch (error: any) {\n this.logger.warn('Failed to save transcript file: %s', error.message);\n return undefined;\n }\n }\n\n /**\n * Save recorded audio file and transcript\n */\n private async saveRecordedFiles(audioFilePath: string, audioContext: string, outputDirectory: string): Promise<{ audioOutputPath?: string; transcriptOutputPath?: string }> {\n try {\n this.logger.info('💾 Saving audio file and transcript...');\n const storage = createStorage({ log: this.logger.info });\n await storage.ensureDirectory(outputDirectory);\n\n // Save audio file copy\n const audioOutputFilename = getTimestampedAudioFilename();\n const audioOutputPath = getOutputPath(outputDirectory, audioOutputFilename);\n await fs.copyFile(audioFilePath, audioOutputPath);\n this.logger.debug('Saved audio file: %s', audioOutputPath);\n\n // Save transcript\n let transcriptOutputPath: string | undefined;\n if (audioContext.trim()) {\n const transcriptOutputFilename = getTimestampedTranscriptFilename();\n transcriptOutputPath = getOutputPath(outputDirectory, transcriptOutputFilename);\n const transcriptContent = `# Audio Transcript\\n\\n**Recorded:** ${new Date().toISOString()}\\n\\n**Transcript:**\\n\\n${audioContext}`;\n await storage.writeFile(transcriptOutputPath, transcriptContent, 'utf-8');\n this.logger.debug('Saved transcript: %s', transcriptOutputPath);\n }\n\n return { audioOutputPath, transcriptOutputPath };\n } catch (error: any) {\n this.logger.warn('Failed to save audio/transcript files: %s', error.message);\n return {};\n }\n }\n\n /**\n * Clean up resources\n */\n private async cleanup(countdownInterval: NodeJS.Timeout | null, recordingProcess: any, tempDir: string, keepTemp = false): Promise<void> {\n try {\n // Clear countdown interval\n if (countdownInterval) {\n clearInterval(countdownInterval);\n }\n\n // Reset stdin thoroughly - this is critical for preventing hanging\n try {\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(false);\n }\n process.stdin.pause();\n process.stdin.removeAllListeners('data');\n process.stdin.removeAllListeners('keypress');\n process.stdin.removeAllListeners('readable');\n process.stdin.removeAllListeners('end');\n process.stdin.removeAllListeners('close');\n // Force stdin to unpipe if it was piped\n if (process.stdin.unpipe) {\n process.stdin.unpipe();\n }\n\n // Completely detach stdin from the event-loop\n if (typeof (process.stdin as any).unref === 'function') {\n (process.stdin as any).unref();\n }\n } catch (stdinError) {\n // Ignore stdin cleanup errors\n }\n\n // Remove ALL process event listeners to prevent hanging\n process.removeAllListeners('SIGINT');\n process.removeAllListeners('SIGTERM');\n process.removeAllListeners('SIGQUIT');\n process.removeAllListeners('SIGHUP');\n process.removeAllListeners('exit');\n process.removeAllListeners('beforeExit');\n\n // Kill recording process aggressively\n if (recordingProcess && !recordingProcess.killed) {\n try {\n recordingProcess.kill('SIGTERM');\n // Give it a very short time to terminate gracefully\n await new Promise(resolve => setTimeout(resolve, 50));\n if (!recordingProcess.killed) {\n recordingProcess.kill('SIGKILL');\n }\n\n // Destroy and detach any stdio streams\n if (recordingProcess.stderr) {\n try {\n recordingProcess.stderr.removeAllListeners();\n recordingProcess.stderr.destroy();\n if (typeof (recordingProcess.stderr as any).unref === 'function') {\n (recordingProcess.stderr as any).unref();\n }\n } catch {\n /* ignore */\n }\n }\n\n // Remove all listeners from the recording process itself and detach from event-loop\n recordingProcess.removeAllListeners();\n if (typeof recordingProcess.unref === 'function') {\n recordingProcess.unref();\n }\n } catch (killError) {\n // Ignore kill errors\n }\n }\n\n // Clean up temporary directory unless instructed to keep it (e.g., on failure)\n if (!keepTemp) {\n try {\n await fs.rm(tempDir, { recursive: true, force: true });\n } catch (fsError) {\n // Ignore filesystem cleanup errors\n }\n } else {\n this.logger.debug('Keeping temporary directory for inspection: %s', tempDir);\n }\n } catch (cleanupError: any) {\n this.logger.debug('Cleanup warning: %s', cleanupError.message);\n }\n }\n}\n\n/**\n * Create a new audio processor instance\n */\nexport const createAudioProcessor = (): AudioProcessor => {\n return new AudioProcessor();\n}; "],"names":["AudioProcessor","processAudio","options","file","preferencesDirectory","audioDeviceConfigExists","Error","dryRun","logger","info","transcript","cancelled","processAudioFile","recordAndTranscribeAudio","filePath","validateAudioFile","transcription","transcribeAudio","audioContext","text","debug","transcriptFilePath","outputDirectory","saveTranscript","trim","warn","audioFilePath","DEFAULT_OUTPUT_DIRECTORY","storage","createStorage","log","ensureDirectory","tempDir","path","join","fs","mkdir","recursive","Date","now","recordingProcess","recordingFinished","recordingCancelled","recordingFailed","countdownInterval","remainingSeconds","intendedRecordingTime","maxRecordingTime","extensionTime","keyHandler","originalRawMode","sigintHandler","cleanupKeyboardHandling","process","stdin","removeListener","setRawMode","pause","e","listAudioDevices","updateCountdownDisplay","maxMinutes","Math","floor","intendedMinutes","intendedSeconds","stdout","write","toString","padStart","extendRecording","newTotal","canExtend","stopRecording","clearInterval","kill","cancelRecording","setupKeyboardHandling","readable","isRaw","resume","setEncoding","data","key","keyCode","charCodeAt","JSON","stringify","toLowerCase","on","error","message","startCountdown","setInterval","setupRecording","manualStopPromise","Promise","resolve","checkInterval","recordingProcessPromise","reject","processStartTime","code","signal","processRunTime","race","killed","setTimeout","verifyAudioFile","verifyError","transcribeRecordedAudio","audioOutputPath","transcriptOutputPath","saveRecordedFiles","cleanup","keepTemp","recordCommand","argsForSpawn","platform","run","homeDeviceConfig","loadAudioDeviceFromHomeConfig","audioDevice","detectBestAudioDevice","getDeviceInputFormat","inputFormat","strippedInputFormat","startsWith","endsWith","slice","channels","undefined","sampleRate","ffmpegAudioArgs","push","String","ffmpegArgs","audioDeviceName","dirname","spawn","command","args","split","stdio","detached","stderrBuffer","stderr","output","includes","showManualRecordingInstructions","waitForManualRecording","enterHandler","access","stats","stat","size","sourceFilePath","transcriptOutputFilename","getTimestampedTranscriptFilename","getOutputPath","transcriptContent","toISOString","writeFile","audioOutputFilename","getTimestampedAudioFilename","copyFile","removeAllListeners","unpipe","unref","stdinError","destroy","killError","rm","force","fsError","cleanupError","getLogger","createAudioProcessor"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../../src/audio/types.ts"],"sourcesContent":["export interface AudioDevice {\n index: string;\n name: string;\n}\n\nexport interface AudioDeviceConfig {\n audioDevice: string;\n audioDeviceName: string;\n /** Native sample rate of the selected device in Hz */\n sampleRate?: number;\n /** Number of audio channels (e.g. 1 = mono, 2 = stereo) */\n channels?: number;\n /** Human-readable channel layout reported by ffmpeg (e.g. \"mono\", \"stereo\") */\n channelLayout?: string;\n}\n\nexport interface AudioProcessingOptions {\n /** Input audio file path (if processing existing file) */\n file?: string;\n /** Audio device index to use for recording */\n audioDevice?: string;\n /** Maximum recording time in seconds */\n maxRecordingTime?: number;\n /** Output directory for saved files */\n outputDirectory?: string;\n /** Preferences directory for device configuration */\n preferencesDirectory?: string;\n /** Enable debug mode for additional logging */\n debug?: boolean;\n /** Dry run mode */\n dryRun?: boolean;\n /** Keep temporary raw recording directory for inspection */\n keepTemp?: boolean;\n}\n\nexport interface AudioProcessingResult {\n /** Transcribed text content */\n transcript: string;\n /** Path to the audio file */\n audioFilePath?: string;\n /** Path to the transcript file */\n transcriptFilePath?: string;\n /** Whether the operation was cancelled */\n cancelled: boolean;\n}\n\nexport interface AudioRecordingControls {\n /** Callback when recording is stopped manually */\n onStop?: () => void;\n /** Callback when recording is cancelled */\n onCancel?: () => void;\n /** Callback when recording is extended */\n onExtend?: (newDuration: number) => void;\n}\n\nexport const SUPPORTED_AUDIO_FORMATS = [\n 'mp3', 'mp4', 'mpeg', 'mpga', 'm4a', 'wav', 'webm', 'flac', 'aac', 'ogg', 'opus'\n] as const;\n\nexport type SupportedAudioFormat = typeof SUPPORTED_AUDIO_FORMATS[number]; "],"names":["SUPPORTED_AUDIO_FORMATS"],"mappings":"MAuDaA,uBAAAA,GAA0B;AACnC,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;;;;;"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getLogger } from '../logging.js';
|
|
4
|
+
import { SUPPORTED_AUDIO_FORMATS } from './types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validates an audio file for processing
|
|
8
|
+
* @param filePath Path to the audio file to validate
|
|
9
|
+
* @throws Error if validation fails
|
|
10
|
+
*/ const validateAudioFile = async (filePath)=>{
|
|
11
|
+
const logger = getLogger();
|
|
12
|
+
try {
|
|
13
|
+
// Check if file exists
|
|
14
|
+
await fs.access(filePath);
|
|
15
|
+
// Check file extension
|
|
16
|
+
const ext = path.extname(filePath).toLowerCase().slice(1); // Remove the dot
|
|
17
|
+
if (!SUPPORTED_AUDIO_FORMATS.includes(ext)) {
|
|
18
|
+
throw new Error(`Unsupported audio format: ${ext}. Supported formats: ${SUPPORTED_AUDIO_FORMATS.join(', ')}`);
|
|
19
|
+
}
|
|
20
|
+
// Check if file is not empty
|
|
21
|
+
const stats = await fs.stat(filePath);
|
|
22
|
+
if (stats.size === 0) {
|
|
23
|
+
throw new Error('Audio file is empty');
|
|
24
|
+
}
|
|
25
|
+
logger.debug('Audio file validation passed: %s (%d bytes)', filePath, stats.size);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error.code === 'ENOENT') {
|
|
28
|
+
throw new Error(`Audio file not found: ${filePath}`);
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { validateAudioFile };
|
|
35
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sources":["../../src/audio/validation.ts"],"sourcesContent":["import fs from 'fs/promises';\nimport path from 'path';\nimport { getLogger } from '../logging';\nimport { SUPPORTED_AUDIO_FORMATS } from './types';\n\n/**\n * Validates an audio file for processing\n * @param filePath Path to the audio file to validate\n * @throws Error if validation fails\n */\nexport const validateAudioFile = async (filePath: string): Promise<void> => {\n const logger = getLogger();\n\n try {\n // Check if file exists\n await fs.access(filePath);\n\n // Check file extension\n const ext = path.extname(filePath).toLowerCase().slice(1); // Remove the dot\n if (!SUPPORTED_AUDIO_FORMATS.includes(ext as any)) {\n throw new Error(`Unsupported audio format: ${ext}. Supported formats: ${SUPPORTED_AUDIO_FORMATS.join(', ')}`);\n }\n\n // Check if file is not empty\n const stats = await fs.stat(filePath);\n if (stats.size === 0) {\n throw new Error('Audio file is empty');\n }\n\n logger.debug('Audio file validation passed: %s (%d bytes)', filePath, stats.size);\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n throw new Error(`Audio file not found: ${filePath}`);\n }\n throw error;\n }\n}; "],"names":["validateAudioFile","filePath","logger","getLogger","fs","access","ext","path","extname","toLowerCase","slice","SUPPORTED_AUDIO_FORMATS","includes","Error","join","stats","stat","size","debug","error","code"],"mappings":";;;;;AAKA;;;;IAKO,MAAMA,iBAAAA,GAAoB,OAAOC,QAAAA,GAAAA;AACpC,IAAA,MAAMC,MAAAA,GAASC,SAAAA,EAAAA;IAEf,IAAI;;QAEA,MAAMC,EAAAA,CAAGC,MAAM,CAACJ,QAAAA,CAAAA;;QAGhB,MAAMK,GAAAA,GAAMC,IAAAA,CAAKC,OAAO,CAACP,QAAAA,CAAAA,CAAUQ,WAAW,EAAA,CAAGC,KAAK,CAAC,CAAA,CAAA,CAAA;AACvD,QAAA,IAAI,CAACC,uBAAAA,CAAwBC,QAAQ,CAACN,GAAAA,CAAAA,EAAa;YAC/C,MAAM,IAAIO,KAAAA,CAAM,CAAC,0BAA0B,EAAEP,GAAAA,CAAI,qBAAqB,EAAEK,uBAAAA,CAAwBG,IAAI,CAAC,IAAA,CAAA,CAAA,CAAO,CAAA;AAChH;;AAGA,QAAA,MAAMC,KAAAA,GAAQ,MAAMX,EAAAA,CAAGY,IAAI,CAACf,QAAAA,CAAAA;QAC5B,IAAIc,KAAAA,CAAME,IAAI,KAAK,CAAA,EAAG;AAClB,YAAA,MAAM,IAAIJ,KAAAA,CAAM,qBAAA,CAAA;AACpB;AAEAX,QAAAA,MAAAA,CAAOgB,KAAK,CAAC,6CAAA,EAA+CjB,QAAAA,EAAUc,MAAME,IAAI,CAAA;AACpF,KAAA,CAAE,OAAOE,KAAAA,EAAY;QACjB,IAAIA,KAAAA,CAAMC,IAAI,KAAK,QAAA,EAAU;AACzB,YAAA,MAAM,IAAIP,KAAAA,CAAM,CAAC,sBAAsB,EAAEZ,QAAAA,CAAAA,CAAU,CAAA;AACvD;QACA,MAAMkB,KAAAA;AACV;AACJ;;;;"}
|
|
@@ -1,274 +1,90 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
|
-
import { Formatter } from '@riotprompt/riotprompt';
|
|
5
|
-
import shellescape from 'shell-escape';
|
|
6
2
|
import { getLogger } from '../logging.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { run } from '../util/child.js';
|
|
10
|
-
import { create as create$3 } from '../content/log.js';
|
|
11
|
-
import { hasStagedChanges, create as create$2 } from '../content/diff.js';
|
|
12
|
-
import { DEFAULT_OUTPUT_DIRECTORY, DEFAULT_EXCLUDED_PATTERNS } from '../constants.js';
|
|
13
|
-
import { stringifyJSON, getOutputPath, getTimestampedResponseFilename, getTimestampedRequestFilename } from '../util/general.js';
|
|
14
|
-
import { create as create$1 } from '../util/storage.js';
|
|
3
|
+
import { execute as execute$1 } from './commit.js';
|
|
4
|
+
import { processAudio } from '../audio/index.js';
|
|
15
5
|
|
|
16
6
|
const execute = async (runConfig)=>{
|
|
17
|
-
var _runConfig_commit
|
|
7
|
+
var _runConfig_commit;
|
|
18
8
|
const logger = getLogger();
|
|
19
|
-
const prompts = create(runConfig.model, runConfig);
|
|
20
9
|
const isDryRun = runConfig.dryRun || false;
|
|
21
10
|
if (isDryRun) {
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
logger.info('DRY RUN: Would add all changes to the index with: git add -A');
|
|
27
|
-
}
|
|
28
|
-
if ((_runConfig_commit8 = runConfig.commit) === null || _runConfig_commit8 === void 0 ? void 0 : _runConfig_commit8.sendit) {
|
|
29
|
-
logger.info('DRY RUN: Would automatically commit with generated message');
|
|
30
|
-
}
|
|
31
|
-
return 'DRY RUN: Audio-commit command would record audio, transcribe it, and generate commit message using the transcription as context';
|
|
32
|
-
}
|
|
33
|
-
// Handle add option first
|
|
34
|
-
if ((_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.add) {
|
|
35
|
-
logger.verbose('Adding all changes to the index...');
|
|
36
|
-
await run('git add -A');
|
|
37
|
-
}
|
|
38
|
-
// Start audio recording
|
|
39
|
-
logger.info('Starting audio recording for commit context...');
|
|
40
|
-
logger.info('This command will use your system\'s default audio recording tool');
|
|
41
|
-
logger.info('Press Ctrl+C after you finish speaking to generate your commit message');
|
|
42
|
-
// Create temporary file for audio recording
|
|
43
|
-
const outputDirectory = runConfig.outputDirectory || DEFAULT_OUTPUT_DIRECTORY;
|
|
44
|
-
const storage = create$1({
|
|
45
|
-
log: logger.info
|
|
46
|
-
});
|
|
47
|
-
await storage.ensureDirectory(outputDirectory);
|
|
48
|
-
const tempDir = await fs.mkdtemp(path.join(outputDirectory, '.temp-audio-'));
|
|
49
|
-
const audioFilePath = path.join(tempDir, 'recording.wav');
|
|
50
|
-
let audioContext = '';
|
|
51
|
-
try {
|
|
52
|
-
// Use system recording tool - cross-platform approach
|
|
53
|
-
logger.info('🎤 Starting recording... Speak now!');
|
|
54
|
-
logger.info('Recording will stop automatically after 30 seconds or when you press Ctrl+C');
|
|
55
|
-
let recordingProcess;
|
|
56
|
-
let recordingFinished = false;
|
|
57
|
-
// Determine which recording command to use based on platform
|
|
58
|
-
let recordCommand;
|
|
59
|
-
if (process.platform === 'darwin') {
|
|
60
|
-
// macOS - try ffmpeg first, then fall back to manual recording
|
|
61
|
-
try {
|
|
62
|
-
// Check if ffmpeg is available
|
|
63
|
-
await run('which ffmpeg');
|
|
64
|
-
recordCommand = `ffmpeg -f avfoundation -i ":0" -t 30 -y "${audioFilePath}"`;
|
|
65
|
-
} catch {
|
|
66
|
-
// ffmpeg not available, try sox/rec
|
|
67
|
-
try {
|
|
68
|
-
await run('which rec');
|
|
69
|
-
recordCommand = `rec -r 44100 -c 1 -t wav "${audioFilePath}" trim 0 30`;
|
|
70
|
-
} catch {
|
|
71
|
-
// Neither available, use manual fallback
|
|
72
|
-
throw new Error('MANUAL_RECORDING_NEEDED');
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} else if (process.platform === 'win32') {
|
|
76
|
-
// Windows - use ffmpeg if available, otherwise fallback
|
|
77
|
-
try {
|
|
78
|
-
await run('where ffmpeg');
|
|
79
|
-
recordCommand = `ffmpeg -f dshow -i audio="Microphone" -t 30 -y "${audioFilePath}"`;
|
|
80
|
-
} catch {
|
|
81
|
-
throw new Error('MANUAL_RECORDING_NEEDED');
|
|
82
|
-
}
|
|
11
|
+
var _runConfig_audioCommit, _runConfig_commit1;
|
|
12
|
+
if ((_runConfig_audioCommit = runConfig.audioCommit) === null || _runConfig_audioCommit === void 0 ? void 0 : _runConfig_audioCommit.file) {
|
|
13
|
+
logger.info('DRY RUN: Would process audio file: %s', runConfig.audioCommit.file);
|
|
14
|
+
logger.info('DRY RUN: Would transcribe audio and use as context for commit message generation');
|
|
83
15
|
} else {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
await run('which arecord');
|
|
87
|
-
recordCommand = `arecord -f cd -t wav -d 30 "${audioFilePath}"`;
|
|
88
|
-
} catch {
|
|
89
|
-
try {
|
|
90
|
-
await run('which ffmpeg');
|
|
91
|
-
recordCommand = `ffmpeg -f alsa -i default -t 30 -y "${audioFilePath}"`;
|
|
92
|
-
} catch {
|
|
93
|
-
throw new Error('MANUAL_RECORDING_NEEDED');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
// Start recording as a background process
|
|
98
|
-
try {
|
|
99
|
-
recordingProcess = run(recordCommand);
|
|
100
|
-
} catch (error) {
|
|
101
|
-
if (error.message === 'MANUAL_RECORDING_NEEDED') {
|
|
102
|
-
// Provide helpful instructions for manual recording
|
|
103
|
-
logger.warn('⚠️ Automatic recording not available on this system.');
|
|
104
|
-
logger.warn('📱 Please record audio manually using your system\'s built-in tools:');
|
|
105
|
-
logger.warn('');
|
|
106
|
-
if (process.platform === 'darwin') {
|
|
107
|
-
logger.warn('🍎 macOS options:');
|
|
108
|
-
logger.warn(' 1. Use QuickTime Player: File → New Audio Recording');
|
|
109
|
-
logger.warn(' 2. Use Voice Memos app');
|
|
110
|
-
logger.warn(' 3. Install ffmpeg: brew install ffmpeg');
|
|
111
|
-
logger.warn(' 4. Install sox: brew install sox');
|
|
112
|
-
} else if (process.platform === 'win32') {
|
|
113
|
-
logger.warn('🪟 Windows options:');
|
|
114
|
-
logger.warn(' 1. Use Voice Recorder app');
|
|
115
|
-
logger.warn(' 2. Install ffmpeg: https://ffmpeg.org/download.html');
|
|
116
|
-
} else {
|
|
117
|
-
logger.warn('🐧 Linux options:');
|
|
118
|
-
logger.warn(' 1. Install alsa-utils: sudo apt install alsa-utils');
|
|
119
|
-
logger.warn(' 2. Install ffmpeg: sudo apt install ffmpeg');
|
|
120
|
-
}
|
|
121
|
-
logger.warn('');
|
|
122
|
-
logger.warn(`💾 Save your recording as: ${audioFilePath}`);
|
|
123
|
-
logger.warn('🎵 Recommended format: WAV, 44.1kHz, mono or stereo');
|
|
124
|
-
logger.warn('');
|
|
125
|
-
logger.warn('⌨️ Press ENTER when you have saved the audio file...');
|
|
126
|
-
// Wait for user input
|
|
127
|
-
await new Promise((resolve)=>{
|
|
128
|
-
process.stdin.setRawMode(true);
|
|
129
|
-
process.stdin.resume();
|
|
130
|
-
process.stdin.on('data', (key)=>{
|
|
131
|
-
if (key[0] === 13) {
|
|
132
|
-
process.stdin.setRawMode(false);
|
|
133
|
-
process.stdin.pause();
|
|
134
|
-
resolve(void 0);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
} else {
|
|
139
|
-
throw error;
|
|
140
|
-
}
|
|
16
|
+
logger.info('DRY RUN: Would start audio recording for commit context');
|
|
17
|
+
logger.info('DRY RUN: Would transcribe audio and use as context for commit message generation');
|
|
141
18
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
logger.info('🛑 Recording stopped');
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
// Listen for Ctrl+C
|
|
153
|
-
process.on('SIGINT', stopRecording);
|
|
154
|
-
// Wait for recording to finish (either timeout or manual stop)
|
|
155
|
-
if (recordingProcess) {
|
|
156
|
-
try {
|
|
157
|
-
await recordingProcess;
|
|
158
|
-
logger.info('✅ Recording completed automatically');
|
|
159
|
-
} catch (error) {
|
|
160
|
-
if (!recordingFinished && error.signal === 'SIGTERM') {
|
|
161
|
-
logger.info('✅ Recording stopped by user');
|
|
162
|
-
} else if (!recordingFinished) {
|
|
163
|
-
logger.warn('Recording process ended unexpectedly: %s', error.message);
|
|
164
|
-
}
|
|
19
|
+
logger.info('DRY RUN: Would then delegate to regular commit command');
|
|
20
|
+
// In dry run, just call the regular commit command with empty audio context
|
|
21
|
+
return execute$1({
|
|
22
|
+
...runConfig,
|
|
23
|
+
commit: {
|
|
24
|
+
...runConfig.commit,
|
|
25
|
+
direction: ((_runConfig_commit1 = runConfig.commit) === null || _runConfig_commit1 === void 0 ? void 0 : _runConfig_commit1.direction) || ''
|
|
165
26
|
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
let audioContext;
|
|
30
|
+
try {
|
|
31
|
+
var _runConfig_audioCommit1, _runConfig_audioCommit2, _runConfig_audioCommit3, _runConfig_audioCommit4, _runConfig_audioCommit5;
|
|
32
|
+
// Process audio using the audio subsystem
|
|
33
|
+
logger.info('🎙️ Starting audio processing for commit context...');
|
|
34
|
+
if (!((_runConfig_audioCommit1 = runConfig.audioCommit) === null || _runConfig_audioCommit1 === void 0 ? void 0 : _runConfig_audioCommit1.file)) {
|
|
35
|
+
logger.info('This command will use your system\'s default audio recording tool');
|
|
36
|
+
logger.info('💡 Tip: Run "kodrdriv select-audio" to choose a specific microphone');
|
|
37
|
+
logger.info('Press Ctrl+C after you finish speaking to generate your commit message');
|
|
166
38
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
39
|
+
const result = await processAudio({
|
|
40
|
+
file: (_runConfig_audioCommit2 = runConfig.audioCommit) === null || _runConfig_audioCommit2 === void 0 ? void 0 : _runConfig_audioCommit2.file,
|
|
41
|
+
audioDevice: (_runConfig_audioCommit3 = runConfig.audioCommit) === null || _runConfig_audioCommit3 === void 0 ? void 0 : _runConfig_audioCommit3.audioDevice,
|
|
42
|
+
maxRecordingTime: (_runConfig_audioCommit4 = runConfig.audioCommit) === null || _runConfig_audioCommit4 === void 0 ? void 0 : _runConfig_audioCommit4.maxRecordingTime,
|
|
43
|
+
outputDirectory: runConfig.outputDirectory,
|
|
44
|
+
preferencesDirectory: runConfig.preferencesDirectory,
|
|
45
|
+
debug: runConfig.debug,
|
|
46
|
+
dryRun: isDryRun,
|
|
47
|
+
keepTemp: (_runConfig_audioCommit5 = runConfig.audioCommit) === null || _runConfig_audioCommit5 === void 0 ? void 0 : _runConfig_audioCommit5.keepTemp
|
|
48
|
+
});
|
|
49
|
+
// If the recording was cancelled, exit
|
|
50
|
+
if (result.cancelled) {
|
|
51
|
+
logger.info('❌ Audio commit cancelled by user');
|
|
52
|
+
process.exit(0);
|
|
179
53
|
}
|
|
180
|
-
|
|
181
|
-
logger.info('🎯 Transcribing audio...');
|
|
182
|
-
const transcription = await transcribeAudio(audioFilePath);
|
|
183
|
-
audioContext = transcription.text;
|
|
184
|
-
logger.info('✅ Audio transcribed successfully');
|
|
185
|
-
logger.debug('Transcription: %s', audioContext);
|
|
54
|
+
audioContext = result.transcript;
|
|
186
55
|
if (!audioContext.trim()) {
|
|
187
56
|
logger.warn('No audio content was transcribed. Proceeding without audio context.');
|
|
57
|
+
audioContext = '';
|
|
188
58
|
} else {
|
|
189
59
|
logger.info('📝 Using transcribed audio as commit context');
|
|
190
60
|
}
|
|
191
61
|
} catch (error) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
} finally{
|
|
196
|
-
// Clean up temporary directory
|
|
197
|
-
try {
|
|
198
|
-
await fs.rm(tempDir, {
|
|
199
|
-
recursive: true,
|
|
200
|
-
force: true
|
|
201
|
-
});
|
|
202
|
-
} catch (error) {
|
|
203
|
-
logger.debug('Failed to clean up temporary directory: %s', error.message);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
// Now proceed with commit logic using the transcribed audio as context
|
|
207
|
-
let cached = (_runConfig_commit1 = runConfig.commit) === null || _runConfig_commit1 === void 0 ? void 0 : _runConfig_commit1.cached;
|
|
208
|
-
// If `add` is used, we should always look at staged changes.
|
|
209
|
-
if ((_runConfig_commit2 = runConfig.commit) === null || _runConfig_commit2 === void 0 ? void 0 : _runConfig_commit2.add) {
|
|
210
|
-
cached = true;
|
|
211
|
-
} else if (cached === undefined) {
|
|
212
|
-
// If cached is undefined? We're going to look for a staged commit; otherwise, we'll use the supplied setting.
|
|
213
|
-
cached = await hasStagedChanges();
|
|
214
|
-
}
|
|
215
|
-
// Fix: Exit early if sendit is true but no changes are staged
|
|
216
|
-
if (((_runConfig_commit3 = runConfig.commit) === null || _runConfig_commit3 === void 0 ? void 0 : _runConfig_commit3.sendit) && !cached) {
|
|
217
|
-
logger.warn('SendIt mode enabled, but no changes to commit.');
|
|
218
|
-
process.exit(1);
|
|
219
|
-
}
|
|
220
|
-
var _runConfig_excludedPatterns;
|
|
221
|
-
const options = {
|
|
222
|
-
cached,
|
|
223
|
-
excludedPatterns: (_runConfig_excludedPatterns = runConfig.excludedPatterns) !== null && _runConfig_excludedPatterns !== void 0 ? _runConfig_excludedPatterns : DEFAULT_EXCLUDED_PATTERNS
|
|
224
|
-
};
|
|
225
|
-
const diff = await create$2(options);
|
|
226
|
-
const diffContent = await diff.get();
|
|
227
|
-
const logOptions = {
|
|
228
|
-
limit: (_runConfig_commit4 = runConfig.commit) === null || _runConfig_commit4 === void 0 ? void 0 : _runConfig_commit4.messageLimit
|
|
229
|
-
};
|
|
230
|
-
const log = await create$3(logOptions);
|
|
231
|
-
const logContent = await log.get();
|
|
232
|
-
// Use the transcribed audio as context, fallback to any configured context
|
|
233
|
-
const commitContext = audioContext.trim() || ((_runConfig_commit5 = runConfig.commit) === null || _runConfig_commit5 === void 0 ? void 0 : _runConfig_commit5.context) || '';
|
|
234
|
-
const prompt = await prompts.createCommitPrompt(diffContent, logContent, commitContext);
|
|
235
|
-
if (runConfig.debug) {
|
|
236
|
-
const formattedPrompt = Formatter.create({
|
|
237
|
-
logger
|
|
238
|
-
}).formatPrompt("gpt-4o-mini", prompt);
|
|
239
|
-
logger.silly('Formatted Prompt: %s', stringifyJSON(formattedPrompt));
|
|
240
|
-
}
|
|
241
|
-
const request = prompts.format(prompt);
|
|
242
|
-
if (runConfig.debug) {
|
|
243
|
-
const storage = create$1({
|
|
244
|
-
log: logger.info
|
|
245
|
-
});
|
|
246
|
-
await storage.ensureDirectory(outputDirectory);
|
|
247
|
-
}
|
|
248
|
-
const summary = await createCompletion(request.messages, {
|
|
249
|
-
model: runConfig.model,
|
|
250
|
-
debug: runConfig.debug,
|
|
251
|
-
debugRequestFile: runConfig.debug ? getOutputPath(outputDirectory, getTimestampedRequestFilename('audio-commit')) : undefined,
|
|
252
|
-
debugResponseFile: runConfig.debug ? getOutputPath(outputDirectory, getTimestampedResponseFilename('audio-commit')) : undefined
|
|
253
|
-
});
|
|
254
|
-
if ((_runConfig_commit6 = runConfig.commit) === null || _runConfig_commit6 === void 0 ? void 0 : _runConfig_commit6.sendit) {
|
|
255
|
-
if (!cached) {
|
|
256
|
-
logger.error('SendIt mode enabled, but no changes to commit. Message: \n\n%s\n\n', summary);
|
|
62
|
+
if (error.message.includes('No audio device configured')) {
|
|
63
|
+
logger.error('❌ No audio device configured. Please run "kodrdriv select-audio" first to configure your audio device.');
|
|
64
|
+
logger.info('💡 This will create %s/audio-device.yaml with your preferred audio device.', runConfig.preferencesDirectory);
|
|
257
65
|
process.exit(1);
|
|
258
66
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
]);
|
|
264
|
-
await run(`git commit -m ${escapedSummary}`);
|
|
265
|
-
logger.info('Commit successful!');
|
|
266
|
-
} catch (error) {
|
|
267
|
-
logger.error('Failed to commit:', error);
|
|
67
|
+
// If audio recording failed, exit instead of continuing
|
|
68
|
+
if (error.message.includes('Audio recording failed')) {
|
|
69
|
+
logger.error('❌ Audio recording failed. Cannot proceed with audio-commit command.');
|
|
70
|
+
logger.info('💡 Try running "kodrdriv select-audio" to choose a different audio device');
|
|
268
71
|
process.exit(1);
|
|
269
72
|
}
|
|
73
|
+
logger.error('Audio processing failed: %s', error.message);
|
|
74
|
+
logger.info('Proceeding with commit generation without audio context...');
|
|
75
|
+
audioContext = '';
|
|
270
76
|
}
|
|
271
|
-
|
|
77
|
+
// Now delegate to the regular commit command with the audio context
|
|
78
|
+
logger.info('🤖 Generating commit message using audio context...');
|
|
79
|
+
const result = await execute$1({
|
|
80
|
+
...runConfig,
|
|
81
|
+
commit: {
|
|
82
|
+
...runConfig.commit,
|
|
83
|
+
direction: audioContext.trim() || ((_runConfig_commit = runConfig.commit) === null || _runConfig_commit === void 0 ? void 0 : _runConfig_commit.direction) || ''
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
// Cleanup is handled by the audio processor
|
|
87
|
+
return result;
|
|
272
88
|
};
|
|
273
89
|
|
|
274
90
|
export { execute };
|