@forvibe/cli 1.0.8 → 1.0.9

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.
Files changed (2) hide show
  1. package/dist/index.js +139 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2697,6 +2697,145 @@ async function analyzeCommand(options) {
2697
2697
  console.log(chalk.gray(" \u2139 Skipped \u2014 you can add this later in the dashboard."));
2698
2698
  }
2699
2699
  console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2700
+ if (techStack.platforms.includes("android")) {
2701
+ console.log();
2702
+ console.log(chalk.bold(" \u{1F916} Play Store Declarations"));
2703
+ console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2704
+ console.log(chalk.gray(" Google Play requires content declarations before publishing."));
2705
+ console.log(chalk.gray(" We'll auto-detect what we can and ask you to confirm."));
2706
+ console.log();
2707
+ const hasAdSDKs = (sdkScan.third_party_services.ads?.length ?? 0) > 0;
2708
+ const hasPaymentSDKs = (sdkScan.third_party_services.payment?.length ?? 0) > 0;
2709
+ const isHealthApp = report.app_type === "health";
2710
+ const isFinanceApp = report.app_type === "finance";
2711
+ const hasHealthSDKs = sdkScan.detected_sdks.some(
2712
+ (s) => s.name.toLowerCase().includes("health") || s.collects.includes("health_data")
2713
+ );
2714
+ const hasFinanceSDKs = hasPaymentSDKs || sdkScan.detected_sdks.some(
2715
+ (s) => s.name.toLowerCase().includes("billing") || s.name.toLowerCase().includes("stripe") || s.name.toLowerCase().includes("revenue")
2716
+ );
2717
+ let appAccess = "unrestricted";
2718
+ let appAccessInstructions;
2719
+ if (report.sign_in_required) {
2720
+ appAccess = "restricted_login";
2721
+ if (report.test_account) {
2722
+ appAccessInstructions = `Test account: ${report.test_account.email} / ${report.test_account.password}`;
2723
+ }
2724
+ console.log(chalk.white(" App Access: ") + chalk.yellow("Restricted (login required)"));
2725
+ } else {
2726
+ const accessAnswer = await askQuestion(
2727
+ chalk.cyan(" Does your app have restricted access (login, special permissions, etc.)? (y/n): ")
2728
+ );
2729
+ if (accessAnswer.toLowerCase().startsWith("y")) {
2730
+ appAccess = "restricted_login";
2731
+ const instrAnswer = await askQuestion(
2732
+ chalk.cyan(" How can a reviewer access all features? (describe or Enter to skip): ")
2733
+ );
2734
+ if (instrAnswer) appAccessInstructions = instrAnswer;
2735
+ } else {
2736
+ console.log(chalk.green(" \u2713 App is freely accessible"));
2737
+ }
2738
+ }
2739
+ let containsAds = hasAdSDKs || report.advertising_type !== "none";
2740
+ if (containsAds) {
2741
+ console.log(chalk.white(" Ads: ") + chalk.yellow(`Detected (${sdkScan.third_party_services.ads?.join(", ") || report.advertising_type})`));
2742
+ const adsConfirm = await askQuestion(
2743
+ chalk.cyan(" Does your app contain ads? (Y/n): ")
2744
+ );
2745
+ if (adsConfirm.toLowerCase() === "n") containsAds = false;
2746
+ } else {
2747
+ const adsAnswer = await askQuestion(
2748
+ chalk.cyan(" Does your app contain ads? (y/N): ")
2749
+ );
2750
+ containsAds = adsAnswer.toLowerCase().startsWith("y");
2751
+ }
2752
+ console.log(containsAds ? chalk.yellow(" \u2192 Contains ads") : chalk.green(" \u2713 No ads"));
2753
+ let targetAgeGroup = "all_ages";
2754
+ let isAppealToChildren = false;
2755
+ if (report.is_for_children) {
2756
+ console.log(chalk.yellow(" \u26A0 App appears to target children"));
2757
+ targetAgeGroup = "all_ages";
2758
+ isAppealToChildren = true;
2759
+ } else {
2760
+ console.log();
2761
+ console.log(chalk.gray(" Target age groups:"));
2762
+ console.log(chalk.gray(" 1. All ages (including children under 13)"));
2763
+ console.log(chalk.gray(" 2. Older users only (13+ or 18+)"));
2764
+ console.log(chalk.gray(" 3. Mixed (targets both children and older users)"));
2765
+ const ageAnswer = await askQuestion(chalk.cyan(" Choose target audience (1/2/3): "));
2766
+ if (ageAnswer === "2") {
2767
+ targetAgeGroup = "older_users_only";
2768
+ } else if (ageAnswer === "3") {
2769
+ targetAgeGroup = "mixed";
2770
+ isAppealToChildren = true;
2771
+ } else {
2772
+ targetAgeGroup = "all_ages";
2773
+ const appealAnswer = await askQuestion(
2774
+ chalk.cyan(" Could the app appeal to children even if not targeted at them? (y/N): ")
2775
+ );
2776
+ isAppealToChildren = appealAnswer.toLowerCase().startsWith("y");
2777
+ }
2778
+ }
2779
+ const govAnswer = await askQuestion(
2780
+ chalk.cyan(" Is this a government app? (y/N): ")
2781
+ );
2782
+ const isGovernmentApp = govAnswer.toLowerCase().startsWith("y");
2783
+ let hasFinancialFeatures = isFinanceApp || hasFinanceSDKs;
2784
+ if (hasFinancialFeatures) {
2785
+ console.log(chalk.white(" Financial features: ") + chalk.yellow("Detected"));
2786
+ const finConfirm = await askQuestion(
2787
+ chalk.cyan(" Does your app offer financial features (payments, digital wallet, crypto, etc.)? (Y/n): ")
2788
+ );
2789
+ if (finConfirm.toLowerCase() === "n") hasFinancialFeatures = false;
2790
+ } else {
2791
+ const finAnswer = await askQuestion(
2792
+ chalk.cyan(" Does your app offer financial features (payments, digital wallet, crypto, etc.)? (y/N): ")
2793
+ );
2794
+ hasFinancialFeatures = finAnswer.toLowerCase().startsWith("y");
2795
+ }
2796
+ let financialDetails;
2797
+ if (hasFinancialFeatures) {
2798
+ const finDetailsAnswer = await askQuestion(
2799
+ chalk.cyan(" Describe financial features briefly (or Enter to skip): ")
2800
+ );
2801
+ if (finDetailsAnswer) financialDetails = finDetailsAnswer;
2802
+ }
2803
+ let isHealthAppDecl = isHealthApp || hasHealthSDKs;
2804
+ if (isHealthAppDecl) {
2805
+ console.log(chalk.white(" Health app: ") + chalk.yellow("Detected"));
2806
+ const healthConfirm = await askQuestion(
2807
+ chalk.cyan(" Is this a health or fitness app? (Y/n): ")
2808
+ );
2809
+ if (healthConfirm.toLowerCase() === "n") isHealthAppDecl = false;
2810
+ } else {
2811
+ const healthAnswer = await askQuestion(
2812
+ chalk.cyan(" Is this a health or fitness app? (y/N): ")
2813
+ );
2814
+ isHealthAppDecl = healthAnswer.toLowerCase().startsWith("y");
2815
+ }
2816
+ let healthDetails;
2817
+ if (isHealthAppDecl) {
2818
+ const healthDetailsAnswer = await askQuestion(
2819
+ chalk.cyan(" Describe health features briefly (or Enter to skip): ")
2820
+ );
2821
+ if (healthDetailsAnswer) healthDetails = healthDetailsAnswer;
2822
+ }
2823
+ report.play_store_declarations = {
2824
+ app_access: appAccess,
2825
+ app_access_instructions: appAccessInstructions,
2826
+ contains_ads: containsAds,
2827
+ target_age_group: targetAgeGroup,
2828
+ is_appeal_to_children: isAppealToChildren,
2829
+ is_government_app: isGovernmentApp,
2830
+ has_financial_features: hasFinancialFeatures,
2831
+ financial_features_details: financialDetails,
2832
+ is_health_app: isHealthAppDecl,
2833
+ health_app_details: healthDetails
2834
+ };
2835
+ console.log();
2836
+ console.log(chalk.green(" \u2713 Play Store declarations collected"));
2837
+ console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2838
+ }
2700
2839
  console.log();
2701
2840
  const sendSpinner = ora({
2702
2841
  text: "Sending report to Forvibe...",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forvibe/cli",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Forvibe CLI - AI-powered project analyzer for App Store automation",
5
5
  "type": "module",
6
6
  "bin": {