"+slugTitle(pn)+"
\nBuilt with PantheraHive BOS
\nThis document details the execution and output of the initial crawling phase for your Site SEO Auditor. This crucial first step ensures a comprehensive and accurate foundation for the subsequent SEO audit.
Description: This step leverages Puppeteer, a headless browser, to systematically navigate and discover all accessible pages on your website. Unlike traditional HTTP crawlers, Puppeteer operates as a real browser, rendering JavaScript-heavy content and interacting with the DOM just like a user would. This ensures that no dynamically loaded content or client-side rendered pages are missed, providing a complete picture of your site's structure and content.
Purpose: The primary goal of this phase is to generate a definitive list of all internal URLs within your domain. This list serves as the input for the subsequent audit steps, ensuring that every page is thoroughly analyzed against the 12-point SEO checklist.
Methodology:
* For each visited page, Puppeteer analyzes the rendered DOM to identify all valid internal links (<a> tags with href attributes pointing to the same domain).
* These discovered links are added to a queue for subsequent visitation, ensuring a thorough exploration of the site's architecture.
* To prevent infinite loops and ensure efficiency, a robust link de-duplication mechanism is in place, only processing unique URLs.
robots.txt file, ensuring that pages explicitly disallowed for crawling are not accessed. This behavior can be configured if a full, unrestricted audit is required (e.g., for internal staging environments).* HTTP Status Code: To immediately identify broken links (e.g., 404 Not Found) or redirects (e.g., 301 Moved Permanently).
* Final URL: The resolved URL after any redirects.
* Parent URL: The URL from which the current page was discovered, helping to trace link paths.
* HTML Content (Initial Load): The raw HTML of the page upon initial load, before extensive DOM manipulation, is captured for later analysis.
Upon completion of the crawl, the following data is generated and will serve as the foundation for the subsequent SEO audit steps. This output is stored in a temporary, structured format, ready for processing.
Deliverable: A comprehensive list of all unique, discoverable internal URLs on your website, along with initial crawl metadata for each.
Structure (Example Snippet):
[
{
"id": "unique-uuid-1",
"url": "https://www.yourwebsite.com/",
"resolvedUrl": "https://www.yourwebsite.com/",
"httpStatusCode": 200,
"parentUrl": null, // null for the starting page
"crawlTimestamp": "2023-10-27T10:00:00Z",
"initialHtmlSnippet": "<!DOCTYPE html><html lang=\"en\">..." // First 1000 chars of HTML
},
{
"id": "unique-uuid-2",
"url": "https://www.yourwebsite.com/products/",
"resolvedUrl": "https://www.yourwebsite.com/products/",
"httpStatusCode": 200,
"parentUrl": "https://www.yourwebsite.com/",
"crawlTimestamp": "2023-10-27T10:00:05Z",
"initialHtmlSnippet": "<!DOCTYPE html><html lang=\"en\">..."
},
{
"id": "unique-uuid-3",
"url": "https://www.yourwebsite.com/old-page",
"resolvedUrl": "https://www.yourwebsite.com/new-page", // If redirected
"httpStatusCode": 301, // Indicates a redirect
"parentUrl": "https://www.yourwebsite.com/products/",
"crawlTimestamp": "2023-10-27T10:00:10Z",
"initialHtmlSnippet": "<html><head><meta http-equiv=\"refresh\" content=\"0; URL=/new-page\"/></head><body>..."
},
{
"id": "unique-uuid-4",
"url": "https://www.yourwebsite.com/broken-link",
"resolvedUrl": "https://www.yourwebsite.com/broken-link",
"httpStatusCode": 404, // Indicates a broken link
"parentUrl": "https://www.yourwebsite.com/about-us/",
"crawlTimestamp": "2023-10-27T10:00:15Z",
"initialHtmlSnippet": null // Or 404 page HTML
}
// ... many more entries
]
Key Information Provided:
id: A unique identifier for each discovered page, used for internal tracking.url: The URL as it was discovered by the crawler.resolvedUrl: The final URL after any redirects have been followed. This is crucial for auditing the correct page.httpStatusCode: The HTTP status code returned by the server (e.g., 200 OK, 301 Moved Permanently, 404 Not Found, 500 Internal Server Error).parentUrl: The URL of the page that contained the link leading to the current page. This helps in understanding the site's internal linking structure.crawlTimestamp: The exact time the page was crawled.initialHtmlSnippet: A brief snippet of the raw HTML content captured upon the initial page load.The comprehensive list of URLs and their initial crawl data from this step will now be passed to Step 2: Page Auditing & Data Extraction. In that phase, each of these discovered pages will be revisited by Puppeteer to perform a deep dive into its specific SEO attributes and collect all necessary data for the 12-point checklist.
hive_db → Diff - Comprehensive Audit ComparisonThis document details the second critical step in your Site SEO Auditor workflow: the hive_db → diff process. This phase is responsible for intelligently comparing your site's most recent SEO audit against a previous baseline (typically the last successful audit), identifying precise changes, improvements, regressions, and new issues across all audited pages and metrics.
The hive_db → diff step serves as the analytical core of your SEO auditing process. After the headless crawler (Step 1) has completed its comprehensive scan and stored the latest audit data in your dedicated MongoDB instance (hive_db), this step retrieves that fresh data alongside your site's previous audit report. It then performs a meticulous, page-by-page and metric-by-metric comparison to generate a detailed "diff" report.
Purpose: To provide a clear, actionable overview of your site's SEO performance evolution. This enables you to quickly pinpoint what has changed, track the impact of recent optimizations, identify emerging issues, and celebrate resolved problems. Without this diff, understanding the dynamic nature of your site's SEO health would be significantly more challenging.
hive_dbBefore any comparison can occur, the necessary audit reports are retrieved from your dedicated hive_db MongoDB instance.
SiteAuditReport from the most recent crawl (Step 1). This report contains all 12 SEO checklist points for every page discovered on your site during the current run.SiteAuditReport identified as the last successfully completed audit for your domain. This serves as the baseline for comparison. If no previous audit exists (e.g., first-ever run), the diff will effectively highlight all current issues as "new."Each SiteAuditReport document in MongoDB is structured to include:
_id: Unique identifier for the report.domain: The domain audited.timestamp: When the audit was completed.pages: An array of page objects, each containing: * url: The specific URL audited.
* metrics: An object detailing the status/value for each of the 12 SEO checklist items.
* issues: An array of specific problems found on that page.
The diffing process employs a sophisticated comparison algorithm to analyze the two audit reports. The comparison is performed on a page-by-page basis, and then drill-down into each of the 12 SEO metrics.
For each existing page, the system compares the status, value, or presence of each of the 12 SEO metrics between the current and previous audit.
* Logic: Compares the uniqueness status (unique, duplicate, missing) and the actual title/description content.
* Diff Outcomes:
* Resolved: Previously duplicate/missing, now unique and present.
* New Issue: Previously unique/present, now duplicate/missing.
* Regression: Previously unique, now duplicate with a new page.
* Content Change: Title/description content has changed (even if still unique).
* Logic: Checks for the presence and content of the <h1> tag.
* Diff Outcomes:
* Resolved: H1 was missing, now present.
* New Issue: H1 was present, now missing.
* Content Change: H1 text has been modified.
* Logic: Compares the count of images without alt attributes.
* Diff Outcomes:
* Resolved: Number of missing alt texts has decreased.
* New Issue: Number of missing alt texts has increased.
* Regression: Previously all images had alt text, now some are missing.
* Logic: Compares the number of internal links pointing to and from the page.
* Diff Outcomes:
* Change: Significant increase or decrease in internal link count (configurable threshold for "significant").
* Logic: Compares the presence, validity, and target URL of the canonical tag.
* Diff Outcomes:
* Resolved: Canonical tag was missing/incorrect, now present/correct.
* New Issue: Canonical tag was present/correct, now missing/incorrect.
* Target Change: Canonical URL has been updated.
* Logic: Compares the presence and content of essential Open Graph tags (og:title, og:description, og:image, og:url).
* Diff Outcomes:
* Resolved: OG tags were missing/incorrect, now present/correct.
* New Issue: OG tags were present/correct, now missing/incorrect.
* Content Change: Values for specific OG tags have been modified.
* Logic: Compares the Lighthouse scores for Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), and First Input Delay (FID) against predefined thresholds and previous scores.
* Diff Outcomes:
* Improvement: Score has improved, or passed a critical threshold (e.g., LCP moved from "Needs Improvement" to "Good").
* Regression: Score has worsened, or failed a critical threshold.
* No Change: Scores remain consistent.
* Logic: Compares the presence and types of structured data (e.g., Schema.org markup) detected on the page.
* Diff Outcomes:
* Resolved: Structured data was missing, now present.
* New Issue: Structured data was present, now missing.
* Schema Change: Different types of schema are now detected.
* Logic: Compares the presence and correct configuration of the viewport meta tag.
* Diff Outcomes:
* Resolved: Viewport tag was missing/incorrect, now present/correct.
* New Issue: Viewport tag was present/correct, now missing/incorrect.
Beyond just metric status, the diff also tracks specific issues. If a page previously had "Duplicate Meta Title" and now doesn't, that specific issue is marked as "Resolved." If a new "Missing H1" issue appears, it's marked as "New." This granular tracking provides precise insights into problem resolution and emergence.
The output of the hive_db → diff step is a structured Diff Report Object that clearly delineates all changes between the two audit runs. This object is then passed to the subsequent steps in the workflow.
(Current - Previous).For each affected page, a detailed breakdown will be provided:
NEW_PAGE, REMOVED_PAGE, MODIFIED_PAGE. * metric: The SEO metric affected (e.g., meta_title_uniqueness).
* type: NEW_ISSUE, RESOLVED_ISSUE, REGRESSION, VALUE_CHANGE.
* description: A human-readable description of the change (e.g., "Meta Title is now duplicate with /page-b," "H1 tag is now present," "LCP improved from 3.5s to 2.1s").
* previous_value: The value/status from the previous audit.
* current_value: The value/status from the current audit.
The report will categorize issues:
The detailed diff generated by this step provides immense value:
The comprehensive Diff Report Object generated in this step is immediately passed to the subsequent phases of the workflow:
SiteAuditReport document, including the "before/after" comparison.hive_db and delivered to you via your preferred notification channels.gemini → batch_generate - Automated SEO Fix GenerationThis document details the execution of Step 3 of 5 in the "Site SEO Auditor" workflow, focusing on the automated generation of precise fixes for identified SEO issues using Google Gemini.
Workflow: Site SEO Auditor
Current Step: gemini → batch_generate
Description: This crucial step leverages the advanced capabilities of Google Gemini to analyze the "broken elements" or SEO deficiencies identified by the headless crawler. Gemini then generates exact, actionable fixes for these issues in a batch process, significantly streamlining the SEO optimization workflow.
The primary purpose of this step is to transform raw audit findings into concrete, implementable solutions. Instead of merely flagging issues, the system intelligently provides the how-to-fix for each problem.
For each identified SEO issue, Gemini receives a structured prompt containing the following critical information:
alt attribute", "H1 tag is missing from the page", "Canonical tag points to incorrect URL").Example Input for a Missing H1:
Prompt: "On URL: https://www.example.com/product-page, the 'H1 Presence' audit failed. The page HTML snippet near the expected H1 position is: `<div class='header'><p>Product Overview</p></div>`. Please provide the exact HTML fix to add a semantically correct H1 tag."
Gemini processes the input and generates precise, ready-to-implement solutions. The output for each fix is structured to be highly actionable and developer-friendly.
Common Fix Formats Include:
Example (Missing H1)*:
<!-- Recommended fix: Insert this H1 tag after the opening <body> or within the main content area -->
<h1 class="page-title">Your Product Page Title Here</h1>
Example (Image Alt Text)*:
<!-- Recommended fix: Add or update the alt attribute for the image -->
<img src="/assets/product-image.jpg" alt="[Descriptive alt text for product image]">
Example (Duplicate Meta Description)*:
<!-- Recommended fix: Update the meta description for uniqueness and relevance -->
<meta name="description" content="[Unique, keyword-rich description for this specific page, max 160 characters]">
Example (Incorrect Canonical Tag)*:
<!-- Recommended fix: Ensure the canonical tag points to the correct, preferred version of the URL -->
<link rel="canonical" href="https://www.example.com/correct-product-page-url/">
Example (Missing Product Schema)*:
<!-- Recommended fix: Add this JSON-LD script to the <head> or <body> -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Your Product Name",
"image": "https://www.example.com/assets/product-image.jpg",
"description": "A brief description of your product.",
"sku": "SKU12345",
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"price": "99.99"
}
}
</script>
The generated fixes are immediately integrated into the SiteAuditReport document stored in MongoDB. Each fix is associated with the specific audit issue it addresses.
SiteAuditReport now contains not just a list of problems, but a comprehensive action plan, ready for review and implementation by your development or marketing team.This gemini → batch_generate step delivers significant value:
This step ensures that your Site SEO Auditor isn't just a diagnostic tool, but a powerful, proactive engine for continuous SEO improvement, providing not just the "what" but the "how" for every identified opportunity.
This crucial step marks the successful persistence of your comprehensive SEO audit findings. Following the completion of the in-depth scan and analysis by our headless crawler, all generated insights, identified issues, and Gemini-powered fixes are now securely stored within your dedicated hive_db database. This ensures a persistent, historical record of your site's SEO health.
The audit results are meticulously structured into a SiteAuditReport document, which is then upserted into the SiteAuditReports collection within your dedicated hive_db instance. This document captures every facet of the audit, enabling a holistic view of your site's SEO health.
Each SiteAuditReport document includes, but is not limited to, the following key fields:
audit_id: A unique identifier for this specific audit run, facilitating easy retrieval and tracking.site_url: The primary URL of the audited website.audit_timestamp: The exact date and time when the audit was completed, crucial for historical analysis.overall_score: An aggregate score reflecting the overall SEO health of your site based on the 12-point checklist.page_reports: An array of detailed reports for each individual page visited by the crawler, containing: * page_url: The URL of the specific page.
* meta_title: Content and uniqueness status (Pass/Fail).
* meta_description: Content and uniqueness status (Pass/Fail).
* h1_presence: Boolean indicating the presence of an H1 tag (Pass/Fail).
* image_alt_coverage: Percentage of images with descriptive alt text (Pass/Fail).
* internal_link_density: Number of internal links found on the page.
* canonical_tag: Presence and correctness of the canonical URL (Pass/Fail).
* open_graph_tags: Presence and validity of Open Graph tags for social sharing (Pass/Fail).
* core_web_vitals: Detailed scores for Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), and First Input Delay (FID) (Pass/Fail).
* structured_data_presence: Boolean indicating the presence of schema markup (Pass/Fail).
* mobile_viewport: Presence of the viewport meta tag for mobile responsiveness (Pass/Fail).
* status: An aggregate status for the page (e.g., "Good," "Needs Improvement," "Critical").
identified_issues: A consolidated, site-wide list of all broken elements and SEO deficiencies discovered during the audit, categorized for clarity.gemini_fixes: For each identified issue, a detailed, actionable fix generated by our Gemini AI, often including specific code snippets, configuration changes, or step-by-step instructions.before_after_diff: A critical component that automatically compares the current audit's findings with the most recent previous audit for your site. This highlights:* Improvements: Metrics or issues that have been resolved or improved.
* Regressions: Metrics or issues that have worsened since the last audit.
* New Issues: Problems identified for the first time.
This differential analysis provides immediate context on the impact of recent changes to your website.
The upsert operation is a highly efficient database command that intelligently handles the data persistence process within your hive_db (MongoDB) instance:
Insertion: If a SiteAuditReport for the specific audit_id (or site_url and audit_timestamp combination) does not* already exist in the SiteAuditReports collection, a new document is inserted. This typically occurs during the very first audit or a manual re-run that generates a new unique audit_id.
Update Logic: If a SiteAuditReport for the given site_url and audit_timestamp (or a similar identifying key for recurring audits) already exists*, the existing document is updated with the latest comprehensive audit results. This is crucial for maintaining a single, up-to-date record for a specific audit run, especially if any post-processing or additional data enrichment occurs.
site_url and audit_timestamp. This ensures that each unique audit run for your site is correctly identified and either stored as a new record or updated appropriately.hive_db instance, leveraging MongoDB's robust NoSQL capabilities for scalability and flexibility.By diligently storing your SiteAuditReport data in hive_db, we provide you with invaluable resources to continuously enhance and refine your SEO strategy:
before_after_diff component allows you to clearly visualize the improvements (or regressions) on specific metrics and issues, providing concrete, data-driven evidence of your SEO efforts' return on investment.With the SiteAuditReport successfully persisted in hive_db, the final step (Step 5) involves the critical distribution of these findings. This typically includes sending a comprehensive report to designated stakeholders and updating your centralized dashboard with the latest SEO health metrics, ensuring you and your team are immediately informed and ready to act on the audit results.
hive_db → conditional_update)This final step in the "Site SEO Auditor" workflow is critical for persisting the comprehensive audit results, enabling historical tracking, and providing actionable insights through a "before/after" comparison. All the data gathered by the headless crawler, analyzed against the 12-point SEO checklist, and enhanced with Gemini's fix suggestions, is now securely stored in your dedicated MongoDB database.
The conditional_update operation ensures that every SEO audit performed (either on-demand or via the weekly schedule) is meticulously recorded. This step serves to:
SiteAuditReport document.SiteAuditReport DocumentA new SiteAuditReport document is created in your MongoDB database for each audit run. This document is designed to be comprehensive and easily queryable.
Key Fields within a SiteAuditReport:
_id: Unique identifier for the audit report.siteUrl: The URL of the website that was audited.auditTimestamp: Date and time when the audit was completed (ISO format).triggerType: Indicates how the audit was initiated (scheduled or on-demand).overallStatus: An aggregated status for the entire site (Pass, Warning, Fail) based on the severity of identified issues.summary: * totalPagesAudited: Count of unique pages visited.
* pagesWithIssues: Count of pages that failed one or more checks.
* seoHealthScore: A calculated percentage score reflecting overall site SEO health.
* issuesByCategory: Breakdown of issues by type (e.g., metaTitleMissing: 5, imageAltMissing: 12).
pageResults: An array of objects, each representing the audit findings for a single page. * pageUrl: The URL of the specific page.
* pageStatus: (Pass, Warning, Fail) for this individual page.
* seoChecks: An object containing the results for each of the 12 SEO checklist items:
* metaTitle: { status: 'Pass'/'Fail', value: '...', issue: '...', fixSuggestion: '...' }
* metaDescription: { status: 'Pass'/'Fail', value: '...', issue: '...', fixSuggestion: '...' }
* h1Presence: { status: 'Pass'/'Fail', count: 1, issue: '...', fixSuggestion: '...' }
* imageAltCoverage: { status: 'Pass'/'Fail', coverage: '85%', issues: [...], fixSuggestion: '...' }
* internalLinkDensity: { status: 'Pass'/'Fail', count: 20, issue: '...', fixSuggestion: '...' }
* canonicalTag: { status: 'Pass'/'Fail', value: '...', issue: '...', fixSuggestion: '...' }
* openGraphTags: { status: 'Pass'/'Fail', tags: {...}, issue: '...', fixSuggestion: '...' }
* coreWebVitals: { status: 'Pass'/'Fail', lcp: '...', cls: '...', fid: '...', issue: '...', fixSuggestion: '...' }
* structuredData: { status: 'Pass'/'Fail', types: [...], issue: '...', fixSuggestion: '...' }
* mobileViewport: { status: 'Pass'/'Fail', issue: '...', fixSuggestion: '...' }
(Each issue field contains a description of the problem, and fixSuggestion holds the Gemini-generated actionable fix.)*
* brokenElements: An array of specific issues identified on the page, including their Gemini-generated fixes.
* issueDescription: "Missing H1 tag"
* geminiFix: "Add an H1 tag to the page, ensuring it's unique and semantically relevant to the page content. Example: <H1>Your Page Title Here</H1>"
diffFromPreviousAudit: (Detailed in the next section)Before storing the new report, the system performs a conditional_update check:
SiteAuditReport for the siteUrl being audited.* If a previous audit exists, a detailed "before/after" comparison is performed between the newly generated audit report and the previous one.
* This diff highlights:
New Issues: Problems present in the current audit that were not* in the previous one.
Resolved Issues: Problems present in the previous audit that are no longer* present in the current one.
* Changed Metrics: Significant changes in Core Web Vitals scores, link counts, or other quantifiable metrics.
* Page Status Changes: Pages that moved from Fail to Pass, Pass to Warning, etc.
SiteAuditReport (including the calculated diffFromPreviousAudit) is then inserted as a new document into the SiteAuditReports collection. This ensures a complete, timestamped record of every audit.Structure of diffFromPreviousAudit:
previousAuditId: Reference to the _id of the previous audit report.overallStatusChange: { from: 'Pass', to: 'Warning' }summaryChanges: * seoHealthScoreChange: +5% or -2%
* newIssuesCount: 3
* resolvedIssuesCount: 2
pageLevelChanges: An array detailing changes on specific pages. * pageUrl: URL of the page with changes.
* statusChange: { from: 'Pass', to: 'Fail' }
* issueChanges:
* newIssues: [Missing Meta Description, Poor LCP Score]
* resolvedIssues: [Duplicate H1]
* metricChanges: [LCP: from 2.5s to 3.8s]
The hive_db → conditional_update operation specifically involves:
SiteAuditReports (or a similar designated collection within your MongoDB instance).insertOne operation for the new SiteAuditReport document.siteUrl and auditTimestamp fields are indexed to facilitate efficient retrieval of historical reports and diff calculations.Upon completion of this step, your SEO audit data is fully processed and stored.
SiteAuditReport documents directly via your PantheraHive dashboard, which will present the data in an easily digestible format, including visual trends and the "before/after" diffs.This concludes the "Site SEO Auditor" workflow. Your site's SEO performance is now comprehensively audited, and actionable insights are stored and ready for your review.
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+"