// Extract actual USB diagnostic, microphone callback and manager failure path. import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import {fileURLToPath} from 'node:url'; const here = path.dirname(fileURLToPath(import.meta.url)); const root = path.resolve(here, '..'); const names = ['main/conv_ai_embedded_kit.c', 'components/application/service/conv_service/src/volc_conv.c', 'components/application/service/conv_service/src/volc_conv_service.c', 'components/volc_conv_ai/src/transports/high_quality/src/volc_rtc.c']; const sha = b => crypto.createHash('sha256').update(b).digest('hex'); const raw = names.map(p => fs.readFileSync(path.join(root,p))); const texts = raw.map(b => b.toString('utf8').replaceAll('\r\n','\n')); function between(text,start,end) { const a=text.indexOf(start), b=text.indexOf(end,a); if(a<0 || b<0) throw new Error('Missing source marker '+start); return text.slice(a,b+end.length); } const production = [ '#define CONV_SERVICE_TIMEOUT 60\n' + between(texts[1],'/* CALL_IDLE_BEGIN:', '/* CALL_IDLE_END */'), between(texts[0],'/* RTC_PRIORITY_DIAGNOSTIC_BEGIN:', '/* RTC_PRIORITY_DIAGNOSTIC_END */'), between(texts[1],'/* VOICE_DIAGNOSTIC_BEGIN:', '/* VOICE_DIAGNOSTIC_END */'), between(texts[3],'/* RTC_SELF_PRIORITY_BEGIN:', '/* RTC_SELF_PRIORITY_END */'), // Existing capture callback accepts a positive int length; the cast retains // its loop bound and makes that conversion explicit for host -Wsign-compare. between(texts[1],'static void __audio_capture_cb(', '\n}').replace('i < len / sizeof(int16_t)', 'i < (int)(len / sizeof(int16_t))'), between(texts[2],'static aios_ret_t __state_conversation(', '\n}'), ].join('\n\n'); // Verify real end/error paths still route through the tested reset function. for (const start of ['CONV_AI_QUIT:', 'void conv_ai_service_task_stop(']) { const tail=texts[1].slice(texts[1].indexOf(start)); if(!tail.slice(0,1500).includes('diagnostic_close();')) throw new Error('Missing reset '+start); } if(!between(texts[1],'void conv_ai_service_prepare_task(', '\n}').includes('diagnostic_prepare();')) throw new Error('Missing prepare gate'); const template=fs.readFileSync(path.join(here,'test_voice_diagnostic_host.c.in'),'utf8'); if(template.split('/* @PRODUCTION@ */').length!==2) throw new Error('Invalid template'); const output=path.resolve(process.argv[2] ?? path.join(here,'voice-diagnostic-host.c')); fs.mkdirSync(path.dirname(output),{recursive:true}); fs.writeFileSync(output,template.replace('/* @PRODUCTION@ */',production)); const manifest={source_rows:names.map((p,i)=>({path:path.join(root,p),sha256:sha(raw[i])})), output,host_sha256:sha(fs.readFileSync(output)), build:'clang -std=c11 -g -O1 -fsanitize=undefined -fno-omit-frame-pointer voice-diagnostic-host.c -o voice-diagnostic-host'}; fs.writeFileSync(output+'.json',JSON.stringify(manifest,null,2)+'\n'); console.log(JSON.stringify(manifest));