@better-update/cli 0.15.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from "node:module";
3
3
  import { spawn, spawnSync } from "node:child_process";
4
4
  import { defineCommand, runMain } from "citty";
5
- import { Console, Context, Data, Deferred, Duration, Effect, Fiber, Layer, Match, Option, ParseResult, Schema, Stream } from "effect";
5
+ import { Console, Context, Data, Deferred, Duration, Effect, Layer, Match, Option, ParseResult, Schema } from "effect";
6
6
  import { Command, FetchHttpClient, FileSystem, HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, HttpApiSecurity, HttpClient, HttpClientRequest, OpenApi, Path } from "@effect/platform";
7
7
  import { NodeContext } from "@effect/platform-node";
8
8
  import path, { join } from "node:path";
@@ -15,6 +15,8 @@ import { maxBy, uniqBy } from "es-toolkit";
15
15
  import { createHash, randomBytes, randomUUID } from "node:crypto";
16
16
  import forge from "node-forge";
17
17
  import { createReadStream, existsSync, readFileSync, writeFileSync } from "node:fs";
18
+ import { spawn as spawn$1 } from "node-pty";
19
+ import chalk from "chalk";
18
20
  import os from "node:os";
19
21
  import plistMod from "@expo/plist";
20
22
  import { ExpoRunFormatter } from "@expo/xcpretty";
@@ -28,7 +30,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
28
30
 
29
31
  //#endregion
30
32
  //#region package.json
31
- var version = "0.15.3";
33
+ var version = "0.16.0";
32
34
 
33
35
  //#endregion
34
36
  //#region src/lib/interactive-mode.ts
@@ -4388,56 +4390,178 @@ const sha256Namespaced = (contentType, contentSha256Hex) => {
4388
4390
  return toBase64Url(createHash("sha256").update(input).digest());
4389
4391
  };
4390
4392
 
