"+slugTitle(pn)+"
Built with PantheraHive BOS
This document details Step 3 of 5 in your "Site SEO Auditor" workflow: the AI-powered generation of precise fixes for identified SEO issues using Google's Gemini model.
Following the comprehensive crawl and audit of your website by our headless crawler (Puppeteer), our system identifies specific SEO elements that are either missing, incorrect, or suboptimal. Instead of merely reporting these issues, this crucial step leverages the advanced capabilities of Google's Gemini AI to automatically generate the exact, actionable code snippets or instructions required to fix each identified problem.
This proactive approach significantly streamlines your SEO remediation process, transforming audit reports from problem lists into solution blueprints.
The primary purpose of this step is to:
<img> tag, its surrounding HTML, and the image's purpose if inferable. For a broken link, it extracts the source page URL, the broken link URL, and the anchor text.Gemini receives the detailed context of each broken element and generates a precise, actionable fix.
* Page URL: https://www.yourwebsite.com/blog/latest-article
* Page Content Snippet: <div class="main-content"><h2>Subheading 1</h2><p>Article text...</p></div>
* Inferred Page Title/Topic: "Latest Article on AI Trends"
Gemini processes this input and generates an output that is typically a code snippet or a clear instruction set, ready for implementation. The output is formatted for direct use by developers or content managers.
Below are examples of the types of fixes Gemini will generate for various common SEO issues:
https://www.yourwebsite.com/product/item-a and https://www.yourwebsite.com/product/item-b. <!-- For: https://www.yourwebsite.com/product/item-a -->
<title>Product Item A - High Quality Gadget | YourBrand</title>
<meta name="description" content="Discover the features of Product Item A, a high-quality gadget from YourBrand. Shop now for exclusive deals."/>
<!-- For: https://www.yourwebsite.com/product/item-b -->
<title>Product Item B - Innovative Solution | YourBrand</title>
<meta name="description" content="Explore Product Item B, an innovative solution designed for efficiency. Find out more at YourBrand."/>
Workflow: Site SEO Auditor
Step: puppeteer → crawl
Description: This initial and foundational step leverages a headless browser (Puppeteer) to systematically visit and render every discoverable page on your website. Its primary objective is to accurately simulate a real user's browser experience, ensuring all dynamically loaded content and JavaScript-rendered elements are captured, which is critical for a comprehensive SEO audit.
The core objective of the puppeteer → crawl step is to:
Unlike traditional HTTP crawlers that only fetch raw HTML, this system employs Puppeteer to control a headless Chromium browser instance. This advanced approach offers several key advantages for SEO auditing:
The crawl process is executed systematically to ensure thorough coverage and data integrity:
* Upon loading each page, Puppeteer scans the fully rendered DOM for all internal <a> tags (hyperlinks).
* Discovered internal links are added to a queue for subsequent crawling, ensuring all navigable pages within the domain are identified.
* External links are noted but not followed to remain within the scope of your site.
* For each URL, a new browser page is opened, and the URL is navigated to.
* The browser waits for network idle conditions and specific DOM events (e.g., load, domcontentloaded) to ensure all resources have loaded and JavaScript has executed.
* Mobile Viewport Emulation: The browser viewport is set to a common mobile device size (e.g., iPhone X, 375x812 pixels) to assess mobile-specific rendering and performance.
* Full HTML/DOM Snapshot: The complete HTML content of the page as seen by the browser after all scripts have run.
* HTTP Status Code: The server's response code (e.g., 200 OK, 301 Redirect, 404 Not Found).
* Response Headers: Key HTTP response headers, including Content-Type, Cache-Control, etc.
* Initial Performance Metrics: Basic timing metrics from the browser's Performance API, such as DOMContentLoaded, loadEventEnd, and initial measurements for Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) if directly available from the browser context.
* Console Logs & Network Requests: Any JavaScript errors or significant network requests made by the page (optional, for advanced debugging).
* Timeouts: Pages that take too long to load are flagged.
* Network Errors: Connection issues or unreachable URLs.
* HTTP Errors: 4xx (client errors) and 5xx (server errors) status codes are recorded.
* A limited number of retries may be attempted for transient errors.
The Puppeteer instance is configured with best practices to ensure a robust and reliable crawl:
PantheraHive-SiteAuditor/1.0 (+https://pantherahive.com/seo-auditor)), allowing server-side logging and potential identification.deviceScaleFactor: 2) to ensure mobile-first rendering.Upon completion, this step generates a comprehensive dataset that serves as the foundation for the subsequent audit steps:
* The complete, fully rendered HTML content.
* The final URL after any redirects.
* Response headers.
* Initial performance metrics (e.g., loadEventEnd, FCP, LCP, CLS values captured from browser's performance timeline API).
The collected raw data from this crawl step will now be passed to the next stage of the "Site SEO Auditor" workflow:
This comprehensive crawling process ensures that the subsequent audit is based on the most accurate and complete representation of your website, reflecting the true user and search engine experience.
hive_db → diff - Comprehensive Audit Difference AnalysisThis crucial step in the Site SEO Auditor workflow is dedicated to providing you with a precise, actionable understanding of how your website's SEO performance is evolving. By comparing the results of the latest site crawl and audit against your historical data stored in PantheraHive's dedicated MongoDB instance (hive_db), we generate a detailed "diff" report. This report highlights all changes, improvements, and regressions, ensuring you have a clear, quantifiable perspective on your site's SEO health.
The primary goal of the hive_db → diff step is to:
Our system employs a robust comparison engine to meticulously analyze the audit data:
* Upon completion of a new site crawl and audit, the system first accesses hive_db to retrieve the most recent SiteAuditReport stored for your domain.
* This previous report serves as the baseline for comparison. If no prior report exists (e.g., this is the very first audit), the current audit becomes the initial baseline.
The system then performs a deep, page-by-page and metric-by-metric comparison between the current audit report and the previous* audit report.
* Every data point from the 12-point SEO checklist (e.g., meta titles, H1 presence, image alt coverage, Core Web Vitals scores, canonical tags, etc.) is systematically contrasted.
* Differences are intelligently categorized to provide immediate clarity on their nature and impact:
New Issues: Problems detected in the current audit that were not* present or flagged in the previous report.
Resolved Issues: Issues that were* present in the previous audit but are now successfully fixed and no longer detected.
* Improved Metrics: Quantitative or qualitative metrics that show a positive change (e.g., faster LCP, increased alt tag coverage, presence of a previously missing H1).
* Regressed Metrics: Quantitative or qualitative metrics that show a negative change (e.g., slower LCP, new instances of missing alt tags, removal of a previously present H1).
* Unchanged: Elements or metrics that remain consistent between the two audit periods.
The output of this step is a structured report detailing the identified changes:
* Example for Core Web Vitals: "LCP Score: Before 2.8s, After 1.9s (Improved)" or "CLS Score: Before 0.05, After 0.12 (Regressed)".
* Example for Qualitative Metrics: "H1 Presence on /product-page: Before Missing, After Present (Resolved)" or "Meta Description Uniqueness: Before Unique, After Duplicate (New Issue)".
The detailed diff report generated in this step offers significant advantages:
The detailed diff report, highlighting all broken elements and areas of regression, will now be used as input for the subsequent step. Specifically, the identified broken elements will be sent to Gemini for precise, actionable fix generation, further streamlining your SEO maintenance process.
<head> or <body> of the product page. Crucially, review and update the placeholder values (e.g., image URL, description, price, brand, rating) with the actual product data."Once Gemini has generated these detailed fixes, the workflow proceeds to:
hive_db Upsert OperationThis step focuses on the crucial persistence of your website's SEO audit results within our secure MongoDB database. Following the comprehensive crawling and analysis by our headless auditor and the AI-powered fix generation by Gemini, all findings are meticulously structured and stored as a SiteAuditReport. This ensures historical tracking, detailed insights, and the ability to monitor your site's SEO health over time.
hive_db UpsertThe hive_db upsert operation is responsible for:
SiteAuditReport document.SiteAuditReport Data Model OverviewEach time the Site SEO Auditor runs (either on demand or automatically), a new SiteAuditReport document is created in your dedicated MongoDB collection. This document encapsulates the entire audit for a specific website at a given point in time.
Key Fields of the SiteAuditReport Document:
_id (ObjectId): Unique identifier for this specific audit report (auto-generated by MongoDB).siteUrl (String): The root URL of the website that was audited (e.g., https://www.yourdomain.com).auditId (String): A unique, human-readable identifier for this audit run (e.g., audit-20231027-0830).timestamp (Date): The exact date and time when the audit was completed.status (String): Overall status of the audit (e.g., completed, failed, partial).overallScore (Number, 0-100): A calculated aggregate SEO score for the entire site, based on the checklist adherence and Core Web Vitals.pagesAudited (Number): The total count of unique pages successfully audited during this run.previousAuditId (String, Optional): References the auditId of the immediately preceding audit for the same siteUrl. This is crucial for diff calculations.summary (Object): A high-level summary of the audit findings. * totalPages: Total number of pages processed.
* pagesWithIssues: Number of pages with at least one SEO issue.
* criticalIssuesCount: Count of critical issues across all pages.
* warningsCount: Count of warning-level issues across all pages.
* coreWebVitalsAverages: Average LCP, CLS, FID scores across the site.
pageReports (Array of Objects): An array containing detailed audit results for each individual page visited by the crawler.pageReports Array)Each object within the pageReports array represents a single page's audit results and contains the following structure:
url (String): The full URL of the audited page.statusCode (Number): The HTTP status code returned for the page (e.g., 200, 301, 404).pageTitle (String, Optional): The <title> content of the page.auditedAt (Date): Timestamp when this specific page was audited.seoChecklistResults (Array of Objects): Detailed results for each of the 12 SEO checklist items. * checkName (String): Name of the SEO check (e.g., meta_title_uniqueness, h1_presence, image_alt_coverage).
* status (String): Result of the check (pass, fail, warning).
* details (Object): Specific information about the check's outcome.
* For meta_title_uniqueness: isUnique (Boolean), duplicateOf (Array of URLs if not unique).
* For h1_presence: foundH1 (Boolean), h1Content (String, Optional).
* For image_alt_coverage: totalImages (Number), imagesMissingAlt (Array of image URLs).
* For core_web_vitals: lcpScore, clsScore, fidScore (details below).
* ... and similar specific details for all 12 checks.
* issueDescription (String, Optional): A human-readable description of the identified issue.
* geminiFixSuggestion (String, Optional): The exact, actionable fix generated by Gemini for fail or warning statuses.
coreWebVitals (Object): Detailed performance metrics. * LCP (Largest Contentful Paint): score (ms), status (good, needs_improvement, poor).
* CLS (Cumulative Layout Shift): score (unitless), status (good, needs_improvement, poor).
* FID (First Input Delay): score (ms), status (good, needs_improvement, poor).
brokenElements (Array of Objects, Optional): A list of any broken links, images, or scripts found on the page. * elementType (String): e.g., link, image, script.
* src (String): The href or src attribute of the broken element.
* status (Number): The HTTP status code returned (e.g., 404, 500).
geminiFixes (Array of Objects, Optional): Specific, generated fixes by Gemini for broken elements or general page issues. * issueType (String): e.g., broken_link, missing_h1, duplicate_meta_description.
* elementSelector (String, Optional): CSS selector to locate the problematic element.
* suggestedFix (String): The precise code snippet or instruction to resolve the issue.
A critical feature of the SiteAuditReport is the inclusion of a "before/after diff." This is achieved by comparing the newly generated SiteAuditReport with the previousAuditId for the same siteUrl.
SiteAuditReport for your domain. It then performs a deep comparison of key metrics and checklist item statuses across all audited pages.diffReport (Object, within SiteAuditReport): This object is included in the new SiteAuditReport document and highlights changes since the previousAuditId. * comparedToAuditId (String): The auditId of the previous report used for comparison.
* overallScoreChange (Number): The change in overallScore (e.g., +5, -2).
newIssuesFound (Array of Objects): Details of issues identified in the current audit that were not* present in the previous one.
* pageUrl, checkName, issueDescription, geminiFixSuggestion.
* issuesResolved (Array of Objects): Details of issues that were present in the previous audit but are now pass in the current one.
* pageUrl, checkName, issueDescription (from previous report).
* performanceChanges (Array of Objects): Highlights significant changes in Core Web Vitals.
* pageUrl, metric (LCP, CLS, FID), oldScore, newScore, change.
* statusChanges (Array of Objects): Any checklist items that changed status (e.g., warning to fail, pass to warning).
* pageUrl, checkName, oldStatus, newStatus.
The hive_db operation utilizes MongoDB's updateOne method with the upsert: true option. However, for audit reports, we typically create a new document for each run rather than updating an existing one, to maintain a complete historical record.
The logic is as follows:
SiteAuditReport document is constructed based on the latest audit results.SiteAuditReport with the most recent timestamp for the given siteUrl.auditId is stored in the previousAuditId field of the new report, and the diffReport is calculated and embedded.SiteAuditReport document is then inserted into the site_audit_reports collection.This approach ensures that every audit run is preserved as an immutable snapshot, providing a robust timeline of your site's SEO evolution.
This sophisticated data storage and diffing mechanism delivers significant value:
By storing your audit results in this detailed and structured manner, we empower you with the data and insights needed to maintain and improve your website's search engine visibility effectively.
hive_db → conditional_update - Database Persistence & ReportingThis final step of the "Site SEO Auditor" workflow is critical for ensuring that all gathered audit data, SEO recommendations, and performance metrics are securely stored and made accessible for your review and action. The conditional_update operation intelligently manages your site's audit history within our MongoDB database, providing a robust foundation for tracking your SEO progress.
Upon successful completion of the site crawl, SEO checklist evaluation, and AI-powered fix generation by Gemini, this step orchestrates the persistence of the comprehensive SiteAuditReport. This involves either inserting a new audit record or updating an existing one, specifically designed to facilitate "before/after" comparisons and maintain a clear historical record of your site's SEO health.
SiteAuditReportThis collection is specifically designed to store all audit-related data, structured for easy retrieval, analysis, and diff generation.
SiteAuditReport Document Structure (Schema)Each document within the SiteAuditReport collection represents a single, complete audit of your website. The structure is comprehensive, capturing all aspects evaluated by the auditor and the AI-generated fixes.
{
"_id": "ObjectId", // Unique identifier for this audit report
"auditId": "string", // A human-readable unique ID for this specific audit run (e.g., UUID)
"siteUrl": "string", // The root URL of the audited website (e.g., "https://www.example.com")
"timestamp": "ISODate", // Date and time when this audit was completed
"auditType": "string", // Type of audit: "scheduled" (for weekly runs) or "on-demand"
"overallStatus": "string", // Aggregated status: "Pass", "Needs Improvement", "Critical Issues"
"pagesAudited": "number", // Total count of unique pages successfully crawled and audited
"summaryMetrics": {
"totalIssuesFound": "number", // Total number of individual SEO issues across all pages
"uniqueFixesRecommended": "number", // Total number of distinct fixes recommended by Gemini
"overallCoreWebVitalsScore": { // Aggregated Core Web Vitals score (e.g., average or worst-case)
"LCP": "number", // Largest Contentful Paint (ms)
"CLS": "number", // Cumulative Layout Shift
"FID": "number" // First Input Delay (ms) - often approximated for reports
},
"metaTitleCoverage": "number", // Percentage of pages with a unique meta title
"metaDescriptionCoverage": "number", // Percentage of pages with a unique meta description
"h1Coverage": "number", // Percentage of pages with a valid H1
"imageAltCoverage": "number", // Percentage of images with alt text
"canonicalTagCoverage": "number", // Percentage of pages with a canonical tag
"openGraphTagCoverage": "number", // Percentage of pages with Open Graph tags
"structuredDataCoverage": "number", // Percentage of pages with structured data
"mobileViewportCoverage": "number" // Percentage of pages with a mobile viewport meta tag
},
"pageDetails": [ // Array of objects, each representing an audited page
{
"pageUrl": "string", // URL of the specific page
"pageStatus": "string", // Status for this page: "Pass", "Warning", "Critical"
"seoMetrics": {
"metaTitle": {
"value": "string",
"status": "string", // "Pass", "Fail", "Warning"
"issues": ["string"], // e.g., "Missing", "Duplicate", "Too Long"
"recommendedFix": "string" // Gemini-generated fix, if applicable
},
"metaDescription": { /* ... similar structure ... */ },
"h1Presence": { /* ... similar structure ... */ },
"imageAltCoverage": { /* ... similar structure ... */ },
"internalLinkDensity": { /* ... similar structure ... */ },
"canonicalTag": { /* ... similar structure ... */ },
"openGraphTags": { /* ... similar structure ... */ },
"coreWebVitals": {
"LCP": "number", "CLS": "number", "FID": "number",
"status": "string", // "Good", "Needs Improvement", "Poor"
"issues": ["string"], // e.g., "LCP too high"
"recommendedFix": "string" // Gemini-generated fix
},
"structuredData": { /* ... similar structure ... */ },
"mobileViewport": { /* ... similar structure ... */ }
},
"brokenElements": [ // Array of specific broken elements found on this page (e.g., broken links, missing attributes)
{
"type": "string", // e.g., "link", "image", "script"
"selector": "string", // CSS selector or XPath to locate element
"attribute": "string", // Specific attribute if applicable (e.g., "href", "alt")
"issue": "string" // Description of the issue
}
],
"geminiFixes": [ // Array of all specific fixes generated by Gemini for this page
{
"metric": "string", // e.g., "metaTitle", "imageAltCoverage"
"description": "string", // Original issue description
"aiRecommendation": "string" // Detailed fix generated by Gemini
}
]
}
],
"previousAuditId": "string", // `auditId` of the immediately preceding audit for this site, if any
"diffReport": { // Generated only if `previousAuditId` is present
"newIssues": [ /* ... array of issues found that were not present previously ... */ ],
"resolvedIssues": [ /* ... array of issues that were present previously but are now resolved ... */ ],
"metricChanges": [ // Significant changes in key metrics
{
"metric": "string", // e.g., "overallCoreWebVitalsScore.LCP"
"oldValue": "any",
"newValue": "any",
"change": "string" // e.g., "+150ms", "-0.1 CLS"
}
]
}
}
The conditional_update logic ensures intelligent management of your audit history:
* If no prior SiteAuditReport exists for your siteUrl, a brand new document will be inserted into the SiteAuditReport collection. The previousAuditId and diffReport fields will be omitted as there is no prior baseline.
* The system first queries the SiteAuditReport collection to find the most recent audit report for your siteUrl.
* Diff Generation: The newly completed audit results are meticulously compared against the data from the previousAuditId report. This comparison generates the diffReport, highlighting:
New Issues: Any SEO problems identified in the current audit that were not* present or flagged in the previous audit.
* Resolved Issues: Issues that were present in the previous audit but are now marked as Pass or no longer detected in the current audit.
* Metric Changes: Quantifiable improvements or degradations in key metrics (e.g., Core Web Vitals, coverage percentages).
* New Report Insertion: A new SiteAuditReport document is then inserted, containing all the current audit data. Crucially, its previousAuditId field will be populated with the auditId of the preceding report, establishing a clear historical link.
* The diffReport field in the new document will contain the detailed comparison, allowing you to instantly see what has changed since the last audit.
diffReport provides immediate insights into the impact of your SEO efforts, clearly showing resolved issues and new challenges.Your SiteAuditReport is now successfully stored in the MongoDB database. You can access and visualize this detailed report, including the "before/after" diffs and Gemini's recommended fixes, through your dedicated PantheraHive dashboard or via API integration. The next scheduled audit will automatically run this Sunday at 2 AM (or can be triggered on-demand), continuing to build your site's SEO history.
No content
";}fr.dataset.loaded="1";}}}function phCopyCode(){navigator.clipboard.writeText(_phCode).then(function(){var b=document.getElementById("tab-code");if(b){var o=b.innerHTML;b.innerHTML=' Copied!';setTimeout(function(){b.innerHTML=o;},2000);}});}function phCopyAll(){var txt=_phAll;if(!txt){var vc=document.getElementById("panel-content");if(vc)txt=vc.innerText||vc.textContent||"";}navigator.clipboard.writeText(txt).then(function(){alert("Content copied to clipboard!");});}function phDownload(){var content=_phCode||_phAll;if(!content){var vc=document.getElementById("panel-content");if(vc)content=vc.innerText||vc.textContent||"";}if(!content){alert("No content to download.");return;}var fn=_phFname;if(!_phCode&&fn.endsWith(".txt"))fn=fn.replace(/\.txt$/,".md");var a=document.createElement("a");a.href="data:text/plain;charset=utf-8,"+encodeURIComponent(content);a.download=fn;a.click();}function phDownloadZip(){ var lbl=document.getElementById("ph-zip-lbl"); if(lbl)lbl.textContent="Preparing…"; /* ===== HELPERS ===== */ function cc(s){ return s.replace(/[_-s]+([a-z])/g,function(m,c){return c.toUpperCase();}) .replace(/^[a-z]/,function(m){return m.toUpperCase();}); } function pkgName(app){ return app.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"my_app"; } function slugTitle(app){ return app.replace(/_/g," "); } /* Generic code block extractor. Finds marker comments like: // lib/main.dart or # lib/main.dart or ## lib/main.dart and collects lines until the next marker. Also strips markdown fences (```lang ... ```) from each block. */ function extractFiles(txt, pathRe){ var files={}, cur=null, buf=[]; function flush(){ if(cur&&buf.length){ files[cur]=buf.join(" ").trim(); } } txt.split(" ").forEach(function(line){ var m=line.trim().match(pathRe); if(m){ flush(); cur=m[1]; buf=[]; return; } if(cur) buf.push(line); }); flush(); // Strip ```...``` fences from each file Object.keys(files).forEach(function(k){ files[k]=files[k].replace(/^```[a-z]* ?/,"").replace(/ ?```$/,"").trim(); }); return files; } /* General path extractor that covers most languages */ function extractCode(txt){ var re=/^(?://|#|##)s*((?:lib|src|test|tests|Sources?|app|components?|screens?|views?|hooks?|routes?|store|services?|models?|pages?)/[w/-.]+.w+|pubspec.yaml|Package.swift|angular.json|babel.config.(?:js|ts)|vite.config.(?:js|ts)|tsconfig.(?:json|app.json)|app.json|App.(?:tsx|jsx|vue|kt|swift)|MainActivity(?:.kt)?|ContentView.swift)/i; return extractFiles(txt, re); } /* Detect language from combined code+panel text */ function detectLang(code, panel){ var t=(code+" "+panel).toLowerCase(); if(t.indexOf("import 'package:flutter")>=0||t.indexOf('import "package:flutter')>=0) return "flutter"; if(t.indexOf("statelesswidget")>=0||t.indexOf("statefulwidget")>=0) return "flutter"; if((t.indexOf(".dart")>=0)&&(t.indexOf("pubspec")>=0||t.indexOf("flutter:")>=0)) return "flutter"; if(t.indexOf("react-native")>=0||t.indexOf("react_native")>=0) return "react-native"; if(t.indexOf("stylesheet.create")>=0||t.indexOf("view, text, touchableopacity")>=0) return "react-native"; if(t.indexOf("expo(")>=0||t.indexOf(""expo":")>=0||t.indexOf("from 'expo")>=0) return "react-native"; if(t.indexOf("import swiftui")>=0||t.indexOf("import uikit")>=0) return "swift"; if(t.indexOf(".swift")>=0&&(t.indexOf("func body")>=0||t.indexOf("@main")>=0||t.indexOf("var body: some view")>=0)) return "swift"; if(t.indexOf("import android.")>=0||t.indexOf("package com.example")>=0) return "kotlin"; if(t.indexOf("@composable")>=0||t.indexOf("fun mainactivity")>=0||(t.indexOf(".kt")>=0&&t.indexOf("androidx")>=0)) return "kotlin"; if(t.indexOf("@ngmodule")>=0||t.indexOf("@component")>=0) return "angular"; if(t.indexOf("angular.json")>=0||t.indexOf("from '@angular")>=0) return "angular"; if(t.indexOf(".vue")>=0||t.indexOf("")>=0||t.indexOf("definecomponent")>=0) return "vue"; if(t.indexOf("createapp(")>=0&&t.indexOf("vue")>=0) return "vue"; if(t.indexOf("import react")>=0||t.indexOf("reactdom")>=0||(t.indexOf("jsx.element")>=0)) return "react"; if((t.indexOf("usestate")>=0||t.indexOf("useeffect")>=0)&&t.indexOf("from 'react'")>=0) return "react"; if(t.indexOf(".dart")>=0) return "flutter"; if(t.indexOf(".kt")>=0) return "kotlin"; if(t.indexOf(".swift")>=0) return "swift"; if(t.indexOf("import numpy")>=0||t.indexOf("import pandas")>=0||t.indexOf("#!/usr/bin/env python")>=0) return "python"; if(t.indexOf("const express")>=0||t.indexOf("require('express')")>=0||t.indexOf("app.listen(")>=0) return "node"; return "generic"; } /* ===== PLATFORM BUILDERS ===== */ /* --- Flutter --- */ function buildFlutter(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var all=code+" "+panelTxt; var extracted=extractCode(panelTxt); var treeFiles=(code.match(/[w_]+.dart/g)||[]).filter(function(f,i,a){return a.indexOf(f)===i;}); if(!extracted["lib/main.dart"]) extracted["lib/main.dart"]="import 'package:flutter/material.dart'; void main()=>runApp(const "+cc(pn)+"App()); class "+cc(pn)+"App extends StatelessWidget{ const "+cc(pn)+"App({super.key}); @override Widget build(BuildContext context)=>MaterialApp( title: '"+slugTitle(pn)+"', debugShowCheckedModeBanner: false, theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: Scaffold(appBar: AppBar(title: const Text('"+slugTitle(pn)+"')), body: const Center(child: Text('Welcome!'))), ); } "; // pubspec.yaml — sniff deps var deps=[" flutter: sdk: flutter"]; var devDeps=[" flutter_test: sdk: flutter"," flutter_lints: ^5.0.0"]; var knownPkg={"go_router":"^14.0.0","flutter_riverpod":"^2.6.1","riverpod_annotation":"^2.6.1","shared_preferences":"^2.3.4","http":"^1.2.2","dio":"^5.7.0","firebase_core":"^3.12.1","firebase_auth":"^5.5.1","cloud_firestore":"^5.6.5","get_it":"^8.0.3","flutter_bloc":"^9.1.0","provider":"^6.1.2","cached_network_image":"^3.4.1","url_launcher":"^6.3.1","intl":"^0.19.0","google_fonts":"^6.2.1","equatable":"^2.0.7","freezed_annotation":"^2.4.4","json_annotation":"^4.9.0","path_provider":"^2.1.5","image_picker":"^1.1.2","uuid":"^4.4.2","flutter_svg":"^2.0.17","lottie":"^3.2.0","hive_flutter":"^1.1.0"}; var knownDev={"build_runner":"^2.4.14","freezed":"^2.5.7","json_serializable":"^6.8.0","riverpod_generator":"^2.6.3","hive_generator":"^2.0.1"}; Object.keys(knownPkg).forEach(function(p){if(all.indexOf("package:"+p)>=0)deps.push(" "+p+": "+knownPkg[p]);}); Object.keys(knownDev).forEach(function(p){if(all.indexOf(p)>=0)devDeps.push(" "+p+": "+knownDev[p]);}); zip.file(folder+"pubspec.yaml","name: "+pn+" description: Flutter app — PantheraHive BOS. version: 1.0.0+1 environment: sdk: '>=3.3.0 <4.0.0' dependencies: "+deps.join(" ")+" dev_dependencies: "+devDeps.join(" ")+" flutter: uses-material-design: true assets: - assets/images/ "); zip.file(folder+"analysis_options.yaml","include: package:flutter_lints/flutter.yaml "); zip.file(folder+".gitignore",".dart_tool/ .flutter-plugins .flutter-plugins-dependencies /build/ .pub-cache/ *.g.dart *.freezed.dart .idea/ .vscode/ "); zip.file(folder+"README.md","# "+slugTitle(pn)+" Generated by PantheraHive BOS. ## Setup ```bash flutter pub get flutter run ``` ## Build ```bash flutter build apk # Android flutter build ipa # iOS flutter build web # Web ``` "); zip.file(folder+"assets/images/.gitkeep",""); Object.keys(extracted).forEach(function(p){ zip.file(folder+p,extracted[p]); }); treeFiles.forEach(function(fn){ if(fn.indexOf("_test.dart")>=0) return; var found=Object.keys(extracted).some(function(p){return p.endsWith("/"+fn)||p===fn;}); if(!found){ var path="lib/"+fn; var cls=cc(fn.replace(".dart","")); var isScr=fn.indexOf("screen")>=0||fn.indexOf("page")>=0||fn.indexOf("view")>=0; var stub=isScr?"import 'package:flutter/material.dart'; class "+cls+" extends StatelessWidget{ const "+cls+"({super.key}); @override Widget build(BuildContext ctx)=>Scaffold( appBar: AppBar(title: const Text('"+fn.replace(/_/g," ").replace(".dart","")+"')), body: const Center(child: Text('"+cls+" — TODO')), ); } ":"// TODO: implement class "+cls+"{ // "+fn+" } "; zip.file(folder+path,stub); } }); } /* --- React Native (Expo) --- */ function buildReactNative(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var extracted=extractCode(panelTxt); var allT=code+" "+panelTxt; var usesTS=allT.indexOf(".tsx")>=0||allT.indexOf(": React.")>=0||allT.indexOf("interface ")>=0; var ext=usesTS?"tsx":"jsx"; zip.file(folder+"package.json",'{ "name": "'+pn+'", "version": "1.0.0", "main": "expo-router/entry", "scripts": { "start": "expo start", "android": "expo run:android", "ios": "expo run:ios", "web": "expo start --web" }, "dependencies": { "expo": "~52.0.0", "expo-router": "~4.0.0", "expo-status-bar": "~2.0.1", "expo-font": "~13.0.1", "react": "18.3.1", "react-native": "0.76.7", "react-native-safe-area-context": "4.12.0", "react-native-screens": "~4.3.0", "@react-navigation/native": "^7.0.14" }, "devDependencies": { "@babel/core": "^7.25.0", "typescript": "~5.3.3", "@types/react": "~18.3.12" } } '); zip.file(folder+"app.json",'{ "expo": { "name": "'+slugTitle(pn)+'", "slug": "'+pn+'", "version": "1.0.0", "orientation": "portrait", "scheme": "'+pn+'", "platforms": ["ios","android","web"], "icon": "./assets/icon.png", "splash": {"image": "./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"}, "ios": {"supportsTablet": true}, "android": {"package": "com.example.'+pn+'"}, "newArchEnabled": true } } '); zip.file(folder+"tsconfig.json",'{ "extends": "expo/tsconfig.base", "compilerOptions": { "strict": true, "paths": {"@/*": ["./src/*"]} } } '); zip.file(folder+"babel.config.js","module.exports=function(api){ api.cache(true); return {presets:['babel-preset-expo']}; }; "); var hasApp=Object.keys(extracted).some(function(k){return k.toLowerCase().indexOf("app.")>=0;}); if(!hasApp) zip.file(folder+"App."+ext,"import React from 'react'; import {View,Text,StyleSheet,StatusBar,SafeAreaView} from 'react-native'; export default function App(){ return(Built with PantheraHive BOS
Built with PantheraHive BOS
Built with PantheraHive BOS
"); h+="
"+hc+"