"+slugTitle(pn)+"
\nBuilt with PantheraHive BOS
\nThis document details the execution and deliverables for the first critical step in your Site SEO Auditor workflow: the comprehensive web crawl and initial data collection using Puppeteer. This foundational step systematically visits every page on your site to gather essential SEO-related information, setting the stage for subsequent analysis and recommendations.
Purpose: The primary objective of this step is to act as a headless browser, meticulously navigating your website to discover all accessible pages and extract a baseline of critical SEO metrics and content elements. By simulating a real user's browser experience, Puppeteer ensures that dynamic content, JavaScript-rendered elements, and Core Web Vitals are accurately captured.
Technology Used: This step leverages Puppeteer, a Node.js library that provides a high-level API to control headless Chrome or Chromium. This allows for robust and realistic page rendering, interaction, and data extraction.
The crawling process is executed with the following methodology to ensure thoroughness and accuracy:
<a> tags pointing to the same domain) and adds them to a queue for subsequent processing, ensuring comprehensive site coverage.Upon successfully loading each page, Puppeteer executes a series of scripts within the browser context to extract the following critical SEO data points:
<title> tag and <meta name="description">.<h1> tag is present and extracts its text content.<img> tags, recording their src and checking for the presence and content of the alt attribute.href attributes.href attribute from <link rel="canonical"> if present.<meta property="og:..."> tags (e.g., og:title, og:description, og:image, og:url).<script type="application/ld+json"> blocks, indicating structured data implementation.<meta name="viewport"> tag.PerformanceObserver API for largest-contentful-paint entries, indicating the render time of the largest image or text block visible within the viewport.layout-shift entries via PerformanceObserver, quantifying unexpected layout shifts during page load.For every unique URL discovered and processed, the following structured data will be collected:
<title> tag.<meta name="description"> tag.<h1> tag (if multiple, only the first is recorded; presence and content are noted).imageSrc and altText for all <img> tags.href attributes.href attribute of the <link rel="canonical"> tag.og: meta properties.<script type="application/ld+json">.content attribute of the <meta name="viewport"> tag. * LCP: Value in milliseconds.
* CLS: Value as a decimal score.
* FID (or TBT proxy): Value in milliseconds.
The output of this step is a comprehensive, structured JSON dataset containing all the collected information for every crawled page. This dataset is then securely stored in a temporary staging area and immediately handed over to the next step in the workflow for initial validation and pre-processing before permanent storage in MongoDB.
Example Data Structure Snippet (per page):
{
"url": "https://www.yourdomain.com/example-page",
"statusCode": 200,
"pageTitle": "Example Page Title - Your Brand",
"metaDescription": "This is a detailed meta description for an example page.",
"h1Content": "Welcome to Our Example Page",
"imageAlts": [
{"src": "/img/hero.jpg", "alt": "A descriptive alt text for hero image"},
{"src": "/img/logo.png", "alt": "Your Brand Logo"}
],
"internalLinksCount": 15,
"canonicalUrl": "https://www.yourdomain.com/example-page",
"openGraph": {
"og:title": "Example Page Title",
"og:type": "website",
"og:image": "https://www.yourdomain.com/img/og-image.jpg"
},
"structuredDataPresent": true,
"viewportMeta": "width=device-width, initial-scale=1",
"coreWebVitals": {
"lcp": 1250, // milliseconds
"cls": 0.01, // score
"fid_tbt_proxy": 80 // milliseconds
},
"crawlTimestamp": "2023-10-27T08:30:00Z"
}
The collected data from this Puppeteer crawl will now be passed to Step 2: SEO Checklist Analysis & Issue Identification. In this subsequent step, the raw data will be systematically evaluated against the 12-point SEO checklist to identify specific areas of non-compliance or opportunity.
This step is crucial for understanding the evolution of your site's SEO performance over time. Following the completion of the latest site crawl and audit (Step 1), this phase focuses on intelligently comparing the new audit results with the previous audit data stored in our hive_db (MongoDB). The outcome is a comprehensive "before-and-after" differential report that highlights changes, improvements, and regressions across your website's pages and key SEO metrics.
The primary objective of this step is to generate a detailed, actionable diff report by:
SiteAuditReport document in MongoDB, preparing it for subsequent steps like automated fix generation.Our system executes a sophisticated comparison algorithm to analyze the two audit reports:
hive_dbSiteAuditReport (from Step 1) is immediately available for processing.hive_db to retrieve the SiteAuditReport that was completed prior to the current one for your specific website. This ensures we always compare against the most relevant preceding state.The comparison is performed on a page-by-page and metric-by-metric basis, covering the 12-point SEO checklist:
* Uniqueness (Meta Title/Description): Checks for changes in uniqueness status (e.g., if a previously unique title is now duplicated, or vice-versa).
* Presence (H1, Canonical, Open Graph, Structured Data, Mobile Viewport): Detects if a tag or element's presence status has changed (e.g., H1 added, canonical removed).
* Coverage (Image Alt): Monitors changes in the percentage or count of images with alt attributes.
* Density (Internal Links): Tracks fluctuations in the number of internal links per page.
* Performance (Core Web Vitals - LCP, CLS, FID): Compares the numerical values of these metrics, noting improvements or regressions against defined thresholds (e.g., LCP improving from "Needs Improvement" to "Good").
Each identified difference is categorized for clarity:
The direct output of this step is the enrichment of the SiteAuditReport with a comprehensive diff object, providing invaluable insights:
SiteAuditReport document now includes a dedicated diff field. This field contains: * site_level_summary: An aggregate overview of changes across the entire site (e.g., total pages with improved LCP, total new H1 issues).
* page_diffs: An array of objects, each representing a specific URL and detailing all changes observed on that page. For each URL, it lists:
* The specific SEO metric (meta_title_uniqueness, h1_presence, lcp_score, etc.).
* The previous_value and current_value.
* The change_type (e.g., "improved", "regressed", "new_issue", "resolved_issue").
* new_urls: A list of URLs found in the current audit that were not present in the previous one.
* removed_urls: A list of URLs present in the previous audit that are no longer found in the current one.
previous_value and current_value provides the exact context needed for Gemini to generate targeted and effective fixes in the subsequent step. Only elements identified as "broken" or "regressed" in this diff will be sent to Gemini.SiteAuditReport document is designed to accommodate the diff object, ensuring efficient storage and retrieval of historical comparisons.site_id and timestamp fields in MongoDB allows for rapid retrieval of the preceding audit report.This differential analysis is a cornerstone of effective SEO management, offering:
The detailed diff report generated in this step is now stored within your SiteAuditReport in hive_db. This rich data immediately feeds into Step 3: Gemini Fix Generation, where our AI will leverage these identified "broken elements" and regressions to formulate exact, actionable fixes for your development team.
gemini → batch_generate)This crucial step leverages the advanced capabilities of Google's Gemini AI to transform identified SEO issues into concrete, actionable solutions. Following the comprehensive site audit (Step 2), where a 12-point SEO checklist was applied to every page, any detected "broken elements" or optimization opportunities are now fed into Gemini.
Gemini then performs a sophisticated analysis, understanding the context of each issue and generating precise, developer-ready fixes or detailed recommendations. This process dramatically streamlines the remediation phase, moving from problem identification to solution generation automatically.
Gemini provides specific, actionable solutions for each point on our 12-point SEO checklist:
* Issue: Duplicate meta descriptions, titles too long/short, or lacking target keywords.
* Gemini Fix: Rewrites unique, compelling, and keyword-optimized meta titles and descriptions, adhering to character limits, by analyzing page content for core themes and entities.
* Example Output:
<title>New Product Name | Key Feature | Your Brand</title>
<meta name="description" content="Discover our innovative new product with [Key Feature 1] and [Key Feature 2]. Shop now for [Benefit 1] and [Benefit 2]." />
* Issue: Page missing an H1 tag or having multiple H1s, or an H1 that doesn't accurately reflect page content.
* Gemini Fix: Suggests a single, descriptive, and keyword-rich H1 tag based on the page's primary topic and content.
* Example Output:
<h1>Comprehensive Guide to SEO Auditing for E-commerce</h1>
* Issue: Images missing alt attributes or having generic alt text.
* Gemini Fix: Generates descriptive and keyword-relevant alt text for each image, considering its visual content (if image analysis is available) and surrounding textual context.
* Example Output:
<img src="seo-dashboard.jpg" alt="Screenshot of an SEO performance dashboard showing traffic trends and keyword rankings" />
* Issue: Pages with low internal link count or missed opportunities for relevant internal linking.
* Gemini Fix: Identifies highly relevant internal pages and suggests specific anchor text and placement for new internal links, improving site structure and crawlability.
* Example Output:
* "Consider adding an internal link from the 'Our Services' page to the 'Contact Us' page with the anchor text: Get a Free SEO Consultation."
* "On your 'Blog Post: Content Marketing Strategies,' link to your 'Service Page: Content Creation' using the anchor: Learn More About Our Content Creation Services."
* Issue: Incorrect or missing canonical tags, leading to duplicate content issues.
* Gemini Fix: Specifies the correct canonical URL for a page, ensuring search engines index the preferred version.
* Example Output:
<link rel="canonical" href="https://www.yourdomain.com/category/product-page-original" />
* Issue: Missing or incomplete Open Graph tags, leading to poor social media sharing previews.
* Gemini Fix: Generates accurate and complete OG tags (title, description, image, type, URL) based on page content, optimizing for social sharing.
* Example Output:
<meta property="og:title" content="Exclusive Offer: 20% Off All SEO Services This Month!" />
<meta property="og:description" content="Don't miss out! Boost your search rankings with our expert SEO services. Limited-time discount." />
<meta property="og:image" content="https://www.yourdomain.com/images/og-seo-offer.jpg" />
<meta property="og:url" content="https://www.yourdomain.com/special-offer" />
<meta property="og:type" content="website" />
* Issue: Poor performance metrics in Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), or First Input Delay (FID).
* Gemini Fix: Provides specific recommendations for code-level optimizations to improve performance, such as:
* LCP: Suggesting image compression, lazy loading strategies, font preloading, or critical CSS inlining.
* CLS: Recommending explicit width/height attributes for images/videos, reserving space for ads/embeds, or avoiding injecting content above existing content.
* FID: Advising on deferring non-critical JavaScript, breaking up long tasks, or optimizing third-party script loading.
* Example Output (Recommendation):
* "To improve LCP on /product/xyz, consider adding loading='lazy' to offscreen images and preloading the main hero image. Example: <link rel='preload' href='hero-image.jpg' as='image'>."
* "For CLS improvement on /blog/latest-post, ensure all images have explicit width and height attributes to prevent layout shifts during loading."
* Issue: Missing or incorrect JSON-LD structured data for common entities (e.g., Article, Product, FAQPage).
* Gemini Fix: Generates appropriate JSON-LD schema markup based on page content, enhancing search engine understanding and potentially enabling rich results.
* Example Output (for an Article page):
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "The Future of AI in SEO Auditing",
"image": [
"https://www.yourdomain.com/images/ai-seo-future.jpg"
],
"datePublished": "2023-10-27T09:00:00+08:00",
"dateModified": "2023-10-27T09:00:00+08:00",
"author": {
"@type": "Person",
"name": "Jane Doe"
},
"publisher": {
"@type": "Organization",
"name": "PantheraHive",
"logo": {
"@type": "ImageObject",
"url": "https://www.yourdomain.com/logo.png"
}
},
"description": "An in-depth look at how artificial intelligence is revolutionizing the way we conduct SEO audits and implement fixes."
}
</script>
* Issue: Missing or incorrect viewport meta tag, leading to poor mobile responsiveness.
* Gemini Fix: Provides the standard, responsive viewport meta tag to ensure proper rendering across all devices.
* Example Output:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
This step ensures that the SEO audit is not just a report of problems, but a direct pathway to a fully optimized website, with Gemini acting as your intelligent SEO developer. The generated fixes will then be stored in MongoDB as part of the SiteAuditReport, enabling a clear before/after diff for tracking progress.
This critical step ensures that the comprehensive SEO audit results generated by the headless crawler and the AI-powered fixes from Gemini are securely stored, versioned, and made accessible for historical tracking and analysis. We leverage our robust hive_db (a MongoDB instance) to perform an "upsert" operation, which intelligently either inserts a new SiteAuditReport document or updates an existing one if specific conditions are met, ensuring data integrity and efficient storage.
The primary goal of this step is to persistently store the detailed SiteAuditReport for your website. This enables:
Each SiteAuditReport document stored in hive_db is meticulously structured to capture all relevant data from the audit. Below is a detailed breakdown of its key fields:
_id (ObjectId): A unique identifier automatically generated by MongoDB for each audit report.siteUrl (String): The root URL of the website that was audited (e.g., https://www.example.com).auditTimestamp (ISODate): The exact date and time when the audit was completed, crucial for chronological tracking.runType (String): Indicates how the audit was initiated ("Automatic" for scheduled runs, or "On-demand" for manual requests).overallScore (Number): A composite score reflecting the overall SEO health of the site, based on the 12-point checklist.overallStatus (String): A high-level status (e.g., "Excellent", "Good", "Needs Improvement", "Critical").previousAuditId (ObjectId, Optional): A reference to the _id of the immediately preceding audit report for the same siteUrl, enabling efficient diffing.pages (Array of Objects): A comprehensive array, where each object represents the audit findings for a specific page on your website. * url (String): The full URL of the audited page.
* statusCode (Number): The HTTP status code returned for the page (e.g., 200, 404).
metrics (Object): Detailed results for each of the 12 SEO checklist points for this specific page*.
* metaTitle: { content: String, isUnique: Boolean, status: String }
* metaDescription: { content: String, isUnique: Boolean, status: String }
* h1Tag: { present: Boolean, content: String, status: String }
* imageAltTextCoverage: { coveragePercentage: Number, missingAlts: Array<String>, status: String }
* internalLinkDensity: { count: Number, densityPercentage: Number, status: String }
* canonicalTag: { present: Boolean, value: String, isCorrect: Boolean, status: String }
* openGraphTags: { present: Boolean, tags: Object, status: String }
* coreWebVitals: { lcp: Number, cls: Number, fid: Number, status: String }
* structuredData: { present: Boolean, schemas: Array<String>, isValid: Boolean, status: String }
* mobileViewport: { present: Boolean, isConfigured: Boolean, status: String }
* issues (Array of Objects): A list of specific issues identified on this page, before Gemini's intervention.
* description (String)
* severity (String: "Low", "Medium", "High", "Critical")
* type (String: "Missing H1", "Duplicate Meta Title", "Poor LCP", etc.)
aggregatedMetrics (Object): Site-wide summary metrics for a holistic view. * totalPagesAudited: Number
* uniqueMetaTitlesPercentage: Number
* uniqueMetaDescriptionsPercentage: Number
* averageLCP: Number
* averageCLS: Number
* averageFID: Number
* totalBrokenElements: Number (sum of all issues across all pages)
geminiFixes (Array of Objects): Contains all the AI-generated fixes for detected issues. * issueDescription (String): A clear description of the problem.
* pageUrl (String): The URL of the page where the issue was found.
* suggestedFix (String): The exact code snippet or textual instruction generated by Gemini to resolve the issue.
* severity (String): Severity of the original issue.
* fixConfidence (Number, 0-1): Gemini's confidence level in the generated fix.
auditDiff (Object, Optional): This object is generated only when a previousAuditId exists and captures the changes from the prior audit. * scoreChange: { absolute: Number, percentage: Number } (e.g., +5, +2.5%)
* newIssuesDetected: Array of Objects (issues present in current report but not in previous)
* issuesResolved: Array of Objects (issues present in previous report but not in current)
* metricChanges: Array of Objects (significant changes in key metrics, e.g., LCP improved by X ms on Y page)
The upsert process is designed for intelligence and efficiency:
hive_db to find the most recent SiteAuditReport for the siteUrl being audited.auditDiff: If a previous report is found, a sophisticated comparison algorithm is run to identify all changes:* Overall score improvement or degradation.
* New SEO issues that have appeared.
* Existing SEO issues that have been resolved.
* Significant shifts in Core Web Vitals or other key metrics on specific pages.
This auditDiff object is then embedded directly into the new* SiteAuditReport.
previousAuditId: The _id of the retrieved previous report (if any) is then assigned to the previousAuditId field of the current report, establishing a clear historical link.SiteAuditReport (including previousAuditId and auditDiff) is then inserted as a new document into the siteAuditReports collection in MongoDB. This ensures that every audit run creates a distinct, immutable record.This approach guarantees that you always have a complete historical record and an immediate understanding of how your site's SEO performance has evolved since the last audit.
hive_dbsiteAuditReportssiteAuditReports collection is indexed on siteUrl and auditTimestamp to facilitate rapid querying for historical reports and efficient retrieval of the latest audit for a given site.Upon successful completion of this step, a new SiteAuditReport document has been securely stored in your dedicated hive_db instance. This document contains all the audited data, aggregated metrics, AI-generated fixes, and a comprehensive "before/after" diff compared to your previous audit.
The data is now ready for the final step of the workflow, where it will be presented to you in an intuitive and actionable format, typically through a dedicated dashboard or detailed report. You will be able to review the current audit's findings, track historical performance, and directly access Gemini's recommended fixes.
hive_db → conditional_update)This is the final step in the "Site SEO Auditor" workflow, where all the gathered audit data, identified issues, and AI-generated fixes are systematically stored and updated within your dedicated PantheraHive MongoDB instance. This step ensures data persistence, historical tracking, and the foundation for comprehensive reporting and actionable insights.
The hive_db → conditional_update operation is responsible for:
SiteAuditReport DocumentAll audit results are stored as a SiteAuditReport document within your PantheraHive MongoDB database. This document is designed to be comprehensive, storing granular details for each page, overall site metrics, and historical comparison data.
A typical SiteAuditReport document will have the following structure:
{
"_id": "ObjectId", // Unique identifier for the audit report
"siteId": "String", // Your unique site identifier
"auditDate": "ISODate", // Timestamp of when the audit was completed
"auditType": "String", // "Scheduled" or "OnDemand"
"overallStatus": "String", // "Completed", "CompletedWithIssues", "Failed"
"totalPagesCrawled": "Number",
"issuesFoundCount": "Number",
"pagesWithIssuesCount": "Number",
"previousAuditId": "ObjectId | null", // Reference to the previous audit report for diffing
"pages": [ // Array of objects, one for each audited page
{
"url": "String",
"statusCode": "Number",
"isIndexable": "Boolean",
"seoChecks": {
"metaTitle": {
"value": "String",
"isUnique": "Boolean",
"length": "Number",
"status": "PASS | FAIL | N/A",
"issueDetails": "String | null",
"geminiFix": "String | null"
},
"metaDescription": {
"value": "String",
"isUnique": "Boolean",
"length": "Number",
"status": "PASS | FAIL | N/A",
"issueDetails": "String | null",
"geminiFix": "String | null"
},
"h1Presence": {
"value": "String | null",
"status": "PASS | FAIL",
"issueDetails": "String | null",
"geminiFix": "String | null"
},
"imageAltCoverage": {
"totalImages": "Number",
"imagesMissingAlt": "Number",
"coveragePercentage": "Number",
"status": "PASS | FAIL",
"issueDetails": "String | null",
"geminiFix": "String | null",
"brokenImages": [ // Example for detailed issues
{"src": "broken-image.jpg", "reason": "404 Not Found", "geminiFix": "Remove or replace image link."}
]
},
"internalLinkDensity": {
"totalInternalLinks": "Number",
"uniqueInternalLinks": "Number",
"status": "PASS | INFO",
"issueDetails": "String | null"
},
"canonicalTag": {
"value": "String | null",
"isSelfReferencing": "Boolean",
"status": "PASS | FAIL | N/A",
"issueDetails": "String | null",
"geminiFix": "String | null"
},
"openGraphTags": {
"ogTitle": "String | null",
"ogDescription": "String | null",
"ogImage": "String | null",
"status": "PASS | FAIL",
"issueDetails": "String | null",
"geminiFix": "String | null"
},
"coreWebVitals": {
"LCP": "Number", // Largest Contentful Paint (ms)
"CLS": "Number", // Cumulative Layout Shift
"FID": "Number", // First Input Delay (ms) - *Note: FID is often replaced by INP for real-world data*
"status": "PASS | FAIL",
"issueDetails": "String | null",
"geminiFix": "String | null"
},
"structuredData": {
"present": "Boolean",
"schemaTypes": ["Array of Strings"], // e.g., ["Article", "BreadcrumbList"]
"status": "PASS | INFO",
"issueDetails": "String | null"
},
"mobileViewport": {
"present": "Boolean",
"status": "PASS | FAIL",
"issueDetails": "String | null",
"geminiFix": "String | null"
}
// ... potentially other checks as the checklist evolves
},
"issues": [ // Consolidated list of issues for this page
{
"type": "String", // e.g., "MetaTitleDuplication", "MissingH1"
"severity": "String", // "Critical", "High", "Medium", "Low"
"description": "String",
"recommendedFix": "String", // Gemini-generated fix
"fieldAffected": "String" // e.g., "metaTitle", "h1Presence"
}
]
}
],
"diffReport": { // Comparison with the previous audit
"newIssuesCount": "Number",
"resolvedIssuesCount": "Number",
"regressedIssuesCount": "Number",
"issueChanges": [ // Array of objects detailing changes
{
"url": "String",
"issueType": "String",
"changeType": "NEW | RESOLVED | REGRESSED", // Was it new, fixed, or did it reappear/worsen?
"description": "String",
"severity": "String",
"previousStatus": "String | null",
"currentStatus": "String"
}
],
"pageChanges": [ // Summary of page-level changes
{
"url": "String",
"changeType": "ADDED | REMOVED | STATUS_CHANGE",
"details": "String"
}
]
}
}
The conditional_update logic operates as follows:
SiteAuditReport associated with your siteId.diffReport:* If a previous report is found, the current audit's results are compared against it.
* This comparison identifies:
* New Issues: Problems detected in the current audit that were not present in the previous one.
* Resolved Issues: Problems from the previous audit that are no longer present in the current one.
* Regressed Issues: Issues that were present, potentially resolved, and have reappeared or worsened.
* Page Status Changes: Any significant changes in page indexability, status codes, or overall health.
* This detailed differential is then populated into the diffReport field of the new SiteAuditReport.
SiteAuditReport document is created and inserted into the MongoDB collection. This ensures an immutable historical record of each audit.previousAuditId field in the newly created document is populated with the _id of the report it was compared against, establishing a clear lineage for historical analysis.siteId, auditDate, previousAuditId) are indexed to ensure fast retrieval for reporting and historical analysis.Once this step is complete, the SiteAuditReport document is immediately available for:
* Overall site SEO health score.
* A list of current critical issues.
* Graphs showing trends in issues over time.
* A detailed page-by-page breakdown of audit results.
* A dedicated "Changes Log" or "Diff Report" section highlighting new, resolved, and regressed issues.
* Direct access to Gemini's recommended fixes for each issue.
This robust database storage and conditional update mechanism provides immense value:
The SiteAuditReport for your site has now been successfully stored in your PantheraHive MongoDB database.
You can now navigate to your PantheraHive dashboard to review the full audit report, including the detailed diff from the previous run and all Gemini-generated fixes.
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(){navigator.clipboard.writeText(_phAll).then(function(){alert("Content copied to clipboard!");});}function phDownload(){var content=_phCode||_phAll;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\u2026"; /* ===== 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("\n").trim(); } } txt.split("\n").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]*\n?/,"").replace(/\n?\`\`\`$/,"").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(/\b[\w_]+\.dart\b/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';\n\nvoid main()=>runApp(const "+cc(pn)+"App());\n\nclass "+cc(pn)+"App extends StatelessWidget{\n const "+cc(pn)+"App({super.key});\n @override\n Widget build(BuildContext context)=>MaterialApp(\n title: '"+slugTitle(pn)+"',\n debugShowCheckedModeBanner: false,\n theme: ThemeData(\n colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),\n useMaterial3: true,\n ),\n home: Scaffold(appBar: AppBar(title: const Text('"+slugTitle(pn)+"')),\n body: const Center(child: Text('Welcome!'))),\n );\n}\n"; // pubspec.yaml — sniff deps var deps=[" flutter:\n sdk: flutter"]; var devDeps=[" flutter_test:\n 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+"\ndescription: Flutter app — PantheraHive BOS.\nversion: 1.0.0+1\n\nenvironment:\n sdk: '>=3.3.0 <4.0.0'\n\ndependencies:\n"+deps.join("\n")+"\n\ndev_dependencies:\n"+devDeps.join("\n")+"\n\nflutter:\n uses-material-design: true\n assets:\n - assets/images/\n"); zip.file(folder+"analysis_options.yaml","include: package:flutter_lints/flutter.yaml\n"); zip.file(folder+".gitignore",".dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n/build/\n.pub-cache/\n*.g.dart\n*.freezed.dart\n.idea/\n.vscode/\n"); zip.file(folder+"README.md","# "+slugTitle(pn)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nflutter pub get\nflutter run\n\`\`\`\n\n## Build\n\`\`\`bash\nflutter build apk # Android\nflutter build ipa # iOS\nflutter build web # Web\n\`\`\`\n"); 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';\n\nclass "+cls+" extends StatelessWidget{\n const "+cls+"({super.key});\n @override\n Widget build(BuildContext ctx)=>Scaffold(\n appBar: AppBar(title: const Text('"+fn.replace(/_/g," ").replace(".dart","")+"')),\n body: const Center(child: Text('"+cls+" — TODO')),\n );\n}\n":"// TODO: implement\n\nclass "+cls+"{\n // "+fn+"\n}\n"; 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",'{\n "name": "'+pn+'",\n "version": "1.0.0",\n "main": "expo-router/entry",\n "scripts": {\n "start": "expo start",\n "android": "expo run:android",\n "ios": "expo run:ios",\n "web": "expo start --web"\n },\n "dependencies": {\n "expo": "~52.0.0",\n "expo-router": "~4.0.0",\n "expo-status-bar": "~2.0.1",\n "expo-font": "~13.0.1",\n "react": "18.3.1",\n "react-native": "0.76.7",\n "react-native-safe-area-context": "4.12.0",\n "react-native-screens": "~4.3.0",\n "@react-navigation/native": "^7.0.14"\n },\n "devDependencies": {\n "@babel/core": "^7.25.0",\n "typescript": "~5.3.3",\n "@types/react": "~18.3.12"\n }\n}\n'); zip.file(folder+"app.json",'{\n "expo": {\n "name": "'+slugTitle(pn)+'",\n "slug": "'+pn+'",\n "version": "1.0.0",\n "orientation": "portrait",\n "scheme": "'+pn+'",\n "platforms": ["ios","android","web"],\n "icon": "./assets/icon.png",\n "splash": {"image": "./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},\n "ios": {"supportsTablet": true},\n "android": {"package": "com.example.'+pn+'"},\n "newArchEnabled": true\n }\n}\n'); zip.file(folder+"tsconfig.json",'{\n "extends": "expo/tsconfig.base",\n "compilerOptions": {\n "strict": true,\n "paths": {"@/*": ["./src/*"]}\n }\n}\n'); zip.file(folder+"babel.config.js","module.exports=function(api){\n api.cache(true);\n return {presets:['babel-preset-expo']};\n};\n"); 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';\nimport {View,Text,StyleSheet,StatusBar,SafeAreaView} from 'react-native';\n\nexport default function App(){\n return(\nBuilt with PantheraHive BOS
\n"); h+="
"+hc+"