4393
+ //#endregion
4394
+ //#region src/lib/pty-runner.ts
4395
+ const ptyDimensions = () => {
4396
+ const stdout = process$1.stdout;
4397
+ return {
4398
+ cols: typeof stdout.columns === "number" && stdout.columns > 0 ? stdout.columns : 120,
4399
+ rows: typeof stdout.rows === "number" && stdout.rows > 0 ? stdout.rows : 40
4400
+ };
4401
+ };
4402
+ const mergeEnv$1 = (overrides) => {
4403
+ const merged = {};
4404
+ for (const [key, value] of Object.entries(process$1.env)) if (typeof value === "string") merged[key] = value;
4405
+ for (const [key, value] of Object.entries(overrides)) merged[key] = value;
4406
+ return merged;
4407
+ };
4408
+ const trySpawn = (input) => {
4409
+ const { cols, rows } = ptyDimensions();
4410
+ try {
4411
+ return spawn$1(input.command, [...input.args], {
4412
+ name: "xterm-256color",
4413
+ cols,
4414
+ rows,
4415
+ cwd: input.cwd,
4416
+ env: mergeEnv$1(input.env)
4417
+ });
4418
+ } catch (error) {
4419
+ return error instanceof Error ? error : new Error(String(error));
4420
+ }
4421
+ };
4422
+ /**
4423
+ * Run a command in a pseudo-terminal so the subprocess sees a real TTY
4424
+ * (preserves spinners, progress bars, and ANSI colors emitted by tools like
4425
+ * CocoaPods and `expo prebuild`). Subprocess output is tee'd: forwarded to
4426
+ * `process.stdout` as raw bytes (so colors/positioning are preserved), and
4427
+ * also buffered into lines for the optional `onLine` callback.
4428
+ *
4429
+ * Returns the subprocess exit code. Spawn failures and signal exits surface
4430
+ * as non-zero exit codes (128+signal for Unix-style signal exits).
4431
+ */
4432
+ const runInPty = (input) => Effect.async((resume) => {
4433
+ const spawned = trySpawn(input);
4434
+ if (spawned instanceof Error) {
4435
+ process$1.stderr.write(`Failed to spawn "${input.command}" in pty: ${spawned.message}\n`);
4436
+ resume(Effect.succeed(1));
4437
+ return;
4438
+ }
4439
+ const proc = spawned;
4440
+ let lineBuf = "";
4441
+ const handleLine = (line) => {
4442
+ if (input.onLine === void 0) return;
4443
+ const annotation = input.onLine(line);
4444
+ if (annotation !== void 0) process$1.stdout.write(`${annotation}\n`);
4445
+ };
4446
+ proc.onData((chunk) => {
4447
+ if (input.silent !== true) process$1.stdout.write(chunk);
4448
+ if (input.onLine === void 0) return;
4449
+ lineBuf += chunk;
4450
+ let nl = lineBuf.indexOf("\n");
4451
+ while (nl !== -1) {
4452
+ const line = lineBuf.slice(0, nl).replace(/\r$/u, "");
4453
+ lineBuf = lineBuf.slice(nl + 1);
4454
+ handleLine(line);
4455
+ nl = lineBuf.indexOf("\n");
4456
+ }
4457
+ });
4458
+ const handleResize = () => {
4459
+ const { cols, rows } = ptyDimensions();
4460
+ try {
4461
+ proc.resize(cols, rows);
4462
+ } catch {}
4463
+ };
4464
+ process$1.stdout.on("resize", handleResize);
4465
+ proc.onExit(({ exitCode, signal }) => {
4466
+ process$1.stdout.off("resize", handleResize);
4467
+ if (lineBuf.length > 0) {
4468
+ handleLine(lineBuf.replace(/\r$/u, ""));
4469
+ lineBuf = "";
4470
+ }
4471
+ const code = signal !== void 0 && signal !== 0 ? 128 + signal : exitCode;
4472
+ resume(Effect.succeed(code));
4473
+ });
4474
+ return Effect.sync(() => {
4475
+ try {
4476
+ proc.kill();
4477
+ } catch {}
4478
+ process$1.stdout.off("resize", handleResize);
4479
+ });
4480
+ });
4481
+
4482
+ //#endregion
4483
+ //#region src/lib/warning-style.ts
4484
+ const ANSI_REGEX_GLOBAL = /[›][[()#;?]*(?:\d{1,4}(?:;\d{0,4})*)?[\dA-ORZcf-ntqry=><]/gu;
4485
+ const stripAnsi = (input) => input.replaceAll(ANSI_REGEX_GLOBAL, "");
4486
+ const hasAnsi = (input) => {
4487
+ ANSI_REGEX_GLOBAL.lastIndex = 0;
4488
+ return ANSI_REGEX_GLOBAL.test(input);
4489
+ };
4490
+ const WARNING_PATTERNS = [
4491
+ /^\s*warning:/iu,
4492
+ /^\s*\[!\]/u,
4493
+ /^\s*WARNING:/u,
4494
+ /^\s*WARN\b/u,
4495
+ /\bis deprecated\b/iu,
4496
+ /^\s*DEPRECATION\b/iu,
4497
+ /\[MT\]/u,
4498
+ /⚠/u
4499
+ ];
4500
+ const isWarningLine = (rawLine) => {
4501
+ const plain = stripAnsi(rawLine);
4502
+ return WARNING_PATTERNS.some((pattern) => pattern.test(plain));
4503
+ };
4504
+ /**
4505
+ * Style a single output line as a warning. If the line already contains ANSI
4506
+ * escapes (the subprocess pre-colored it), only prepend our yellow ⚠ marker
4507
+ * so the original colors survive. Otherwise color the whole line yellow.
4508
+ */
4509
+ const styleWarningLine = (line) => hasAnsi(line) ? `${chalk.yellow("⚠")} ${line}` : chalk.yellow(`⚠ ${line}`);
4510
+ /**
4511
+ * Emit a CLI-owned warning. Suppressed in JSON mode; in human mode writes a
4512
+ * yellow, ⚠-prefixed line to stderr so it stands out from regular info logs.
4513
+ */
4514
+ const printWarn = (message) => Effect.gen(function* () {
4515
+ if ((yield* OutputMode).json) return;
4516
+ yield* Console.warn(chalk.yellow(`⚠ warning: ${message}`));
4517
+ });
4518
+
4391
4519
  //#endregion
4392
4520
  //#region src/commands/build/run-step.ts
4393
- const runStep = (cmd, step) => Command.exitCode(cmd.pipe(Command.stdout("inherit"), Command.stderr("inherit"))).pipe(Effect.mapError((cause) => new BuildFailedError({
4521
+ const buildFailed = (step, exitCode, message) => new BuildFailedError({
4394
4522
  step,
4395
- exitCode: 1,
4396
- message: `${step} failed to spawn: ${String(cause)}`
4397
- })), Effect.flatMap((code) => code === 0 ? Effect.void : Effect.fail(new BuildFailedError({
4398
- step,
4399
- exitCode: code,
4400
- message: `${step} exited with code ${code}`
4401
- }))));
4523
+ exitCode,
4524
+ message
4525
+ });
4526
+ const annotateWarning = (line) => isWarningLine(line) ? styleWarningLine(line) : void 0;
4527
+ /**
4528
+ * Run a build step in a PTY so the subprocess sees a real TTY (spinners,
4529
+ * progress bars, ANSI colors are preserved). Completed lines are inspected
4530
+ * and any detected warning is re-echoed with our yellow ⚠ annotation.
4531
+ */
4532
+ const runStep = (cmd, step) => runInPty({
4533
+ command: cmd.command,
4534
+ args: cmd.args,
4535
+ cwd: cmd.cwd,
4536
+ env: cmd.env,
4537
+ onLine: annotateWarning
4538
+ }).pipe(Effect.flatMap((code) => code === 0 ? Effect.void : Effect.fail(buildFailed(step, code, `${step} exited with code ${code}`))));
4402
4539
  /**
4403
- * Run a build step with stdout piped through a formatter (e.g., xcpretty).
4404
- * stderr passes through to the terminal directly.
4540
+ * Run a build step in a PTY, but feed each completed line through the supplied
4541
+ * xcpretty-style formatter before writing. Warning detection still applies to
4542
+ * the formatter's output so xcodebuild deprecation notices stand out.
4543
+ *
4544
+ * The PTY guarantees xcodebuild sees a real TTY (so it keeps colored output);
4545
+ * the formatter strips noise. On failure the formatter's build summary is
4546
+ * flushed to stderr to help diagnose.
4405
4547
  */
4406
4548
  const runStepFormatted = (cmd, step, formatter) => Effect.gen(function* () {
4407
- const proc = yield* Command.start(cmd.pipe(Command.stdout("pipe"), Command.stderr("pipe"))).pipe(Effect.mapError((cause) => new BuildFailedError({
4408
- step,
4409
- exitCode: 1,
4410
- message: `${step} failed to spawn: ${String(cause)}`
4411
- })));
4412
- const stdoutFiber = yield* proc.stdout.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => {
4413
- const formatted = formatter.pipe(line);
4414
- return formatted.length > 0 ? Effect.sync(() => {
4415
- for (const output of formatted) process$1.stdout.write(`${output}\n`);
4416
- }) : Effect.void;
4417
- }), Effect.mapError((cause) => new BuildFailedError({
4418
- step,
4419
- exitCode: 1,
4420
- message: `${step} stdout stream error: ${String(cause)}`
4421
- })), Effect.fork);
4422
- const stderrFiber = yield* proc.stderr.pipe(Stream.decodeText(), Stream.splitLines, Stream.runForEach((line) => Effect.sync(() => process$1.stderr.write(`${line}\n`))), Effect.mapError((cause) => new BuildFailedError({
4423
- step,
4424
- exitCode: 1,
4425
- message: `${step} stderr stream error: ${String(cause)}`
4426
- })), Effect.fork);
4427
- yield* Effect.all([Fiber.join(stdoutFiber), Fiber.join(stderrFiber)], { concurrency: 2 }).pipe(Effect.catchAll(() => Effect.void));
4428
- const code = yield* proc.exitCode.pipe(Effect.mapError((cause) => new BuildFailedError({
4429
- step,
4430
- exitCode: 1,
4431
- message: `${step} exit code error: ${String(cause)}`
4432
- })));
4549
+ const code = yield* runInPty({
4550
+ command: cmd.command,
4551
+ args: cmd.args,
4552
+ cwd: cmd.cwd,
4553
+ env: cmd.env,
4554
+ silent: true,
4555
+ onLine: (line) => {
4556
+ const formatted = formatter.pipe(line);
4557
+ for (const output of formatted) if (isWarningLine(output)) process$1.stdout.write(`${styleWarningLine(output)}\n`);
4558
+ else process$1.stdout.write(`${output}\n`);
4559
+ }
4560
+ });
4433
4561
  if (code !== 0) {
4434
4562
  const summary = formatter.getBuildSummary();
4435
- if (summary) process$1.stderr.write(`${summary}\n`);
4436
- return yield* new BuildFailedError({
4437
- step,
4438
- exitCode: code,
4439
- message: `${step} exited with code ${code}`
4440
- });
4563
+ if (summary.length > 0) process$1.stderr.write(`${summary}\n`);
4564
+ return yield* Effect.fail(buildFailed(step, code, `${step} exited with code ${code}`));
4441
4565
  }
4442
4566
  });
4443
4567
 
@@ -4470,7 +4594,18 @@ const runAndroidBuild = (input) => Effect.gen(function* () {
4470
4594
  applicationIdentifier,
4471
4595
  tempDir
4472
4596
  });
4473
- yield* runStep(Command.make("bunx", "expo", "prebuild", "--platform", "android", "--clean").pipe(Command.workingDirectory(projectRoot), Command.env(commandEnv)), "expo prebuild android");
4597
+ yield* runStep({
4598
+ command: "bunx",
4599
+ args: [
4600
+ "expo",
4601
+ "prebuild",
4602
+ "--platform",
4603
+ "android",
4604
+ "--clean"
4605
+ ],
4606
+ cwd: projectRoot,
4607
+ env: commandEnv
4608
+ }, "expo prebuild android");
4474
4609
  const fs = yield* FileSystem.FileSystem;
4475
4610
  const signingGradlePath = path.join(tempDir, "signing.gradle");
4476
4611
  yield* fs.writeFileString(signingGradlePath, renderSigningGradle({
@@ -4479,8 +4614,16 @@ const runAndroidBuild = (input) => Effect.gen(function* () {
4479
4614
  keyAlias: credentials.keyAlias,
4480
4615
  keyPassword: credentials.keyPassword
4481
4616
  }));
4482
- const taskName = gradleTaskName(format, flavor, buildType);
4483
- yield* runStep(Command.make("./gradlew", "--init-script", signingGradlePath, `:app:${taskName}`).pipe(Command.workingDirectory(androidDir), Command.env(commandEnv)), "gradlew");
4617
+ yield* runStep({
4618
+ command: "./gradlew",
4619
+ args: [
4620
+ "--init-script",
4621
+ signingGradlePath,
4622
+ `:app:${gradleTaskName(format, flavor, buildType)}`
4623
+ ],
4624
+ cwd: androidDir,
4625
+ env: commandEnv
4626
+ }, "gradlew");
4484
4627
  const artifactPath = yield* findAndroidArtifact({
4485
4628
  projectRoot,
4486
4629
  format,
@@ -5127,6 +5270,12 @@ const applyTargetSigning = (options) => Effect.gen(function* () {
5127
5270
 
5128
5271
  //#endregion
5129
5272
  //#region src/lib/ios-export-options.ts
5273
+ const XCODE_METHOD = {
5274
+ "app-store": "app-store-connect",
5275
+ "ad-hoc": "release-testing",
5276
+ development: "debugging",
5277
+ enterprise: "enterprise"
5278
+ };
5130
5279
  const escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
5131
5280
  const boolTag = (value) => value ? "<true/>" : "<false/>";
5132
5281
  /**
@@ -5145,7 +5294,7 @@ const renderExportOptionsPlist = ({ method, teamId, provisioningProfiles, compil
5145
5294
  "<plist version=\"1.0\">",
5146
5295
  "<dict>",
5147
5296
  " <key>method</key>",
5148
- `\t<string>${escapeXml(method)}</string>`,
5297
+ `\t<string>${escapeXml(XCODE_METHOD[method])}</string>`,
5149
5298
  " <key>teamID</key>",
5150
5299
  `\t<string>${escapeXml(teamId)}</string>`,
5151
5300
  " <key>signingStyle</key>",
@@ -5327,8 +5476,8 @@ const validateIosBuild = (params) => Effect.gen(function* () {
5327
5476
  const validatedBundleIds = new Set(perBundle.map((entry) => entry.bundleId).filter((id) => id !== void 0));
5328
5477
  for (const expected of params.expectedTargets) if (!validatedBundleIds.has(expected.bundleId)) warnings.push(`Expected signed target "${expected.bundleId}" was not found in the archive.`);
5329
5478
  if (warnings.length > 0) {
5330
- yield* Console.warn("Post-build validation warnings:");
5331
- for (const warning of warnings) yield* Console.warn(` - ${warning}`);
5479
+ yield* printWarn("Post-build validation warnings:");
5480
+ for (const warning of warnings) yield* printWarn(` - ${warning}`);
5332
5481
  }
5333
5482
  return {
5334
5483
  passed: warnings.length === 0,
@@ -5485,8 +5634,24 @@ const findXcworkspace = (iosDir) => Effect.gen(function* () {
5485
5634
  return workspace;
5486
5635
  });
5487
5636
  const prebuildAndPods = (params) => Effect.gen(function* () {
5488
- yield* runStep(Command.make("bunx", "expo", "prebuild", "--platform", "ios", "--clean").pipe(Command.workingDirectory(params.projectRoot), Command.env(params.commandEnv)), "expo prebuild ios");
5489
- yield* runStep(Command.make("pod", "install").pipe(Command.workingDirectory(params.iosDir), Command.env(params.commandEnv)), "pod install");
5637
+ yield* runStep({
5638
+ command: "bunx",
5639
+ args: [
5640
+ "expo",
5641
+ "prebuild",
5642
+ "--platform",
5643
+ "ios",
5644
+ "--clean"
5645
+ ],
5646
+ cwd: params.projectRoot,
5647
+ env: params.commandEnv
5648
+ }, "expo prebuild ios");
5649
+ yield* runStep({
5650
+ command: "pod",
5651
+ args: ["install"],
5652
+ cwd: params.iosDir,
5653
+ env: params.commandEnv
5654
+ }, "pod install");
5490
5655
  });
5491
5656
  const findAppDirectory = (root) => Effect.gen(function* () {
5492
5657
  const fs = yield* FileSystem.FileSystem;
@@ -5521,13 +5686,46 @@ const runIosSimulatorBuild = (input) => Effect.gen(function* () {
5521
5686
  const scheme = iosProfile.scheme ?? workspaceFilename.replace(/\.xcworkspace$/u, "");
5522
5687
  const configuration = iosProfile.buildConfiguration ?? "Release";
5523
5688
  const derivedDataPath = path.join(tempDir, "derived-data");
5524
- const buildCmd = Command.make("xcodebuild", "-workspace", workspaceFilename, "-scheme", scheme, "-configuration", configuration, "-sdk", "iphonesimulator", "-destination", "generic/platform=iOS Simulator", "-derivedDataPath", derivedDataPath, "build", "CODE_SIGNING_ALLOWED=NO", "CODE_SIGNING_REQUIRED=NO", "CODE_SIGN_IDENTITY=").pipe(Command.workingDirectory(iosDir), Command.env(commandEnv));
5689
+ const buildCmd = {
5690
+ command: "xcodebuild",
5691
+ args: [
5692
+ "-workspace",
5693
+ workspaceFilename,
5694
+ "-scheme",
5695
+ scheme,
5696
+ "-configuration",
5697
+ configuration,
5698
+ "-sdk",
5699
+ "iphonesimulator",
5700
+ "-destination",
5701
+ "generic/platform=iOS Simulator",
5702
+ "-derivedDataPath",
5703
+ derivedDataPath,
5704
+ "build",
5705
+ "CODE_SIGNING_ALLOWED=NO",
5706
+ "CODE_SIGNING_REQUIRED=NO",
5707
+ "CODE_SIGN_IDENTITY="
5708
+ ],
5709
+ cwd: iosDir,
5710
+ env: commandEnv
5711
+ };
5525
5712
  const formatter = input.rawOutput ? void 0 : createXcodebuildFormatter(projectRoot);
5526
5713
  yield* formatter ? runStepFormatted(buildCmd, "xcodebuild build (simulator)", formatter) : runStep(buildCmd, "xcodebuild build (simulator)");
5527
5714
  const appDir = yield* findAppDirectory(path.join(derivedDataPath, "Build", "Products", `${configuration}-iphonesimulator`));
5528
5715
  const archiveName = `${path.basename(appDir, ".app")}-simulator.tar.gz`;
5529
5716
  const archivePath = path.join(tempDir, archiveName);
5530
- yield* runStep(Command.make("tar", "-czf", archivePath, "-C", path.dirname(appDir), path.basename(appDir)).pipe(Command.env(commandEnv)), "tar simulator .app");
5717
+ yield* runStep({
5718
+ command: "tar",
5719
+ args: [
5720
+ "-czf",
5721
+ archivePath,
5722
+ "-C",
5723
+ path.dirname(appDir),
5724
+ path.basename(appDir)
5725
+ ],
5726
+ cwd: projectRoot,
5727
+ env: commandEnv
5728
+ }, "tar simulator .app");
5531
5729
  const { sha256, byteSize } = yield* sha256File(archivePath);
5532
5730
  return {
5533
5731
  artifactPath: archivePath,
@@ -5630,7 +5828,23 @@ const runIosDeviceBuild = (input) => Effect.gen(function* () {
5630
5828
  }))
5631
5829
  });
5632
5830
  const archivePath = path.join(tempDir, "build.xcarchive");
5633
- const archiveCmd = Command.make("xcodebuild", "-workspace", workspaceFilename, "-scheme", scheme, "-configuration", configuration, "-archivePath", archivePath, "-allowProvisioningUpdates", "archive").pipe(Command.workingDirectory(iosDir), Command.env(commandEnv));
5831
+ const archiveCmd = {
5832
+ command: "xcodebuild",
5833
+ args: [
5834
+ "-workspace",
5835
+ workspaceFilename,
5836
+ "-scheme",
5837
+ scheme,
5838
+ "-configuration",
5839
+ configuration,
5840
+ "-archivePath",
5841
+ archivePath,
5842
+ "-allowProvisioningUpdates",
5843
+ "archive"
5844
+ ],
5845
+ cwd: iosDir,
5846
+ env: commandEnv
5847
+ };
5634
5848
  const formatter = input.rawOutput ? void 0 : createXcodebuildFormatter(projectRoot);
5635
5849
  yield* formatter ? runStepFormatted(archiveCmd, "xcodebuild archive", formatter) : runStep(archiveCmd, "xcodebuild archive");
5636
5850
  const exportOptionsPath = path.join(tempDir, "ExportOptions.plist");
@@ -5650,7 +5864,21 @@ const runIosDeviceBuild = (input) => Effect.gen(function* () {
5650
5864
  }))
5651
5865
  }));
5652
5866
  const exportPath = path.join(tempDir, "export");
5653
- const exportCmd = Command.make("xcodebuild", "-exportArchive", "-archivePath", archivePath, "-exportPath", exportPath, "-exportOptionsPlist", exportOptionsPath, "-allowProvisioningUpdates").pipe(Command.workingDirectory(iosDir), Command.env(commandEnv));
5867
+ const exportCmd = {
5868
+ command: "xcodebuild",
5869
+ args: [
5870
+ "-exportArchive",
5871
+ "-archivePath",
5872
+ archivePath,
5873
+ "-exportPath",
5874
+ exportPath,
5875
+ "-exportOptionsPlist",
5876
+ exportOptionsPath,
5877
+ "-allowProvisioningUpdates"
5878
+ ],
5879
+ cwd: iosDir,
5880
+ env: commandEnv
5881
+ };
5654
5882
  yield* formatter ? runStepFormatted(exportCmd, "xcodebuild exportArchive", formatter) : runStep(exportCmd, "xcodebuild exportArchive");
5655
5883
  yield* validateIosBuild({
5656
5884
  archivePath,
@@ -6235,7 +6463,7 @@ const readGradleConfig = (androidDir) => Effect.gen(function* () {
6235
6463
  const warnOnGradleMismatch = (gradleConfig, expectedPackage) => {
6236
6464
  if (!gradleConfig?.applicationId) return Effect.void;
6237
6465
  if (gradleConfig.applicationId === expectedPackage) return Effect.void;
6238
- return Console.warn(`Gradle applicationId "${gradleConfig.applicationId}" differs from app.json package "${expectedPackage}". The Gradle value will be used in the built APK/AAB.`);
6466
+ return printWarn(`Gradle applicationId "${gradleConfig.applicationId}" differs from app.json package "${expectedPackage}". The Gradle value will be used in the built APK/AAB.`);
6239
6467
  };
6240
6468
  /**
6241
6469
  * Strip Groovy single-line and block comments.