Resolve workspace root and workPackage when invoking pub from any sub-directory (#4186)

diff --git a/lib/src/command/add.dart b/lib/src/command/add.dart
index 9d74d3e..88f4bf5 100644
--- a/lib/src/command/add.dart
+++ b/lib/src/command/add.dart
@@ -256,8 +256,7 @@
     }
 
     String? overridesFileContents;
-    final overridesPath =
-        p.join(entrypoint.workspaceRoot.dir, Pubspec.pubspecOverridesFilename);
+    final overridesPath = entrypoint.workspaceRoot.pubspecOverridesPath;
     try {
       overridesFileContents = readTextFile(overridesPath);
     } on IOException {
@@ -268,7 +267,7 @@
     /// gets a report on the other packages that might change version due
     /// to this new dependency.
     await entrypoint
-        .withPubspec(
+        .withWorkPubspec(
           Pubspec.parse(
             newPubspecText,
             cache.sources,
diff --git a/lib/src/command/remove.dart b/lib/src/command/remove.dart
index 152c1df..11eea6b 100644
--- a/lib/src/command/remove.dart
+++ b/lib/src/command/remove.dart
@@ -93,7 +93,7 @@
     final rootPubspec = entrypoint.workspaceRoot.pubspec;
     final newPubspec = _removePackagesFromPubspec(rootPubspec, targets);
 
-    await entrypoint.withPubspec(newPubspec).acquireDependencies(
+    await entrypoint.withWorkPubspec(newPubspec).acquireDependencies(
           SolveType.get,
           precompile: !isDryRun && argResults.flag('precompile'),
           dryRun: isDryRun,
diff --git a/lib/src/command/upgrade.dart b/lib/src/command/upgrade.dart
index 91b0e26..1832187 100644
--- a/lib/src/command/upgrade.dart
+++ b/lib/src/command/upgrade.dart
@@ -364,7 +364,7 @@
     }
 
     await entrypoint
-        .withPubspec(_updatedPubspec(newPubspecText, entrypoint))
+        .withWorkPubspec(_updatedPubspec(newPubspecText, entrypoint))
         .acquireDependencies(
           solveType,
           dryRun: _dryRun,
diff --git a/lib/src/entrypoint.dart b/lib/src/entrypoint.dart
index e20ef20..45b7cfd 100644
--- a/lib/src/entrypoint.dart
+++ b/lib/src/entrypoint.dart
@@ -33,6 +33,7 @@
 import 'solver/report.dart';
 import 'solver/solve_suggestions.dart';
 import 'source/cached.dart';
+import 'source/root.dart';
 import 'source/unknown.dart';
 import 'system_cache.dart';
 import 'utils.dart';
@@ -58,25 +59,112 @@
   ///
   /// [workspaceRoot] will be the package in the nearest parent directory that
   /// has `resolution: null`
-  // TODO(https://github.com/dart-lang/pub/issues/4127): make this actually
-  // true.
   final String workingDir;
 
-  Package? _workspaceRoot;
+  /// Finds the [workspaceRoot] and [workPackage] based on [workingDir].
+  ///
+  /// Works by iterating through the parent directories from [workingDir].
+  ///
+  /// [workPackage] is the package of first dir we find with a `pubspec.yaml`
+  /// file.
+  ///
+  /// [workspaceRoot] is the package of the first dir we find with a
+  /// `pubspec.yaml` that does not have `resolution: workspace`.
+  ///
+  /// [workPackage] and [workspaceRoot] can be the same. And will always be the
+  /// same when no `workspace` is involved.
+  /// =
+  /// If [workingDir] doesn't exist, [fail].
+  ///
+  /// If no `pubspec.yaml` is found without `resolution: workspace` we [fail].
+  static ({Package root, Package work}) _loadWorkspace(
+    String workingDir,
+    SystemCache cache,
+  ) {
+    if (!dirExists(workingDir)) {
+      fail('The directory `$workingDir` does not exist.');
+    }
+    // Keep track of all the pubspecs met when walking up the file system.
+    // The first of these is the workingPackage.
+    final pubspecsMet = <String, Pubspec>{};
+    for (final dir in parentDirs(workingDir)) {
+      final Pubspec pubspec;
+
+      try {
+        pubspec = Pubspec.load(
+          dir,
+          cache.sources,
+          containingDescription: RootDescription(dir),
+          allowOverridesFile: true,
+        );
+      } on FileException {
+        continue;
+      }
+      pubspecsMet[p.canonicalize(dir)] = pubspec;
+      final Package root;
+      if (pubspec.resolution == Resolution.none) {
+        root = Package.load(
+          dir,
+          cache.sources,
+          loadPubspec: (
+            path, {
+            expectedName,
+            required withPubspecOverrides,
+          }) =>
+              pubspecsMet[p.canonicalize(path)] ??
+              Pubspec.load(
+                path,
+                cache.sources,
+                expectedName: expectedName,
+                allowOverridesFile: withPubspecOverrides,
+                containingDescription: RootDescription(path),
+              ),
+          withPubspecOverrides: true,
+        );
+        for (final package in root.transitiveWorkspace) {
+          if (identical(pubspecsMet.entries.first.value, package.pubspec)) {
+            return (root: root, work: package);
+          }
+        }
+        assert(false);
+      }
+    }
+    if (pubspecsMet.isEmpty) {
+      throw FileException(
+        'Found no `pubspec.yaml` file in `${p.normalize(p.absolute(workingDir))}` or parent directories',
+        p.join(workingDir, 'pubspec.yaml'),
+      );
+    } else {
+      final firstEntry = pubspecsMet.entries.first;
+      throw FileException(
+        '''
+Found a pubspec.yaml at ${firstEntry.key}. But it has resolution `${firstEntry.value.resolution.name}`.
+But found no workspace root including it in parent directories.
+
+See $workspacesDocUrl for more information.''',
+        p.join(workingDir, 'pubspec.yaml'),
+      );
+    }
+  }
+
+  /// Stores the result of [_loadWorkspace].
+  /// Only access via [workspaceRoot], [workPackage] and [canFindWorkspaceRoot].
+  ({Package root, Package work})? _packages;
+
+  /// Only access via [workspaceRoot], [workPackage] and [canFindWorkspaceRoot].
+  ({Package root, Package work}) get _getPackages =>
+      _packages ??= _loadWorkspace(workingDir, cache);
 
   /// The root package this entrypoint is associated with.
   ///
   /// For a global package, this is the activated package.
-  Package get workspaceRoot => _workspaceRoot ??= Package.load(
-        null,
-        workingDir,
-        cache.sources,
-        withPubspecOverrides: true,
-      );
+  Package get workspaceRoot => _getPackages.root;
 
+  /// True if we can find a `pubspec.yaml` to resolve in [workingDir] or any
+  /// parent directory.
   bool get canFindWorkspaceRoot {
     try {
-      workspaceRoot;
+      _getPackages;
       return true;
     } on FileException {
       return false;
@@ -87,8 +175,6 @@
   ///
   /// It will be the package in the nearest parent directory to `workingDir`.
   /// Example: if a workspace looks like this:
-  // TODO(https://github.com/dart-lang/pub/issues/4127): make this actually
-  // true.
   ///
   /// foo/ pubspec.yaml # contains `workspace: [- 'bar'] bar/ pubspec.yaml #
   ///   contains `resolution: workspace`.
@@ -98,7 +184,7 @@
   ///
   /// Running `pub add` in `foo` will have foo as workPackage, and add
   /// dependencies to `foo/pubspec.yaml`.
-  Package get workPackage => workspaceRoot;
+  Package get workPackage => _getPackages.work;
 
   /// The system-wide cache which caches packages that need to be fetched over
   /// the network.
@@ -193,9 +279,9 @@
     var packages = {
       for (var packageEntry in packageConfig.nonInjectedPackages)
         packageEntry.name: Package.load(
-          packageEntry.name,
           packageEntry.resolvedRootDir(packageConfigPath),
           cache.sources,
+          expectedName: packageEntry.name,
         ),
     };
     packages[workspaceRoot.name] = workspaceRoot;
@@ -229,46 +315,59 @@
     this._example,
     this._packageGraph,
     this.cache,
-    this._workspaceRoot,
+    this._packages,
     this.isCachedGlobal,
   );
 
-  /// An entrypoint representing a package at [rootDir].
+  /// An entrypoint for the workspace containing [workingDir]/
   ///
   /// If [checkInCache] is `true` (the default) an error will be thrown if
   /// [rootDir] is located inside [cache.rootDir].
+
   Entrypoint(
     this.workingDir,
     this.cache, {
-    ({Pubspec pubspec, List<Package> workspacePackages})? preloaded,
     bool checkInCache = true,
-  })  : _workspaceRoot = preloaded == null
-            ? null
-            : Package(
-                preloaded.pubspec,
-                workingDir,
-                preloaded.workspacePackages,
-              ),
-        isCachedGlobal = false {
+  }) : isCachedGlobal = false {
     if (checkInCache && p.isWithin(cache.rootDir, workingDir)) {
       fail('Cannot operate on packages inside the cache.');
     }
   }
 
   /// Creates an entrypoint at the same location, that will use [pubspec] for
-  /// resolution.
-  Entrypoint withPubspec(Pubspec pubspec) {
+  /// resolution of the [workPackage].
+  Entrypoint withWorkPubspec(Pubspec pubspec) {
+    final existingPubspecs = <String, Pubspec>{};
+    // First extract all pubspecs from the workspace.
+    for (final package in workspaceRoot.transitiveWorkspace) {
+      existingPubspecs[package.dir] = package.pubspec;
+    }
+    // Then override the one of the workPackage.
+    existingPubspecs[p.canonicalize(workPackage.dir)] = pubspec;
+    final newWorkspaceRoot = Package.load(
+      workspaceRoot.dir,
+      cache.sources,
+      loadPubspec: (
+        dir, {
+        expectedName,
+        required withPubspecOverrides,
+      }) =>
+          existingPubspecs[p.canonicalize(dir)] ??
+          Pubspec.load(
+            dir,
+            cache.sources,
+            containingDescription: RootDescription(dir),
+          ),
+    );
+    final newWorkPackage = newWorkspaceRoot.transitiveWorkspace
+        .firstWhere((package) => package.dir == workPackage.dir);
     return Entrypoint._(
       workingDir,
       _lockFile,
       _example,
       _packageGraph,
       cache,
-      Package(
-        pubspec,
-        workingDir,
-        workspaceRoot.workspaceChildren,
-      ),
+      (root: newWorkspaceRoot, work: newWorkPackage),
       isCachedGlobal,
     );
   }
@@ -276,11 +375,12 @@
   /// Creates an entrypoint given package and lockfile objects.
   /// If a SolveResult is already created it can be passed as an optimization.
   Entrypoint.global(
-    Package this._workspaceRoot,
+    Package package,
     this._lockFile,
     this.cache, {
     SolveResult? solveResult,
-  })  : workingDir = _workspaceRoot.dir,
+  })  : _packages = (root: package, work: package),
+        workingDir = package.dir,
         isCachedGlobal = true {
     if (solveResult != null) {
       _packageGraph =
@@ -410,7 +510,7 @@
   }) async {
     workspaceRoot; // This will throw early if pubspec.yaml could not be found.
     summaryOnly = summaryOnly || _summaryOnlyEnvironment;
-    final suffix = workspaceRoot.dir == '.' ? '' : ' in ${workspaceRoot.dir}';
+    final suffix = workspaceRoot.dir == '.' ? '' : ' in `${workspaceRoot.dir}`';
 
     if (enforceLockfile && !fileExists(lockFilePath)) {
       throw ApplicationException('''
@@ -978,7 +1078,7 @@
       }
       var touchedLockFile = false;
       late final lockFile = _loadLockFile(lockFilePath, cache);
-      late final root = Package.load(null, dir, cache.sources);
+      late final root = Package.load(dir, cache.sources);
 
       if (!lockfileNewerThanPubspecs) {
         if (isLockFileUpToDate(lockFile, root)) {
diff --git a/lib/src/io.dart b/lib/src/io.dart
index af86eae..fabafa3 100644
--- a/lib/src/io.dart
+++ b/lib/src/io.dart
@@ -1229,3 +1229,32 @@
     RegExp(r'^[a-zA-Z0-9-_=@.^]+$').stringMatch(x) == null
         ? "'${x.replaceAll(r'\', r'\\').replaceAll("'", r"'\''")}'"
         : x;
+
+/// Returns all parent directories of [path], starting from [path] to the
+/// filesystem root.
+///
+/// If [path] is relative the directories will also be.
+///
+/// If [from] is passed, directories are made relative to that.
+///
+/// Examples:
+///   parentDirs('/a/b/c') => ('/a/b/c', '/a/b', '/a', '/')
+///   parentDirs('./d/e', from: '/a/b/c') => ('./d/e', './d', '.', '..', '../..', '../../..')
+Iterable<String> parentDirs(String path, {String? from}) sync* {
+  var relative = false;
+  var d = path;
+  while (true) {
+    if (relative) {
+      yield p.relative(d, from: from);
+    } else {
+      yield d;
+    }
+    if (!p.isWithin(from ?? p.current, d)) {
+      d = p.normalize(p.join(from ?? p.current, d));
+      relative = true;
+    }
+    final parent = p.dirname(d);
+    if (parent == d) break;
+    d = parent;
+  }
+}
diff --git a/lib/src/package.dart b/lib/src/package.dart
index fa99394..5685679 100644
--- a/lib/src/package.dart
+++ b/lib/src/package.dart
@@ -125,28 +125,62 @@
 
   /// Loads the package whose root directory is [packageDir].
   ///
+  /// Will also load the workspace sub-packages of this package (recursively).
+  ///
   /// [name] is the expected name of that package (e.g. the name given in the
   /// dependency), or `null` if the package being loaded is the entrypoint
   /// package.
   ///
   /// `pubspec_overrides.yaml` is only loaded if [withPubspecOverrides] is
   /// `true`.
+  ///
+  /// [loadPubspec] if given will be used to obtain a pubspec from a path. Also
+  /// for the workspace children.
+  ///
+  /// This mechanism can be used to avoid loading pubspecs twice. It can also be
+  /// used to override a pubspec in memory for trying out an alternative
+  /// resolution.
   factory Package.load(
-    String? name,
     String dir,
     SourceRegistry sources, {
     bool withPubspecOverrides = false,
+    String? expectedName,
+    Pubspec Function(
+      String path, {
+      String? expectedName,
+      required bool withPubspecOverrides,
+    })? loadPubspec,
   }) {
-    final pubspec = Pubspec.load(
+    loadPubspec ??=
+        (path, {expectedName, required withPubspecOverrides}) => Pubspec.load(
+              path,
+              sources,
+              containingDescription: RootDescription(path),
+            );
+    final pubspec = loadPubspec(
       dir,
-      sources,
-      expectedName: name,
-      allowOverridesFile: withPubspecOverrides,
-      containingDescription: RootDescription(dir),
+      withPubspecOverrides: withPubspecOverrides,
+      expectedName: expectedName,
     );
     final workspacePackages = pubspec.workspace
-        .map((e) => Package.load(null, p.join(dir, e), sources))
+        .map(
+          (e) => Package.load(
+            p.join(dir, e),
+            sources,
+            loadPubspec: loadPubspec,
+            withPubspecOverrides: withPubspecOverrides,
+          ),
+        )
         .toList();
+    for (final package in workspacePackages) {
+      if (package.pubspec.resolution != Resolution.workspace) {
+        fail('''
+${package.pubspecPath} is inluded in the workspace from ${p.join(dir, 'pubspec.yaml')}, but does not have `resolution: workspace`.
+
+See $workspacesDocUrl for more information.
+''');
+      }
+    }
     return Package(pubspec, dir, workspacePackages);
   }
 
diff --git a/lib/src/solver/report.dart b/lib/src/solver/report.dart
index da82329..6154d32 100644
--- a/lib/src/solver/report.dart
+++ b/lib/src/solver/report.dart
@@ -153,7 +153,7 @@
     final dir = _location;
     if (dir != null) {
       if (dir != '.') {
-        suffix = ' in $dir';
+        suffix = ' in `$dir`';
       }
     }
 
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart
index 99bf59b..7f863aa 100644
--- a/lib/src/source/git.dart
+++ b/lib/src/source/git.dart
@@ -443,7 +443,7 @@
 
             var packageDir = p.join(revisionCachePath, relative);
             try {
-              return Package.load(null, packageDir, cache.sources);
+              return Package.load(packageDir, cache.sources);
             } catch (error, stackTrace) {
               log.error('Failed to load package', error, stackTrace);
               var name = p.basename(revisionCachePath).split('-').first;
diff --git a/lib/src/source/hosted.dart b/lib/src/source/hosted.dart
index 7a2c9de..b51baa9 100644
--- a/lib/src/source/hosted.dart
+++ b/lib/src/source/hosted.dart
@@ -1277,7 +1277,7 @@
         var packages = <Package>[];
         for (var entry in listDir(serverDir)) {
           try {
-            packages.add(Package.load(null, entry, cache.sources));
+            packages.add(Package.load(entry, cache.sources));
           } catch (error, stackTrace) {
             log.error('Failed to load package', error, stackTrace);
             final id = _idForBasename(
@@ -1384,7 +1384,7 @@
         .where(_looksLikePackageDir)
         .map((entry) {
           try {
-            return Package.load(null, entry, cache.sources);
+            return Package.load(entry, cache.sources);
           } catch (error, stackTrace) {
             log.fine('Failed to load package from $entry:\n'
                 '$error\n'
diff --git a/lib/src/system_cache.dart b/lib/src/system_cache.dart
index 222c375..e20a60b 100644
--- a/lib/src/system_cache.dart
+++ b/lib/src/system_cache.dart
@@ -111,16 +111,16 @@
   ///
   /// Throws an [ArgumentError] if [id] has an invalid source.
   Package load(PackageId id) {
-    return Package.load(id.name, getDirectory(id), sources);
+    return Package.load(getDirectory(id), sources, expectedName: id.name);
   }
 
   Package loadCached(PackageId id) {
     final source = id.description.description.source;
     if (source is CachedSource) {
       return Package.load(
-        id.name,
         source.getDirectoryInCache(id, this),
         sources,
+        expectedName: id.name,
       );
     } else {
       throw ArgumentError('Call only on Cached ids.');
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index cb971ff..3093fce 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -104,6 +104,8 @@
   'yield',
 };
 
+const workspacesDocUrl = 'https://dart.dev/go/pub-workspaces';
+
 /// An cryptographically secure instance of [math.Random].
 final random = math.Random.secure();
 
diff --git a/test/add/git/git_test.dart b/test/add/git/git_test.dart
index 833dd0f..19938e3 100644
--- a/test/add/git/git_test.dart
+++ b/test/add/git/git_test.dart
@@ -47,7 +47,7 @@
     await pubAdd(
       args: ['--directory', appPath, 'foo', '--git-url', 'foo.git'],
       workingDirectory: d.sandbox,
-      output: contains('Changed 1 dependency in myapp!'),
+      output: contains('Changed 1 dependency in `myapp`!'),
     );
 
     await d.dir(cachePath, [
@@ -228,7 +228,7 @@
         'foo:{"git": {"url":"foo.git", "path":"subdir"}}',
       ],
       workingDirectory: d.sandbox,
-      output: contains('Changed 1 dependency in myapp!'),
+      output: contains('Changed 1 dependency in `myapp`!'),
     );
 
     await d.appDir(
diff --git a/test/add/path/relative_path_test.dart b/test/add/path/relative_path_test.dart
index 5a3dcaa..32ae0d6 100644
--- a/test/add/path/relative_path_test.dart
+++ b/test/add/path/relative_path_test.dart
@@ -59,7 +59,7 @@
     await pubAdd(
       args: ['--directory', appPath, 'foo', '--path', 'foo'],
       workingDirectory: d.sandbox,
-      output: contains('Changed 1 dependency in myapp!'),
+      output: contains('Changed 1 dependency in `myapp`!'),
     );
 
     await d.appPackageConfigFile([
@@ -180,7 +180,7 @@
         'bar:{"path":"bar"}',
       ],
       workingDirectory: d.sandbox,
-      output: contains('Changed 2 dependencies in myapp!'),
+      output: contains('Changed 2 dependencies in `myapp`!'),
     );
 
     await d.appPackageConfigFile([
diff --git a/test/ascii_tree_test.dart b/test/ascii_tree_test.dart
index d0a921b..b406f72 100644
--- a/test/ascii_tree_test.dart
+++ b/test/ascii_tree_test.dart
@@ -61,11 +61,9 @@
         file('path.dart', bytes(100)),
       ]),
     ]).create();
-    var files = Package.load(
-      null,
-      path(appPath),
-      (name) => throw UnimplementedError(),
-    ).listFiles();
+    var files =
+        Package.load(path(appPath), (name) => throw UnimplementedError())
+            .listFiles();
     ctx.expectNextSection(
       tree.fromFiles(files, baseDir: path(appPath), showFileSizes: true),
     );
diff --git a/test/descriptor.dart b/test/descriptor.dart
index b0e68c2..8a8f783 100644
--- a/test/descriptor.dart
+++ b/test/descriptor.dart
@@ -111,14 +111,25 @@
   String version, {
   Map<String, Object?>? deps,
   Map<String, Object?>? devDeps,
+  String? resolution,
   String? sdk,
   Map<String, Object?>? extras,
+  bool resolutionWorkspace = false,
 }) {
   var map = packageMap(name, version, deps, devDeps);
+  if (resolutionWorkspace && sdk == null) {
+    sdk = '3.7.0';
+  }
   if (sdk != null) {
     map['environment'] = {'sdk': sdk};
   }
-  return pubspec({...map, ...extras ?? {}});
+  return pubspec(
+    {
+      ...map,
+      if (resolutionWorkspace) 'resolution': 'workspace',
+      ...extras ?? {},
+    },
+  );
 }
 
 /// Describes a file named `pubspec_overrides.yaml` by default, with the given
diff --git a/test/get/enforce_lockfile_test.dart b/test/get/enforce_lockfile_test.dart
index 9cafa8e..75c3ee1 100644
--- a/test/get/enforce_lockfile_test.dart
+++ b/test/get/enforce_lockfile_test.dart
@@ -84,14 +84,14 @@
       args: ['--enforce-lockfile', '--example'],
       output: allOf(
         contains('Got dependencies!'),
-        contains('Resolving dependencies in $example...'),
+        contains('Resolving dependencies in `$example`...'),
       ),
       error: allOf(
         contains(
-          'Unable to satisfy `$examplePubspec` using `$examplePubspecLock` in $example.',
+          'Unable to satisfy `$examplePubspec` using `$examplePubspecLock` in `$example`.',
         ),
         contains(
-            'To update `$examplePubspecLock` run `dart pub get` in $example without\n'
+            'To update `$examplePubspecLock` run `dart pub get` in `$example` without\n'
             '`--enforce-lockfile`.'),
       ),
       exitCode: DATA,
diff --git a/test/get/gets_in_example_folder_test.dart b/test/get/gets_in_example_folder_test.dart
index 11288d0..8e990da 100644
--- a/test/get/gets_in_example_folder_test.dart
+++ b/test/get/gets_in_example_folder_test.dart
@@ -47,16 +47,16 @@
 Resolving dependencies...
 Downloading packages...
 Got dependencies!
-Resolving dependencies in $dotExample...
+Resolving dependencies in `$dotExample`...
 Downloading packages...
-Got dependencies in $dotExample.'''
+Got dependencies in `$dotExample`.'''
             : '''
 Resolving dependencies... 
 Downloading packages...
 No dependencies changed.
-Resolving dependencies in $dotExample...
+Resolving dependencies in `$dotExample`...
 Downloading packages...
-Got dependencies in $dotExample.''',
+Got dependencies in `$dotExample`.''',
       );
       expect(lockFile.existsSync(), true);
       expect(exampleLockFile.existsSync(), true);
diff --git a/test/get/path/relative_path_test.dart b/test/get/path/relative_path_test.dart
index 67e9749..4b379f9 100644
--- a/test/get/path/relative_path_test.dart
+++ b/test/get/path/relative_path_test.dart
@@ -92,7 +92,7 @@
     await pubGet(
       args: ['--directory', appPath],
       workingDirectory: d.sandbox,
-      output: contains('Changed 2 dependencies in myapp!'),
+      output: contains('Changed 2 dependencies in `myapp`!'),
     );
 
     await d.appPackageConfigFile([
diff --git a/test/global/activate/installs_dependencies_for_path_test.dart b/test/global/activate/installs_dependencies_for_path_test.dart
index ff85808..7c9f11e 100644
--- a/test/global/activate/installs_dependencies_for_path_test.dart
+++ b/test/global/activate/installs_dependencies_for_path_test.dart
@@ -19,7 +19,7 @@
     ]).create();
 
     var pub = await startPub(args: ['global', 'activate', '-spath', '../foo']);
-    expect(pub.stdout, emitsThrough('Resolving dependencies in ../foo...'));
+    expect(pub.stdout, emitsThrough('Resolving dependencies in `../foo`...'));
     expect(pub.stdout, emitsThrough(startsWith('Activated foo 0.0.0 at path')));
     await pub.shouldExit();
 
diff --git a/test/global/run/missing_path_package_test.dart b/test/global/run/missing_path_package_test.dart
index dc98583..dce42da 100644
--- a/test/global/run/missing_path_package_test.dart
+++ b/test/global/run/missing_path_package_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:path/path.dart' as p;
-import 'package:pub/src/exit_codes.dart' as exit_codes;
 import 'package:pub/src/io.dart';
 import 'package:test/test.dart';
 
@@ -22,11 +21,10 @@
     deleteEntry(p.join(d.sandbox, 'foo'));
 
     var pub = await pubRun(global: true, args: ['foo']);
-    var path = canonicalize(p.join(d.sandbox, 'foo'));
     expect(
       pub.stderr,
-      emits('Could not find a file named "pubspec.yaml" in "$path".'),
+      emits('The directory `${d.path('foo')}` does not exist.'),
     );
-    await pub.shouldExit(exit_codes.NO_INPUT);
+    await pub.shouldExit(1);
   });
 }
diff --git a/test/pub_get_and_upgrade_test.dart b/test/pub_get_and_upgrade_test.dart
index 5000cac..61dfa45 100644
--- a/test/pub_get_and_upgrade_test.dart
+++ b/test/pub_get_and_upgrade_test.dart
@@ -17,8 +17,9 @@
 
         await pubCommand(
           command,
-          error: RegExp(r'Could not find a file named "pubspec.yaml" '
-              r'in "[^\n]*"\.'),
+          error: contains(
+            'Found no `pubspec.yaml` file in `${d.path(appPath)}` or parent directories',
+          ),
           exitCode: exit_codes.NO_INPUT,
         );
       });
diff --git a/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
index c448092..6a8719e 100644
--- a/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
+++ b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
@@ -2,74 +2,74 @@
 
 ## Section 0
 $ pub add --directory=myapp foo
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
 + foo 1.0.0
-Changed 1 dependency in myapp!
-Resolving dependencies in myapp/example...
+Changed 1 dependency in `myapp`!
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 1
 $ pub -C myapp add bar
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
 + bar 1.2.3
-Changed 1 dependency in myapp!
-Resolving dependencies in myapp/example...
+Changed 1 dependency in `myapp`!
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 2
 $ pub -C 'myapp/example' get --directory=myapp bar
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-Got dependencies in myapp!
-Resolving dependencies in myapp/example...
+Got dependencies in `myapp`!
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 3
 $ pub remove bar -C myapp
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
 These packages are no longer being depended on:
 - bar 1.2.3
-Changed 1 dependency in myapp!
-Resolving dependencies in myapp/example...
+Changed 1 dependency in `myapp`!
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 4
 $ pub get bar -C myapp
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-Got dependencies in myapp!
-Resolving dependencies in myapp/example...
+Got dependencies in `myapp`!
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 5
 $ pub get bar -C 'myapp/example'
-Resolving dependencies in myapp/example...
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example!
+Got dependencies in `myapp/example`!
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 6
 $ pub get bar -C 'myapp/example2'
-Resolving dependencies in myapp/example2...
+Resolving dependencies in `myapp/example2`...
 [STDERR] Error on line 1, column 9 of myapp/pubspec.yaml: "name" field doesn't match expected name "myapp".
 [STDERR]   ╷
 [STDERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"https://pub.dev","description":"A package, I guess.","environment":{"sdk":">=3.1.2 <=3.2.0"}, dependencies: { foo: ^1.0.0}}
@@ -81,38 +81,38 @@
 
 ## Section 7
 $ pub get bar -C 'myapp/broken_dir'
-[STDERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp/broken_dir".
-[EXIT CODE] 66
+[STDERR] The directory `myapp/broken_dir` does not exist.
+[EXIT CODE] 1
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 8
 $ pub downgrade -C myapp
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-No dependencies changed in myapp.
-Resolving dependencies in myapp/example...
+No dependencies changed in `myapp`.
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 9
 $ pub upgrade bar -C myapp
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-No dependencies changed in myapp.
-Resolving dependencies in myapp/example...
+No dependencies changed in `myapp`.
+Resolving dependencies in `myapp/example`...
 Downloading packages...
-Got dependencies in myapp/example.
+Got dependencies in `myapp/example`.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 10
 $ pub run -C myapp 'bin/app.dart'
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-Got dependencies in myapp.
+Got dependencies in `myapp`.
 Building package executable...
 Built test_pkg:app.
 Hi
@@ -121,9 +121,9 @@
 
 ## Section 11
 $ pub publish -C myapp --dry-run
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-Got dependencies in myapp!
+Got dependencies in `myapp`!
 Publishing test_pkg 1.0.0 to http://localhost:$PORT:
 ├── CHANGELOG.md (<1 KB)
 ├── LICENSE (<1 KB)
@@ -158,9 +158,9 @@
 
 ## Section 13
 $ pub deps -C myapp
-Resolving dependencies in myapp...
+Resolving dependencies in `myapp`...
 Downloading packages...
-Got dependencies in myapp.
+Got dependencies in `myapp`.
 Dart SDK 3.1.2+3
 test_pkg 1.0.0
 └── foo 1.0.0
diff --git a/test/testdata/goldens/outdated/outdated_test/no pubspec.txt b/test/testdata/goldens/outdated/outdated_test/no pubspec.txt
index ba8858a..c8def95 100644
--- a/test/testdata/goldens/outdated/outdated_test/no pubspec.txt
+++ b/test/testdata/goldens/outdated/outdated_test/no pubspec.txt
@@ -2,6 +2,6 @@
 
 ## Section 0
 $ pub outdated
-[STDERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp".
+[STDERR] Found no `pubspec.yaml` file in `$SANDBOX/myapp` or parent directories
 [EXIT CODE] 66
 
diff --git a/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
index d53310e..b5ea61a 100644
--- a/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
+++ b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
@@ -9,19 +9,19 @@
 
 Changed 1 constraint in pubspec.yaml:
   bar: ^1.0.0 -> ^2.0.0
-Resolving dependencies in ./example...
+Resolving dependencies in `./example`...
 Downloading packages...
-Got dependencies in ./example.
+Got dependencies in `./example`.
 [STDERR] Running `upgrade --major-versions` only in `.`. Run `dart pub upgrade --major-versions --directory example/` separately.
 
 -------------------------------- END OF OUTPUT ---------------------------------
 
 ## Section 1
 $ pub upgrade --major-versions --directory example
-Resolving dependencies in example...
+Resolving dependencies in `example`...
 Downloading packages...
 > foo 2.0.0 (was 1.0.0)
-Changed 1 dependency in example!
+Changed 1 dependency in `example`!
 
 Changed 1 constraint in pubspec.yaml:
   foo: ^1.0.0 -> ^2.0.0
diff --git a/test/unpack_test.dart b/test/unpack_test.dart
index cdf1f6e..ebf83ce 100644
--- a/test/unpack_test.dart
+++ b/test/unpack_test.dart
@@ -72,7 +72,7 @@
       output: allOf(
         contains('''
 Downloading foo 1.2.3 to `.${s}foo-1.2.3`...
-Resolving dependencies in .${s}foo-1.2.3...
+Resolving dependencies in `.${s}foo-1.2.3`...
 '''),
         contains('To explore type: cd .${s}foo-1.2.3'),
         contains(
@@ -97,7 +97,7 @@
       output: allOf(
         contains('''
 Downloading foo 1.2.3-pre to `../foo-1.2.3-pre`...
-Resolving dependencies in ../foo-1.2.3-pre...
+Resolving dependencies in `../foo-1.2.3-pre`...
 '''),
         contains('To explore type: cd ../foo-1.2.3-pre'),
       ),
diff --git a/test/workspace_test.dart b/test/workspace_test.dart
index 60204fa..d603f5d 100644
--- a/test/workspace_test.dart
+++ b/test/workspace_test.dart
@@ -26,7 +26,12 @@
       ),
       dir('pkgs', [
         dir('a', [
-          libPubspec('a', '1.1.1', devDeps: {'dev_dep': '^1.0.0'}),
+          libPubspec(
+            'a',
+            '1.1.1',
+            devDeps: {'dev_dep': '^1.0.0'},
+            resolutionWorkspace: true,
+          ),
         ]),
       ]),
     ]).create();
@@ -62,7 +67,12 @@
       ),
       dir('pkgs', [
         dir('a', [
-          libPubspec('a', '1.1.1', deps: {'b': '^2.0.0'}),
+          libPubspec(
+            'a',
+            '1.1.1',
+            deps: {'b': '^2.0.0'},
+            resolutionWorkspace: true,
+          ),
         ]),
         dir('b', [
           libPubspec(
@@ -71,6 +81,7 @@
             deps: {
               'myapp': {'git': 'somewhere'},
             },
+            resolutionWorkspace: true,
           ),
         ]),
       ]),
@@ -109,7 +120,7 @@
             extras: {
               'workspace': ['example'],
             },
-            sdk: '^3.7.0',
+            resolutionWorkspace: true,
           ),
           dir('example', [
             libPubspec(
@@ -118,6 +129,7 @@
               deps: {
                 'a': {'path': '..'},
               },
+              resolutionWorkspace: true,
             ),
           ]),
         ]),
