@forvibe/cli 0.1.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.
@@ -0,0 +1,168 @@
1
+ // src/ai/report-generator.ts
2
+ import { GoogleGenerativeAI } from "@google/generative-ai";
3
+ var SYSTEM_PROMPT = `You are a senior mobile app analyst and App Store Optimization specialist. You will receive technical data about a mobile application project including its tech stack, dependencies, config files, README, project file tree, and source code excerpts.
4
+
5
+ Your job is to deeply analyze the project and produce a comprehensive structured JSON analysis report.
6
+
7
+ ## ANALYSIS APPROACH \u2014 THINK LIKE A DETECTIVE:
8
+ 1. Study the PROJECT FILE TREE carefully. Directory names like "screens/", "models/", "services/", "pages/" reveal the app's architecture. File names like "plant_detail.dart", "watering_schedule.dart", "shop_screen.dart" reveal features.
9
+ 2. Read the SOURCE CODE thoroughly. Look for: screen/page names, navigation routes, data models, API calls, UI components, business logic, state management patterns.
10
+ 3. Cross-reference the README (if available) with actual code to understand the app's purpose.
11
+ 4. Even if the source code is minimal (e.g., a new project), infer the app's intent from naming conventions, file structure, bundle ID, and any available context.
12
+
13
+ ## DESCRIPTION REQUIREMENTS \u2014 THIS IS CRITICAL:
14
+ The "description" field must be a DETAILED, RICH description of 4-8 sentences that:
15
+ - Explains what the app does and its core purpose
16
+ - Describes the main features and user experience
17
+ - Mentions the target use case (e.g., "helps plant lovers track watering schedules")
18
+ - Notes any notable technical aspects (e.g., "uses real-time syncing", "leverages AI")
19
+ - If code is minimal, infer from app name, bundle ID, file structure, and README. NEVER leave this empty.
20
+ - Write as if you're explaining the app to someone who has never seen it. Be specific, not generic.
21
+
22
+ ## KEY FEATURES REQUIREMENTS:
23
+ - List 5-10 specific features you can identify from the code, file tree, and README
24
+ - Each feature should be a clear, descriptive phrase (e.g., "Plant watering schedule with customizable reminders" NOT just "Scheduling")
25
+ - Infer features from file names, screen names, model classes, and navigation structure
26
+ - If you see a "shop" screen, there's a shopping feature. If you see "notification", there's push notifications. Etc.
27
+
28
+ ## UNIQUE SELLING POINTS:
29
+ - 3-5 points that make this app stand out
30
+ - Be specific based on actual features found in the code
31
+
32
+ ## RESPONSE RULES:
33
+ - Respond ONLY with a valid JSON object, no markdown, no explanation
34
+ - All string values must be non-empty \u2014 NEVER return empty strings
35
+ - app_type must be one of: game, health, finance, ecommerce, education, media, utility, social, other
36
+ - advertising_type must be one of: personalized, non_personalized, none
37
+ - business_model.model must be one of: free, paid, freemium
38
+ - business_model.purchase_type must be one of: one_time, subscription, both, none
39
+ - app_category_suggestion should be an App Store category name (e.g., "Photo & Video", "Productivity", "Health & Fitness", "Lifestyle")
40
+ - target_audience should be a 2-3 sentence description of who would use this app and why`;
41
+ function buildUserPrompt(input) {
42
+ const parts = [];
43
+ parts.push(`## Tech Stack
44
+ - Framework: ${input.techStack.label}
45
+ - Platforms: ${input.techStack.platforms.join(", ")}
46
+ - Config files found: ${input.techStack.configFiles.join(", ")}`);
47
+ parts.push(`## Project Configuration
48
+ - App Name: ${input.config.app_name || "Unknown"}
49
+ - Bundle ID: ${input.config.bundle_id || "Unknown"}
50
+ - Version: ${input.config.version || "Unknown"}
51
+ - Min iOS: ${input.config.min_ios_version || "N/A"}
52
+ - Min Android SDK: ${input.config.min_android_sdk || "N/A"}
53
+ - Description from config: ${input.config.description || "N/A"}`);
54
+ if (input.projectTree) {
55
+ parts.push(`## Project File Tree (IMPORTANT \u2014 analyze directory and file names to understand the app's features and architecture)
56
+ ${input.projectTree}`);
57
+ }
58
+ if (input.sdkScan.detected_sdks.length > 0) {
59
+ parts.push(`## Detected SDKs (${input.sdkScan.detected_sdks.length})
60
+ ${input.sdkScan.detected_sdks.map((sdk) => `- ${sdk.name} (${sdk.category})`).join("\n")}
61
+
62
+ Data collected: ${input.sdkScan.data_collected.join(", ") || "none detected"}
63
+ Advertising type: ${input.sdkScan.advertising_type}
64
+ Has in-app purchases: ${input.sdkScan.has_iap}`);
65
+ } else {
66
+ parts.push(`## Detected SDKs
67
+ No known SDKs detected in dependencies. Determine data collection and business model from source code analysis.`);
68
+ }
69
+ if (input.readmeContent) {
70
+ parts.push(`## README Content (USE THIS to understand the app's purpose)
71
+ ${input.readmeContent.substring(0, 8e3)}`);
72
+ }
73
+ if (input.sourceCode) {
74
+ parts.push(`## Source Code Excerpts (ANALYZE CAREFULLY \u2014 look for screens, routes, models, features, API calls)
75
+ ${input.sourceCode.substring(0, 4e4)}`);
76
+ }
77
+ parts.push(`## Required JSON Response Format
78
+ {
79
+ "description": "4-8 sentence detailed description covering: what the app does, main features, target use case, and notable aspects. MUST be specific and non-empty.",
80
+ "app_type": "one of: game, health, finance, ecommerce, education, media, utility, social, other",
81
+ "is_for_children": false,
82
+ "app_category_suggestion": "App Store category name (e.g. Lifestyle, Health & Fitness, Productivity)",
83
+ "key_features": ["Detailed feature 1", "Detailed feature 2", "...up to 10 specific features found in code/tree"],
84
+ "target_audience": "2-3 sentences describing who would use this app and why",
85
+ "unique_selling_points": ["Specific USP 1", "Specific USP 2", "...3-5 items"],
86
+ "business_model": {
87
+ "model": "free | paid | freemium",
88
+ "purchase_type": "one_time | subscription | both | none",
89
+ "has_trial": false,
90
+ "has_auto_renewal": false
91
+ }
92
+ }`);
93
+ return parts.join("\n\n");
94
+ }
95
+ async function generateReport(input, apiKey) {
96
+ const genAI = new GoogleGenerativeAI(apiKey);
97
+ const model = genAI.getGenerativeModel({
98
+ model: "gemini-2.5-flash",
99
+ generationConfig: {
100
+ temperature: 0.4,
101
+ responseMimeType: "application/json"
102
+ }
103
+ });
104
+ const userPrompt = buildUserPrompt(input);
105
+ const result = await model.generateContent([
106
+ { text: SYSTEM_PROMPT },
107
+ { text: userPrompt }
108
+ ]);
109
+ const responseText = result.response.text();
110
+ let aiAnalysis;
111
+ try {
112
+ aiAnalysis = JSON.parse(responseText);
113
+ } catch {
114
+ const jsonMatch = responseText.match(/\{[\s\S]*\}/);
115
+ const rawJson = jsonMatch ? jsonMatch[0] : responseText;
116
+ try {
117
+ const cleaned = rawJson.replace(/,\s*([}\]])/g, "$1").replace(
118
+ /[\x00-\x1F\x7F]/g,
119
+ (ch) => ch === "\n" || ch === "\r" || ch === " " ? ch : ""
120
+ );
121
+ aiAnalysis = JSON.parse(cleaned);
122
+ } catch {
123
+ throw new Error("Failed to parse AI response as JSON");
124
+ }
125
+ }
126
+ const report = {
127
+ // Basic identification
128
+ app_name: input.config.app_name || "Unknown App",
129
+ bundle_id: input.config.bundle_id || "com.unknown.app",
130
+ description: aiAnalysis.description || input.config.description || "",
131
+ platforms: input.techStack.platforms,
132
+ tech_stack: input.techStack.label,
133
+ min_os_versions: {
134
+ ios: input.config.min_ios_version || void 0,
135
+ android: input.config.min_android_sdk || void 0
136
+ },
137
+ version: input.config.version || "1.0.0",
138
+ // Legal/Privacy from SDK scan + AI
139
+ app_type: aiAnalysis.app_type || "utility",
140
+ is_for_children: aiAnalysis.is_for_children || false,
141
+ data_collected: input.sdkScan.data_collected,
142
+ advertising_type: input.sdkScan.advertising_type,
143
+ third_party_services: input.sdkScan.third_party_services,
144
+ business_model: {
145
+ model: aiAnalysis.business_model?.model || "free",
146
+ purchase_type: aiAnalysis.business_model?.purchase_type || (input.sdkScan.has_iap ? "subscription" : "none"),
147
+ has_trial: aiAnalysis.business_model?.has_trial,
148
+ has_auto_renewal: aiAnalysis.business_model?.has_auto_renewal
149
+ },
150
+ // ASO
151
+ app_category_suggestion: aiAnalysis.app_category_suggestion || "Utilities",
152
+ key_features: aiAnalysis.key_features || [],
153
+ target_audience: aiAnalysis.target_audience || "",
154
+ unique_selling_points: aiAnalysis.unique_selling_points || [],
155
+ // Branding
156
+ primary_color: input.branding.primary_color || "#007AFF",
157
+ secondary_color: input.branding.secondary_color || "#5856D6",
158
+ app_icon_base64: input.branding.app_icon_base64,
159
+ // Raw data
160
+ detected_sdks: input.sdkScan.detected_sdks,
161
+ readme_content: input.readmeContent,
162
+ config_files_found: input.techStack.configFiles
163
+ };
164
+ return report;
165
+ }
166
+ export {
167
+ generateReport
168
+ };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@forvibe/cli",
3
+ "version": "0.1.0",
4
+ "description": "Forvibe CLI - AI-powered project analyzer for App Store automation",
5
+ "type": "module",
6
+ "bin": {
7
+ "forvibe": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsup src/index.ts --format esm --dts --clean",
11
+ "dev": "tsup src/index.ts --format esm --watch",
12
+ "start": "node dist/index.js",
13
+ "typecheck": "tsc --noEmit",
14
+ "lint": "eslint src/",
15
+ "prepublishOnly": "npm run build",
16
+ "release": "npm run build && npm publish --access public",
17
+ "release:dry": "npm run build && npm publish --access public --dry-run"
18
+ },
19
+ "keywords": [
20
+ "forvibe",
21
+ "app-store",
22
+ "aso",
23
+ "cli",
24
+ "ai",
25
+ "automation"
26
+ ],
27
+ "author": "Forvibe",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/Forvibe/cli.git"
32
+ },
33
+ "homepage": "https://forvibe.com",
34
+ "bugs": {
35
+ "url": "https://github.com/Forvibe/cli/issues"
36
+ },
37
+ "dependencies": {
38
+ "@google/generative-ai": "^0.24.0",
39
+ "chalk": "^5.4.1",
40
+ "commander": "^13.1.0",
41
+ "ora": "^8.2.0",
42
+ "plist": "^3.1.0",
43
+ "yaml": "^2.7.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^22.13.0",
47
+ "@types/plist": "^3.0.5",
48
+ "tsup": "^8.4.0",
49
+ "typescript": "^5.7.0"
50
+ },
51
+ "engines": {
52
+ "node": ">=18"
53
+ },
54
+ "files": [
55
+ "dist"
56
+ ]
57
+ }