Repository: tauri-apps/tauri (language: rust)

Issue:
[bug] Automatic migration does not update `@tauri-apps/api`
### Describe the bug

I recently migrated from Tauri v1 to v2. I used `yarn` and the automatic migration script offered. When I compiled my app, IPC did  not work at all. Turns out that `@tauri-apps/api` was not updated to version v2.

### Reproduction

1. `yarn up @tauri-apps/cli@latest `
2. `yarn tauri migrate `
3. `yarn tauri build`


### Expected behavior

I expected that the automatic migration script upgrades `@tauri-apps/api` to 2.0.3 (current latest).

### Full `tauri info` output

```text
[✔] Environment
    - OS: Windows 10.0.22631 x86_64 (X64)
    ✔ WebView2: 129.0.2792.89
    ✔ MSVC:
        - Visual Studio Build Tools 2019
        - Visual Studio Community 2022
    ✔ rustc: 1.78.0 (9b00956e5 2024-04-29)
    ✔ cargo: 1.78.0 (54d8815d0 2024-03-26)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-x86_64-pc-windows-msvc (default)
    - node: 22.4.1
    - yarn: 4.5.1
    - npm: 10.8.3

[-] Packages
    - tauri 🦀: 2.0.6
    - tauri-build 🦀: 2.0.2
    - wry 🦀: 0.46.3
    - tao 🦀: 0.30.3
    - @tauri-apps/api : 1.6.0 (outdated, latest: 2.0.3)
    - @tauri-apps/cli : 2.0.5


[-] Plugins

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../build
    - devUrl: http://localhost:8080/
    - framework: Svelte
    - bundler: Vite
```



Discussion / hints:
I guess based on `tauri info` one could resolve the issue by seeing how it is outdated, but it might be worth considering adding some warning or even enhancing the migration script. Or did I miss something from the docs that referred to this problem?

