/** Match Plutainer's apply_rcon_password, including its newline handling. * Keep the original bytes when the password already matches: its Python reader * normalizes line endings, but only writes the normalized text after a change. */ export function applyRuntimePassword(text: string, password?: string | null): string { if (!password) return text; const lines = text.replace(/\r\n|\r/g, '\n').split('\n'); const replacement = `"${password.replaceAll('"', '')}"`; const pattern = /^(\s*(?:set[a]?\s+)?rcon_password\s+)("[^"]*"|'[^']*'|\S+)(.*)$/i; let matched = false; let changed = false; for (let i = 0; i < lines.length; i++) { const match = pattern.exec(lines[i]); if (!match) continue; matched = true; if (match[2] === replacement) continue; lines[i] = match[1] + replacement + match[3]; changed = true; } if (!matched) { if (lines.at(-1) === '') lines.pop(); lines.push('', '// Added by Plutainer from PLUTAINER_RCON_PASSWORD.', `set rcon_password ${replacement}`, ''); changed = true; } return changed ? lines.join('\n') : text; } /** Uses aliases o (operation) and i (instance). Rebuild commands target the old * generation; their successful result owns the next one. Never use a queued * rebuild's password for the instance that is still running. */ export const runtimeLaunchSql = `o.instance_id=i.id AND o.host_id=i.host_id AND o.kind IN ('instance.create','instance.rebuild') AND ((o.kind='instance.create' AND o.generation=i.generation) OR (o.kind='instance.rebuild' AND o.generation+1=i.generation))`;