User: Переделай этот код на использование spawn

const childProcess = exec("sh update.sh", { cwd: dirPath });

  childProcess.stdout.on("data", (stdout) => {
    setMarkdown((prev) => `${prev}\n\n### Log:\n${stdout}`);
    console.log("!!!!!", stdout);
    // check for the "DEV" or "DONE" string to determine if the update was successful
    if (stdout.trim() === "DEV" || stdout.trim() === "DONE") {
      setMarkdown((prev) => `${prev}\n\n# Update successful!`);
      showToast(Toast.Style.Success, "Update successful");
      popToRoot();
    }
  });
  childProcess.stderr.on("data", (stderr) => {
    setMarkdown((prev) => `${prev}\n\n### Error log: \n${stderr}`);
  });
  childProcess.on("error", (error) => {
    setMarkdown((prev) => `${prev}\n\n#@ Update failed!\nError: ${error}`);
    showToast(Toast.Style.Failure, "Update failed");
  });
Assistant: Для использования `spawn` вместо `exec`, вы должны учесть, что `spawn` не будет выполнять команду в оболочке. Это означает, что вы не можете передать всю строку команды в виде единого аргумента, как это делается в `exec`. Вместо этого, команда и ее аргументы должны быть переданы отдельными значениями в массив. Также обратите внимание, что `spawn` возвращает поток, с которым можно работать так же, как и с `exec`, но немного отличается в отношении обработки ошибок и завершения процесса. Вот как можно адаптировать ваш код:

```javascript
const { spawn } = require('child_process');

// Разделение команды "sh update.sh" на части: "sh" и "update.sh"
const childProcess = spawn('sh', ['update.sh'], { cwd: dirPath });

childProcess.stdout.on('data', (stdout) => {
  setMarkdown((prev) => `${prev}

### Log:
${stdout}`);
  console.log("!!!!!", stdout);
  // Проверка на наличие строки "DEV" или "DONE" для определения успешности обновления
  if (stdout.toString().trim() === "DEV" || stdout.toString().trim() === "DONE") {
    setMarkdown((prev) => `${prev}

# Update successful!`);
    showToast(Toast.Style.Success, "Update successful");
    popToRoot();
  }
});

childProcess.stderr.on('data', (stderr) => {
  setMarkdown((prev) => `${prev}

### Error log: 
${stderr}`);
});

childProcess.on('error', (error) => {
  setMarkdown((prev) => `${prev}

# Update failed!
Error: ${error}`);
  showToast(Toast.Style.Failure, "Update failed");
});

childProcess.on('close', (code) => {
  if (code !== 0) {
    console.log(`child process exited with code ${code}`);
  }
});
```

Некоторые ключевые отличия:
- `spawn` принимает команду и массив её аргументов.
- `stdout` и `stderr` потоки могут выводить `Buffer`, поэтому вызов `toString()` может быть необходим, чтобы преобразовать их в строку.
- Для обработки завершения процесса используется событие `'close'`, которое получает код
User: Мне нужен открепленный спавн, который не умрет, если нода завершит выполнение
Assistant: Для создания открепленного процесса с использованием `spawn`, который будет продолжать выполняться даже после завершения основного процесса Node.js, вам нужно установить свойство `detached` в `true` и обеспечить соответствующую настройку потоков ввода-вывода. Вот как можно изменить ваш код:

```javascript
const { spawn } = require('child_process');

// Разделение команды "sh update.sh" на части: "sh" и "update.sh"
const childProcess = spawn('sh', ['update.sh'], {
  cwd: dirPath,
  detached: true,   // Открепляем процесс
  stdio: ['ignore', 'pipe', 'pipe'] // Игнорируем stdin, но pipe stdout и stderr
});

childProcess.unref(); // Этот вызов позволяет открепленному процессу работать после завершения основного процесса

childProcess.stdout.on('data', (stdout) => {
  setMarkdown((prev) => `${prev}

### Log:
${stdout}`);
  console.log("!!!!!", stdout);
  // Проверка на наличие строки "DEV" или "DONE" для определения успешности обновления
 
User: Как мне в childProcess.stdout.on получать строку?
Assistant: