@@ -41,13 +41,27 @@ export function cliInstallCommand(): string | undefined {
4141 }
4242}
4343
44+ /**
45+ * Options for {@link runCLIUpgrade}.
46+ */
47+ export interface RunCLIUpgradeOptions {
48+ /**
49+ * `true` when the upgrade is being triggered by the automatic postrun hook.
50+ * In that case we skip project-local upgrades — those should only happen when the
51+ * user explicitly runs `shopify upgrade` so we don't surprise them by mutating
52+ * their `package.json` / lockfile in the background.
53+ */
54+ autoupgrade ?: boolean
55+ }
56+
4457/**
4558 * Runs the CLI upgrade using the appropriate package manager.
4659 * Determines the install command and executes it.
4760 *
61+ * @param options - See {@link RunCLIUpgradeOptions}.
4862 * @throws AbortError if the package manager or command cannot be determined.
4963 */
50- export async function runCLIUpgrade ( ) : Promise < void > {
64+ export async function runCLIUpgrade ( options : RunCLIUpgradeOptions = { } ) : Promise < void > {
5165 // Path where the current project is (app/hydrogen)
5266 const path = sniffForPath ( ) ?? cwd ( )
5367 const projectDir = getProjectDir ( path )
@@ -61,6 +75,14 @@ export async function runCLIUpgrade(): Promise<void> {
6175 return
6276 }
6377
78+ // When triggered by the automatic postrun hook, skip project-local upgrades.
79+ // Bumping `package.json` / lockfile silently in the background would surprise users
80+ // and produce noisy diffs; explicit `shopify upgrade` invocations still upgrade the
81+ // local project.
82+ if ( options . autoupgrade && ! isGlobal ) {
83+ return
84+ }
85+
6486 // Generate the install command for the global CLI and execute it
6587 if ( isGlobal ) {
6688 const installCommand = cliInstallCommand ( )
0 commit comments