@@ -151,7 +163,12 @@
       ),
       dir('pkgs', [
         dir('a', [
-          libPubspec('a', '1.1.1', deps: {'myapp': '^0.2.3'}),
+          libPubspec(
+            'a',
+            '1.1.1',
+            deps: {'myapp': '^0.2.3'},
+            resolutionWorkspace: true,
+          ),
         ]),
       ]),
     ]).create();
@@ -181,10 +198,65 @@
             deps: {
               'myapp': {'posted': 'https://abc'},
             },
+            resolutionWorkspace: true,
           ),
         ]),
       ]),
     ]).create();
     await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'});
   });
+
+  test('Can resolve from any directory inside the workspace', () async {
+    await dir(appPath, [
+      libPubspec(
+        'myapp',
+        '1.2.3',
+        extras: {
+          'workspace': ['pkgs/a'],
+        },
+        sdk: '^3.7.0',
+      ),
+      dir('pkgs', [
+        dir('a', [
+          libPubspec(
+            'a',
+            '1.1.1',
+            deps: {
+              'myapp': {'posted': 'https://abc'},
+            },
+            resolutionWorkspace: true,
+          ),
+        ]),
+      ]),
+    ]).create();
+    await pubGet(
+      environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'},
+      workingDirectory: p.join(sandbox, appPath, 'pkgs'),
+      output: contains('Resolving dependencies in `..`...'),
+    );
+    final s = p.separator;
+    await pubGet(
+      environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'},
+      workingDirectory: p.join(sandbox, appPath, 'pkgs', 'a'),
+      output: contains('Resolving dependencies in `..$s..`...'),
+    );
+
+    await pubGet(
+      args: ['-C$appPath/pkgs'],
+      environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'},
+      workingDirectory: sandbox,
+      output: contains('Resolving dependencies in `$appPath`...'),
+    );
+
+    await pubGet(
+      args: ['-C..'],
+      environment: {'_PUB_TEST_SDK_VERSION': '3.7.0'},
+      workingDirectory: p.join(
+        sandbox,
+        appPath,
+        'pkgs',
+      ),
+      output: contains('Resolving dependencies in `..`...'),
+    );
+  });
 }