import test from 'node:test' import assert from 'node:assert/strict' import { taskText, taskState } from '../src/behavior.mjs' import { VoiceSession, pcm16 } from '../src/voice.mjs' test('research envelope preserves corrections and never broadens permission', () => { const text = taskText({ intent: 'research', objective: 'Erişilebilirliği incele', scope: 'Yalnız Android', context: 'Mavi iptal edildi; yeşil olsun.', constraints: 'Kod değişikliği yapma.', output: 'Rapor', completion: 'Kanıtları belirt.' }) assert.match(text, /Değişiklik yapma/); assert.match(text, /Mavi iptal edildi; yeşil olsun/) assert.throws(() => taskText({ intent: 'execute', objective: 'test' }), /eksik/) }) test('voice cannot call raw IDE approval, submit or stop RPCs', async () => { const replies = [], drafts = [] const session = new VoiceSession({ onDraft: (...args) => drafts.push(args) }) session.send = frame => replies.push(frame) for (const name of ['approval.respond', 'task.submit', 'message.stop']) { await session.receive({ data: JSON.stringify({ toolCall: { functionCalls: [{ id: name, name, args: { choice: 'once' } }] } }) }) } assert.equal(drafts.length, 0); assert.equal(replies.length, 3) assert.ok(replies.every(reply => reply.toolResponse.functionResponses[0].response.error)) }) test('discussions and absent terminal events cannot claim completion', () => { assert.equal(taskState({ event: 'transcription', text: 'Tamamlandı' }), null) assert.match(taskState({ event: 'disconnected' }), /bilinmiyor/) assert.match(taskState({ event: 'approval.request' }), /bekliyor/) assert.match(taskState({ event: 'message.complete', status: 'error' }), /error/) }) test('PCM is little endian, clipped, and uses 16k sample output', () => { const bytes = Buffer.from(pcm16(new Float32Array([-2, 0, 2]), 16000), 'base64') assert.equal(bytes.readInt16LE(0), -32768); assert.equal(bytes.readInt16LE(4), 32767) assert.equal(Buffer.from(pcm16(new Float32Array(480), 48000), 'base64').length, 320) }) test('stopping voice frees every microphone and queued sound without IDE calls', () => { let tracks = 0, sounds = 0, closed = 0 const voice = new VoiceSession({ onState: () => {} }) voice.stream = { getTracks: () => [{ stop() { tracks++ } }] } voice.sources.add({ stop() { sounds++ } }); voice.socket = { close() { closed++ } } voice.stop(); voice.stop() assert.deepEqual([tracks, sounds, closed], [1, 1, 1]) })