// Detached Windows lifetime owner: no services, registry changes or test profile. import { spawn } from 'node:child_process'; import { writeFileSync } from 'node:fs'; import { redact } from './core.mjs'; const [repoRoot, resultFile] = process.argv.slice(2); if (!repoRoot || !resultFile || process.platform !== 'win32') process.exit(2); const child = spawn(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', 'npm run dev'], { cwd: repoRoot, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], env: { ...process.env, YCODE_SKIP_KERNEL_DATA_RESET: '1' } }); // Line buffering avoids leaking credentials split across stream chunks. Oversized // lines are omitted, rather than persisting partial unredacted secrets. for (const stream of [child.stdout, child.stderr]) { stream.setEncoding('utf8'); let pending = '', dropping = false; stream.on('data', chunk => { for (const part of chunk.match(/[^\n]*\n|[^\n]+$/g) || []) { if (!dropping) pending += part; if (pending.length > 65536) { pending = ''; dropping = true; } if (part.endsWith('\n')) { process.stdout.write(dropping ? '[oversized log line omitted]\n' : redact(pending)); pending = ''; dropping = false; } } }); stream.on('end', () => { if (pending && !dropping) process.stdout.write(redact(pending)); }); } child.on('error', error => { writeFileSync(resultFile, JSON.stringify({ code: 'SPAWN_FAILED', message: redact(error.message) })); process.exitCode = 1; }); child.on('exit', (code, signal) => { writeFileSync(resultFile, JSON.stringify({ code: 'DEV_EXITED', exitCode: code, signal })); process.exitCode = code ?? 1; });