Repository: withastro/astro
File: packages/astro/src/cli/add/index.ts (TypeScript)

Code before:
					throw new Error(
						`${bold(
							packageName,
						)} doesn't appear to be an integration or an adapter. Find our official integrations at ${cyan(
							'https://astro.build/integrations',
						)}`,
					);
				}

				if (integration === 'tailwind') {
					integrationName = 'tailwind';
					dependencies = [
						['@tailwindcss/vite', '^4.0.0'],
						['tailwindcss', '^4.0.0'],
					];
				}
				return {
					id: integration,
					packageName,
					dependencies,
					type: integrationType,
					integrationName,
				};
			}),
		);
		spinner.stop();
		return integrationEntries;
	} catch (e) {
		if (e instanceof Error) {
			spinner.stop(e.message, 2);
			process.exit(1);
		} else {
			throw e;
		}
	}
}

async function updateTSConfig(
	cwd = process.cwd(),
	logger: Logger,
	integrationsInfo: IntegrationInfo[],
	flags: Flags,
): Promise<UpdateResult> {
	const integrations = integrationsInfo.map(
		(integration) => integration.id as frameworkWithTSSettings,
	);
	const firstIntegrationWithTSSettings = integrations.find((integration) =>
		presets.has(integration),
	);

	if (!firstIntegrationWithTSSettings) {

Review comment (suggestion):
Quick comparison of the two states here:

| Current CLI | This PR |
|--------|--------|
| <img width="179" height="23" alt="Checkmark icon Resolving packages..." src="https://github.com/user-attachments/assets/fb79bc61-06f7-46ea-9d1e-d5d8cbe21426" /> | <img width="253" height="29" alt="diamond icon with no text" src="https://github.com/user-attachments/assets/6be7e406-6ab5-4adc-a7fb-b7d3815562c1" /> | 

The “Resolving packages” message is preserved currently as a reference to the completed task, whereas it looks like Clack’s `stop()` clears that out. I think it would be nice to preserve a message to refer back to.

Maybe as simple as?
```suggestion
		spinner.stop('Resolved packages');
```

Code after:
		}
	}
	return Promise.all(
		Object.entries(ranges).map(([name, range]) => resolveRangeToInstallSpecifier(name, range)),
	);
}

/**
 * Resolves package with a given range to a STABLE version
 * peerDependencies might specify a compatible prerelease,
 * but `astro add` should only ever install stable releases
 */
async function resolveRangeToInstallSpecifier(name: string, range: string): Promise<string> {
	const versions = await fetchPackageVersions(name);
	if (versions instanceof Error) return name;
	// Filter out any prerelease versions, but fallback if there are no stable versions
	const stableVersions = versions.filter((v) => !v.includes('-'));
	const maxStable = maxSatisfying(stableVersions, range) ?? maxSatisfying(versions, range);
	if (!maxStable) return name;
	return `${name}@^${maxStable}`;
}

// Allow forwarding of standard `npm install` flags
// See https://docs.npmjs.com/cli/v8/commands/npm-install#description
const INHERITED_FLAGS = new Set<string>([
	'P',
	'save-prod',
	'D',
	'save-dev',
	'E',
	'save-exact',
	'no-save',
]);

async function tryToInstallIntegrations({
	integrations,
	cwd,
	flags,
	logger,
}: {
	integrations: IntegrationInfo[];
	cwd?: string;
	flags: Flags;
	logger: Logger;
}): Promise<UpdateResult> {
	const packageManager = await detect({
		cwd,
		// Include the `install-metadata` strategy to have the package manager that's
		// used for installation take precedence
		strategies: ['install-metadata', 'lockfile', 'packageManager-field'],
	});