Cheers.
I wasn't able to reproduce, could you share the project that failed to migrate or a minimal repro?
The multirepo [here](https://github.com/Wrench56/Turbotrace) contains the client subproject that contains the codebase for Tauri. I had to manually bump the version of `@tauri-apps/api`. The `main` branch still has the old version if you want to test it on that. Again, just for clarity, I use yarn.

Edit: [Here](https://github.com/Wrench56/TurboTrace/commit/22c5983474c22821274123fedefebb6b8dcf37e7) is the exact commit that has Tauri v1.

Fix patch:
diff --git a/.changes/cli-yarn-berry.md b/.changes/cli-yarn-berry.md
new file mode 100644
index 000000000000..6c75565de6b6
--- /dev/null
+++ b/.changes/cli-yarn-berry.md
@@ -0,0 +1,6 @@
+---
+"tauri-cli": "patch:bug"
+"@tauri-apps/cli": "patch:bug"
+---
+
+Fix detecting yarn berry (v2 and higher) in various tauri cli commands.
diff --git a/crates/tauri-cli/src/add.rs b/crates/tauri-cli/src/add.rs
index ceb73533326e..f02771d97fe3 100644
--- a/crates/tauri-cli/src/add.rs
+++ b/crates/tauri-cli/src/add.rs
@@ -81,10 +81,7 @@ pub fn run(options: Options) -> Result<()> {
   })?;
 
   if !metadata.rust_only {
-    if let Some(manager) = frontend_dir
-      .map(PackageManager::from_project)
-      .and_then(|managers| managers.into_iter().next())
-    {
+    if let Some(manager) = frontend_dir.map(PackageManager::from_project) {
       let npm_version_req = version
         .map(ToString::to_string)
         .or(metadata.version_req.as_ref().map(|v| match manager {
diff --git a/crates/tauri-cli/src/helpers/npm.rs b/crates/tauri-cli/src/helpers/npm.rs
index 8e6134bb1bf9..d1591f78dfdb 100644
--- a/crates/tauri-cli/src/helpers/npm.rs
+++ b/crates/tauri-cli/src/helpers/npm.rs
@@ -7,6 +7,22 @@ use anyhow::Context;
 use crate::helpers::cross_command;
 use std::{fmt::Display, path::Path, process::Command};
 
+pub fn manager_version(package_manager: &str) -> Option<String> {
+  cross_command(package_manager)
+    .arg("-v")
+    .output()
+    .map(|o| {
+      if o.status.success() {
+        let v = String::from_utf8_lossy(o.stdout.as_slice()).to_string();
+        Some(v.split('\n').next().unwrap().to_string())
+      } else {
+        None
+      }
+    })
+    .ok()
+    .unwrap_or_default()
+}
+
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 pub enum PackageManager {
   Npm,
@@ -35,7 +51,16 @@ impl Display for PackageManager {
 }
 
 impl PackageManager {
-  pub fn from_project<P: AsRef<Path>>(path: P) -> Vec<Self> {
+  /// Detects package manager from the given directory, falls back to [`PackageManager::Npm`].
+  pub fn from_project<P: AsRef<Path>>(path: P) -> Self {
+    Self::all_from_project(path)
+      .first()
+      .copied()
+      .unwrap_or(Self::Npm)
+  }
+
+  /// Detects all possible package managers from the given directory.
+  pub fn all_from_project<P: AsRef<Path>>(path: P) -> Vec<Self> {
     let mut found = Vec::new();
 
     if let Ok(entries) = std::fs::read_dir(path) {
@@ -47,7 +72,15 @@ impl PackageManager {
         } else if name.as_ref() == "pnpm-lock.yaml" {
           found.push(PackageManager::Pnpm);
         } else if name.as_ref() == "yarn.lock" {
-          found.push(PackageManager::Yarn);
+          let yarn = if manager_version("yarn")
+            .map(|v| v.chars().next().map(|c| c > '1').unwrap_or_default())
+            .unwrap_or(false)
+          {
+            PackageManager::YarnBerry
+          } else {
+            PackageManager::Yarn
+          };
+          found.push(yarn);
         } else if name.as_ref() == "bun.lockb" {
           found.push(PackageManager::Bun);
         } else if name.as_ref() == "deno.lock" {
diff --git a/crates/tauri-cli/src/info/env_nodejs.rs b/crates/tauri-cli/src/info/env_nodejs.rs
index 5d210429ca41..eb9938eee72d 100644
--- a/crates/tauri-cli/src/info/env_nodejs.rs
+++ b/crates/tauri-cli/src/info/env_nodejs.rs
@@ -5,23 +5,7 @@
 use super::{ActionResult, SectionItem, VersionMetadata};
 use colored::Colorize;
 
-use crate::helpers::cross_command;
-
-pub fn manager_version(package_manager: &str) -> Option<String> {
-  cross_command(package_manager)
-    .arg("-v")
-    .output()
-    .map(|o| {
-      if o.status.success() {
-        let v = String::from_utf8_lossy(o.stdout.as_slice()).to_string();
-        Some(v.split('\n').next().unwrap().to_string())
-      } else {
-        None
-      }
-    })
-    .ok()
-    .unwrap_or_default()
-}
+use crate::helpers::{cross_command, npm::manager_version};
 
 pub fn items(metadata: &VersionMetadata) -> Vec<SectionItem> {
   let node_target_ver = metadata.js_cli.node.replace(">= ", "");
diff --git a/crates/tauri-cli/src/info/packages_nodejs.rs b/crates/tauri-cli/src/info/packages_nodejs.rs
index f484ffd20e7a..73b87d8b7803 100644
--- a/crates/tauri-cli/src/info/packages_nodejs.rs
+++ b/crates/tauri-cli/src/info/packages_nodejs.rs
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: MIT
 
 use super::SectionItem;
-use super::{env_nodejs::manager_version, VersionMetadata};
+use super::VersionMetadata;
 use colored::Colorize;
 use serde::Deserialize;
 use std::path::PathBuf;
@@ -77,7 +77,7 @@ pub fn npm_latest_version(pm: &PackageManager, name: &str) -> crate::Result<Opti
 }
 
 pub fn package_manager(frontend_dir: &PathBuf) -> PackageManager {
-  let found = PackageManager::from_project(frontend_dir);
+  let found = PackageManager::all_from_project(frontend_dir);
 
   if found.is_empty() {
     println!(
@@ -98,15 +98,7 @@ pub fn package_manager(frontend_dir: &PathBuf) -> PackageManager {
         );
   }
 
-  if pkg_manager == PackageManager::Yarn
-    && manager_version("yarn")
-      .map(|v| v.chars().next().map(|c| c > '1').unwrap_or_default())
-      .unwrap_or(false)
-  {
-    PackageManager::YarnBerry
-  } else {
-    pkg_manager
-  }
+  pkg_manager
 }
 
 pub fn items(
diff --git a/crates/tauri-cli/src/init.rs b/crates/tauri-cli/src/init.rs
index cbd4ae1a0ef5..f12bc4abf00e 100644
--- a/crates/tauri-cli/src/init.rs
+++ b/crates/tauri-cli/src/init.rs
@@ -131,10 +131,7 @@ impl Options {
       )
     })?;
 
-    let detected_package_manager = match PackageManager::from_project(&self.directory).first() {
-      Some(&package_manager) => package_manager,
-      None => PackageManager::Npm,
-    };
+    let detected_package_manager = PackageManager::from_project(&self.directory);
 
     self.before_dev_command = self
       .before_dev_command
diff --git a/crates/tauri-cli/src/migrate/migrations/v1/frontend.rs b/crates/tauri-cli/src/migrate/migrations/v1/frontend.rs
index 83f906a905cc..8ad2771f3554 100644
--- a/crates/tauri-cli/src/migrate/migrations/v1/frontend.rs
+++ b/crates/tauri-cli/src/migrate/migrations/v1/frontend.rs
@@ -84,10 +84,7 @@ pub fn migrate(frontend_dir: &Path) -> Result<Vec<String>> {
     )
   };
 
-  let pm = PackageManager::from_project(frontend_dir)
-    .into_iter()
-    .next()
-    .unwrap_or(PackageManager::Npm);
+  let pm = PackageManager::from_project(frontend_dir);
 
   for pkg in ["@tauri-apps/cli", "@tauri-apps/api"] {
     let version = pm
diff --git a/crates/tauri-cli/src/migrate/migrations/v2_rc.rs b/crates/tauri-cli/src/migrate/migrations/v2_rc.rs
index 50ce8a37b10e..844c7de048be 100644
--- a/crates/tauri-cli/src/migrate/migrations/v2_rc.rs
+++ b/crates/tauri-cli/src/migrate/migrations/v2_rc.rs
@@ -35,10 +35,7 @@ pub fn run() -> Result<()> {
 }
 
 fn migrate_npm_dependencies(frontend_dir: &Path) -> Result<()> {
-  let pm = PackageManager::from_project(frontend_dir)
-    .into_iter()
-    .next()
-    .unwrap_or(PackageManager::Npm);
+  let pm = PackageManager::from_project(frontend_dir);
 
   let mut install_deps = Vec::new();
   for pkg in [


Test patch: