preflightlaunch 0.2.3 → 0.2.4

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.
@@ -17431,8 +17431,8 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
17431
17431
  var source_default = chalk;
17432
17432
 
17433
17433
  // src/commands/submit.ts
17434
- import { readFileSync, statSync as statSync3 } from "fs";
17435
- import { basename as basename3, resolve as resolve3 } from "path";
17434
+ import { readFileSync, statSync as statSync3, existsSync as existsSync3, readdirSync as readdirSync3 } from "fs";
17435
+ import { basename as basename3, resolve as resolve3, extname as extname2, join as join3 } from "path";
17436
17436
 
17437
17437
  // src/lib/scanner.ts
17438
17438
  init_esm_shims();
@@ -21618,8 +21618,8 @@ var RealtimeChannel = class _RealtimeChannel {
21618
21618
  _trigger(type, payload, ref) {
21619
21619
  var _a, _b;
21620
21620
  const typeLower = type.toLocaleLowerCase();
21621
- const { close, error: error2, leave, join: join3 } = CHANNEL_EVENTS;
21622
- const events = [close, error2, leave, join3];
21621
+ const { close, error: error2, leave, join: join4 } = CHANNEL_EVENTS;
21622
+ const events = [close, error2, leave, join4];
21623
21623
  if (ref && events.indexOf(typeLower) >= 0 && ref !== this._joinRef()) {
21624
21624
  return;
21625
21625
  }
@@ -33813,7 +33813,8 @@ var KNOWN_COMMANDS = [
33813
33813
  { name: "report", description: "View analysis report" },
33814
33814
  { name: "history", description: "List past submissions" },
33815
33815
  { name: "setup", description: "Run guided setup" },
33816
- { name: "asc", description: "App Store Connect integration" }
33816
+ { name: "asc", description: "App Store Connect integration" },
33817
+ { name: "update", description: "Update to the latest version" }
33817
33818
  ];
33818
33819
  function levenshtein(a, b) {
33819
33820
  const matrix = [];
@@ -33945,22 +33946,6 @@ function calculateAgeRating(answers) {
33945
33946
  return "4+";
33946
33947
  }
33947
33948
  async function collectAppDetails(projectName, defaults) {
33948
- if (!defaults) {
33949
- const skipGate = await select({
33950
- message: "App Details (you can always add these later on the web)",
33951
- options: [
33952
- { value: "fill", label: "Fill in now", hint: "Name, description, keywords, category" },
33953
- { value: "skip", label: "Skip for now", hint: "Just use the project name" }
33954
- ]
33955
- });
33956
- if (skipGate === null) return null;
33957
- if (skipGate === "skip") {
33958
- return {
33959
- appName: projectName,
33960
- signInRequired: false
33961
- };
33962
- }
33963
- }
33964
33949
  const defaultName = defaults?.appName || projectName;
33965
33950
  const appName = await text({
33966
33951
  message: "App Name",
@@ -34081,12 +34066,7 @@ async function collectAgeRating() {
34081
34066
  if (hasMatureContent === null) return null;
34082
34067
  if (!hasMatureContent) {
34083
34068
  const rating = calculateAgeRating(defaultAnswers);
34084
- log.success(`Age Rating: ${rating} (no mature content)`);
34085
- const looksRight = await confirm("Does that look right?", true);
34086
- if (looksRight === null) return null;
34087
- if (!looksRight) {
34088
- return collectAgeRatingDetailed(defaultAnswers);
34089
- }
34069
+ log.success(`Age Rating: ${rating}`);
34090
34070
  return { answers: defaultAnswers, rating };
34091
34071
  }
34092
34072
  return collectAgeRatingDetailed(defaultAnswers);
@@ -34450,6 +34430,42 @@ async function submitCommand(path5, options = {}, fromMenu = false) {
34450
34430
  path: detected.screenshots[i]
34451
34431
  });
34452
34432
  }
34433
+ if (detected.screenshots.length === 0 && fromMenu) {
34434
+ const screenshotPath = await text({
34435
+ message: "Screenshots folder path (press Enter to skip)",
34436
+ placeholder: "e.g. ~/Desktop/screenshots"
34437
+ });
34438
+ if (screenshotPath === null) {
34439
+ await offerDraftSave(draftState);
34440
+ return;
34441
+ }
34442
+ if (screenshotPath.trim()) {
34443
+ const resolved = resolve3(screenshotPath.trim().replace(/^~/, process.env.HOME || ""));
34444
+ if (existsSync3(resolved)) {
34445
+ const imageExts = [".png", ".jpg", ".jpeg"];
34446
+ try {
34447
+ const files = readdirSync3(resolved).filter((f) => imageExts.includes(extname2(f).toLowerCase())).map((f) => join3(resolved, f));
34448
+ for (let i = 0; i < Math.min(files.length, 10); i++) {
34449
+ filesToUpload.push({
34450
+ type: "screenshot",
34451
+ index: i,
34452
+ filename: basename3(files[i]),
34453
+ path: files[i]
34454
+ });
34455
+ }
34456
+ if (files.length > 0) {
34457
+ log.success(`Found ${files.length} screenshot${files.length === 1 ? "" : "s"}`);
34458
+ } else {
34459
+ log.info("No images found in that folder.");
34460
+ }
34461
+ } catch {
34462
+ log.warning("Could not read that directory.");
34463
+ }
34464
+ } else {
34465
+ log.warning("Folder not found. Continuing without screenshots.");
34466
+ }
34467
+ }
34468
+ }
34453
34469
  if (filesToUpload.length === 0) {
34454
34470
  log.warning("No files to upload. Make sure you're pointing to an Xcode project directory.");
34455
34471
  if (fromMenu) return;
@@ -34459,42 +34475,29 @@ async function submitCommand(path5, options = {}, fromMenu = false) {
34459
34475
  let appDetails = null;
34460
34476
  let compliance = null;
34461
34477
  if (fromMenu) {
34462
- const reviewType = await select({
34463
- message: "What would you like to include in your review?",
34464
- options: [
34465
- { value: "quick", label: "Quick review (just analyze my project files)", hint: "Fastest option" },
34466
- { value: "full", label: "Full review (add app details + compliance info)", hint: "More thorough" }
34467
- ]
34468
- });
34469
- if (reviewType === null) {
34470
- if (fromMenu) await offerDraftSave(draftState);
34478
+ appDetails = await collectAppDetails(projectName);
34479
+ if (appDetails === null) {
34480
+ await offerDraftSave(draftState);
34471
34481
  return;
34472
34482
  }
34473
- if (reviewType === "full") {
34474
- appDetails = await collectAppDetails(projectName);
34475
- if (appDetails === null) {
34476
- if (fromMenu) await offerDraftSave(draftState);
34477
- return;
34478
- }
34479
- appName = appDetails.appName;
34480
- draftState.appName = appName;
34481
- draftState.description = appDetails.description;
34482
- draftState.keywords = appDetails.keywords;
34483
- draftState.category = appDetails.category;
34484
- draftState.supportUrl = appDetails.supportUrl;
34485
- draftState.promotionalText = appDetails.promotionalText;
34486
- draftState.marketingUrl = appDetails.marketingUrl;
34487
- draftState.signInRequired = appDetails.signInRequired;
34488
- draftState.demoUsername = appDetails.demoUsername;
34489
- draftState.demoPassword = appDetails.demoPassword;
34490
- appDetails = await offerAscAutofill(appDetails);
34491
- compliance = await collectCompliance();
34492
- if (compliance === null) {
34493
- if (fromMenu) await offerDraftSave(draftState);
34494
- return;
34495
- }
34496
- draftState.compliance = compliance;
34483
+ appName = appDetails.appName;
34484
+ draftState.appName = appName;
34485
+ draftState.description = appDetails.description;
34486
+ draftState.keywords = appDetails.keywords;
34487
+ draftState.category = appDetails.category;
34488
+ draftState.supportUrl = appDetails.supportUrl;
34489
+ draftState.promotionalText = appDetails.promotionalText;
34490
+ draftState.marketingUrl = appDetails.marketingUrl;
34491
+ draftState.signInRequired = appDetails.signInRequired;
34492
+ draftState.demoUsername = appDetails.demoUsername;
34493
+ draftState.demoPassword = appDetails.demoPassword;
34494
+ appDetails = await offerAscAutofill(appDetails);
34495
+ compliance = await collectCompliance();
34496
+ if (compliance === null) {
34497
+ await offerDraftSave(draftState);
34498
+ return;
34497
34499
  }
34500
+ draftState.compliance = compliance;
34498
34501
  }
34499
34502
  if (fromMenu) {
34500
34503
  console.log();
@@ -34990,4 +34993,4 @@ export {
34990
34993
  submitCommand,
34991
34994
  resumeSubmitCommand
34992
34995
  };
34993
- //# sourceMappingURL=chunk-26P7VL2P.js.map
34996
+ //# sourceMappingURL=chunk-5WAPKABO.js.map
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  text,
40
40
  tip,
41
41
  warning
42
- } from "./chunk-26P7VL2P.js";
42
+ } from "./chunk-5WAPKABO.js";
43
43
  import {
44
44
  __commonJS,
45
45
  __require,
@@ -5389,7 +5389,7 @@ async function scanCommand(path) {
5389
5389
  ]
5390
5390
  });
5391
5391
  if (next === "submit") {
5392
- const { submitCommand: submitCommand2 } = await import("./submit-HEQTSQL5.js");
5392
+ const { submitCommand: submitCommand2 } = await import("./submit-BWB7XOAF.js");
5393
5393
  await submitCommand2(dir, {});
5394
5394
  } else {
5395
5395
  tip(`Run ${brand("preflight submit")} anytime to get AI-powered fix instructions.`);
@@ -5988,9 +5988,84 @@ async function ascInteractiveMenu() {
5988
5988
  }
5989
5989
  }
5990
5990
 
5991
+ // src/commands/update.ts
5992
+ init_esm_shims();
5993
+ import { execFileSync } from "child_process";
5994
+ import { createRequire } from "module";
5995
+ function getCurrentVersion() {
5996
+ const require2 = createRequire(import.meta.url);
5997
+ const pkg = require2("../../package.json");
5998
+ return pkg.version;
5999
+ }
6000
+ async function getLatestVersion() {
6001
+ try {
6002
+ const res = await fetch("https://registry.npmjs.org/preflightlaunch/latest");
6003
+ if (!res.ok) return null;
6004
+ const data = await res.json();
6005
+ return data.version ?? null;
6006
+ } catch {
6007
+ return null;
6008
+ }
6009
+ }
6010
+ function compareSemver(a, b) {
6011
+ const pa = a.split(".").map(Number);
6012
+ const pb = b.split(".").map(Number);
6013
+ for (let i = 0; i < 3; i++) {
6014
+ if ((pa[i] ?? 0) < (pb[i] ?? 0)) return -1;
6015
+ if ((pa[i] ?? 0) > (pb[i] ?? 0)) return 1;
6016
+ }
6017
+ return 0;
6018
+ }
6019
+ async function updateCommand() {
6020
+ const current = getCurrentVersion();
6021
+ const s = spinner();
6022
+ s.start("Checking for updates...");
6023
+ const latest = await getLatestVersion();
6024
+ if (!latest) {
6025
+ s.stop("Could not check for updates");
6026
+ log.error("Failed to reach npm registry. Check your internet connection.");
6027
+ return;
6028
+ }
6029
+ if (compareSemver(current, latest) >= 0) {
6030
+ s.stop("Up to date!");
6031
+ console.log();
6032
+ console.log(` ${brand("Preflight")} ${brandDim(`v${current}`)} is the latest version.`);
6033
+ console.log();
6034
+ return;
6035
+ }
6036
+ s.stop(`Update available: ${current} \u2192 ${latest}`);
6037
+ console.log();
6038
+ const installSpinner = spinner();
6039
+ installSpinner.start(`Installing v${latest}...`);
6040
+ try {
6041
+ execFileSync("npm", ["install", "-g", "preflightlaunch@latest"], {
6042
+ stdio: "pipe",
6043
+ timeout: 6e4
6044
+ });
6045
+ installSpinner.stop(`Updated to v${latest}!`);
6046
+ console.log();
6047
+ console.log(` ${brand("Preflight")} has been updated to ${brandDim(`v${latest}`)}.`);
6048
+ console.log();
6049
+ } catch (err) {
6050
+ installSpinner.stop("Update failed");
6051
+ const msg = err instanceof Error ? err.message : "";
6052
+ if (msg.includes("EACCES") || msg.includes("permission")) {
6053
+ console.log();
6054
+ log.warning("Permission denied. Try running with sudo:");
6055
+ console.log(subtext(` sudo npm install -g preflightlaunch@latest`));
6056
+ console.log();
6057
+ } else {
6058
+ console.log();
6059
+ log.error("Could not update automatically. Run manually:");
6060
+ console.log(subtext(` npm install -g preflightlaunch@latest`));
6061
+ console.log();
6062
+ }
6063
+ }
6064
+ }
6065
+
5991
6066
  // src/index.ts
5992
6067
  var program2 = new Command();
5993
- program2.name("preflight").description("Preflight - App Store Review Scanner").version("0.2.3");
6068
+ program2.name("preflight").description("Preflight - App Store Review Scanner").version("0.2.4");
5994
6069
  program2.command("login").description("Log in to Preflight (opens browser)").action(loginCommand);
5995
6070
  program2.command("logout").description("Log out and clear stored credentials").action(logoutCommand);
5996
6071
  program2.command("whoami").description("Show current user and credit balance").action(whoamiCommand);
@@ -6001,6 +6076,7 @@ program2.command("report [id]").description("View full analysis report").option(
6001
6076
  program2.command("history").description("List past submissions").option("--json", "Output as JSON").action(historyCommand);
6002
6077
  program2.command("credits").description("Show credit balance").action(creditsCommand);
6003
6078
  program2.command("setup").description("Run guided setup (can be re-run anytime)").action(setupCommand);
6079
+ program2.command("update").description("Update Preflight to the latest version").action(updateCommand);
6004
6080
  var ascCmd = program2.command("asc").description("App Store Connect integration");
6005
6081
  ascCmd.command("connect").description("Connect your App Store Connect account").action(ascConnectCommand);
6006
6082
  ascCmd.command("status").description("Check App Store Connect connection status").action(ascStatusCommand);
@@ -4,10 +4,10 @@ const require = createRequire(import.meta.url);
4
4
  import {
5
5
  resumeSubmitCommand,
6
6
  submitCommand
7
- } from "./chunk-26P7VL2P.js";
7
+ } from "./chunk-5WAPKABO.js";
8
8
  import "./chunk-45JYNMSU.js";
9
9
  export {
10
10
  resumeSubmitCommand,
11
11
  submitCommand
12
12
  };
13
- //# sourceMappingURL=submit-HEQTSQL5.js.map
13
+ //# sourceMappingURL=submit-BWB7XOAF.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "preflightlaunch",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Preflight CLI - App Store Review Scanner from your terminal",
6
6
  "bin": {