diff --git a/packages/cli-kit/src/public/node/custom-oclif-loader.ts b/packages/cli-kit/src/public/node/custom-oclif-loader.ts index 4e3284b8d3..b722d5932f 100644 --- a/packages/cli-kit/src/public/node/custom-oclif-loader.ts +++ b/packages/cli-kit/src/public/node/custom-oclif-loader.ts @@ -81,9 +81,16 @@ export class ShopifyConfig extends Config { commandClass.id = id // eslint-disable-next-line @typescript-eslint/no-explicit-any commandClass.plugin = cmd.plugin ?? (this as any).rootPlugin - await this.runHook('prerun', {argv, Command: commandClass}) + // Execute the command first — give it exclusive CPU time. const result = (await commandClass.run(argv, this)) as T - await this.runHook('postrun', {argv, Command: commandClass, result}) + // Fire prerun + postrun AFTER command completes. Both are fire-and-forget. + // Analytics is best-effort; process.exit(0) in bootstrap may terminate + // before these complete, which is fine. + // eslint-disable-next-line no-void + void this.runHook('prerun', {argv, Command: commandClass}).then(() => { + // eslint-disable-next-line no-void + void this.runHook('postrun', {argv, Command: commandClass, result}) + }) return result } } diff --git a/packages/cli/src/bootstrap.ts b/packages/cli/src/bootstrap.ts index 7e99f28509..6a70833c1c 100644 --- a/packages/cli/src/bootstrap.ts +++ b/packages/cli/src/bootstrap.ts @@ -64,6 +64,9 @@ async function runShopifyCLI({development}: RunShopifyCLIOptions) { development, lazyCommandLoader: loadCommand, }) + // Force exit after command completes. Pending network requests (analytics, + // version checks) are best-effort and shouldn't delay the user. + process.exit(0) } export default runShopifyCLI