@rankcli/agent-runtime 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -853,6 +853,7 @@ __export(index_exports, {
853
853
  applyFixes: () => applyFixes,
854
854
  buildGSCApiRequest: () => buildGSCApiRequest,
855
855
  buildGSCRequest: () => buildGSCRequest,
856
+ calculateAIVisibilityScore: () => calculateAIVisibilityScore,
856
857
  calculateBM25: () => calculateBM252,
857
858
  calculateKeywordTFIDF: () => calculateTFIDF,
858
859
  calculateNextRun: () => calculateNextRun,
@@ -867,6 +868,7 @@ __export(index_exports, {
867
868
  checkGitHubCLI: () => checkGitHubCLI,
868
869
  checkInternalRedirects: () => checkInternalRedirects,
869
870
  checkJSRenderingRatio: () => checkJSRenderingRatio,
871
+ checkLLMCitations: () => checkLLMCitations,
870
872
  checkLlmsTxt: () => checkLlmsTxt,
871
873
  checkMobileResources: () => checkMobileResources,
872
874
  checkPlaintextEmails: () => checkPlaintextEmails,
@@ -970,6 +972,7 @@ __export(index_exports, {
970
972
  generatePDFReport: () => generatePDFReport,
971
973
  generatePRDescription: () => generatePRDescription,
972
974
  generateReactHelmetSocialMeta: () => generateReactHelmetSocialMeta,
975
+ generateRecommendationQueries: () => generateRecommendationQueries,
973
976
  generateRemixMeta: () => generateRemixMeta,
974
977
  generateSecretsDoc: () => generateSecretsDoc,
975
978
  generateSocialMetaFix: () => generateSocialMetaFix,
@@ -977,6 +980,7 @@ __export(index_exports, {
977
980
  generateUncertaintyQuestions: () => generateUncertaintyQuestions,
978
981
  generateWizardQuestions: () => generateWizardQuestions,
979
982
  generateWorkflow: () => generateWorkflow,
983
+ getAIVisibilitySummary: () => getAIVisibilitySummary,
980
984
  getAutocompleteSuggestions: () => getAutocompleteSuggestions,
981
985
  getDateRange: () => getDateRange,
982
986
  getExpandedSuggestions: () => getExpandedSuggestions,
@@ -1321,6 +1325,15 @@ var ISSUE_DEFINITIONS = {
1321
1325
  impact: "Poor user experience and potential trust issues.",
1322
1326
  howToFix: "Update or remove the broken external link."
1323
1327
  },
1328
+ JS_ONLY_NAVIGATION: {
1329
+ code: "JS_ONLY_NAVIGATION",
1330
+ severity: "warning",
1331
+ category: "links",
1332
+ title: "JavaScript-only navigation detected",
1333
+ description: "Navigation elements use onClick handlers without proper <a href> links.",
1334
+ impact: "Search engine crawlers cannot follow JavaScript-only navigation. These links are invisible to crawlers, preventing page discovery and indexing.",
1335
+ howToFix: "Replace onClick navigation with proper <a href> or <Link> components. In React, use react-router Link instead of navigate() in onClick handlers. Ensure all navigation renders as real anchor tags with href attributes."
1336
+ },
1324
1337
  TOO_MANY_LINKS: {
1325
1338
  code: "TOO_MANY_LINKS",
1326
1339
  severity: "notice",
@@ -3183,6 +3196,7 @@ async function analyzeLinks(html, baseUrl, checkBroken = false) {
3183
3196
  const external = [];
3184
3197
  const brokenInternal = [];
3185
3198
  const brokenExternal = [];
3199
+ const jsOnlyNavigation = [];
3186
3200
  $("a[href]").each((_, el) => {
3187
3201
  const href = $(el).attr("href") || "";
3188
3202
  const text = $(el).text().trim();
@@ -3211,6 +3225,56 @@ async function analyzeLinks(html, baseUrl, checkBroken = false) {
3211
3225
  }
3212
3226
  });
3213
3227
  const totalLinks = internal.length + external.length;
3228
+ const navPatterns = /navigate|router|history\.push|location\.href|window\.location|goto|redirect/i;
3229
+ const navTextPatterns = /^(home|about|contact|pricing|blog|docs|features|products?|services?|sign\s*up|log\s*in|register|dashboard|account|settings|help|faq|support|menu|nav)$/i;
3230
+ $("button[onclick], div[onclick], span[onclick], li[onclick]").each((_, el) => {
3231
+ const $el = $(el);
3232
+ const onclick = $el.attr("onclick") || "";
3233
+ const text = $el.text().trim().substring(0, 50);
3234
+ if (navPatterns.test(onclick) || navTextPatterns.test(text)) {
3235
+ jsOnlyNavigation.push({
3236
+ element: el.tagName.toLowerCase(),
3237
+ text: text || "(no text)",
3238
+ reason: "Element uses onClick for navigation instead of <a href>"
3239
+ });
3240
+ }
3241
+ });
3242
+ $("a[onclick]").each((_, el) => {
3243
+ const $el = $(el);
3244
+ const href = $el.attr("href") || "";
3245
+ const onclick = $el.attr("onclick") || "";
3246
+ const text = $el.text().trim().substring(0, 50);
3247
+ if ((href === "#" || href === "" || href.startsWith("javascript:")) && onclick) {
3248
+ jsOnlyNavigation.push({
3249
+ element: "a",
3250
+ text: text || "(no text)",
3251
+ reason: `Link has href="${href}" with onClick - crawlers cannot follow this`
3252
+ });
3253
+ }
3254
+ });
3255
+ $("[data-href], [data-to], [data-link], [data-route]").each((_, el) => {
3256
+ const $el = $(el);
3257
+ const tagName = el.tagName.toLowerCase();
3258
+ const text = $el.text().trim().substring(0, 50);
3259
+ if (tagName !== "a" || !$el.attr("href") || $el.attr("href") === "#") {
3260
+ jsOnlyNavigation.push({
3261
+ element: tagName,
3262
+ text: text || "(no text)",
3263
+ reason: "Uses data attribute for routing instead of real href"
3264
+ });
3265
+ }
3266
+ });
3267
+ if (jsOnlyNavigation.length > 0) {
3268
+ const uniqueNav = jsOnlyNavigation.slice(0, 10);
3269
+ issues.push({
3270
+ ...ISSUE_DEFINITIONS.JS_ONLY_NAVIGATION,
3271
+ affectedUrls: [baseUrl],
3272
+ details: {
3273
+ count: jsOnlyNavigation.length,
3274
+ examples: uniqueNav
3275
+ }
3276
+ });
3277
+ }
3214
3278
  const internalCount = internal.length;
3215
3279
  const externalCount = external.length;
3216
3280
  const internalToExternalRatio = externalCount > 0 ? internalCount / externalCount : null;
@@ -3318,6 +3382,7 @@ async function analyzeLinks(html, baseUrl, checkBroken = false) {
3318
3382
  totalLinks,
3319
3383
  brokenInternal,
3320
3384
  brokenExternal,
3385
+ jsOnlyNavigation,
3321
3386
  ratio: {
3322
3387
  internal: internalCount,
3323
3388
  external: externalCount,
@@ -8693,6 +8758,12 @@ function analyzeContentScience(html, url, targetKeywords = []) {
8693
8758
  init_http();
8694
8759
  var cheerio28 = __toESM(require("cheerio"));
8695
8760
  async function getSSLCertificateAge(url) {
8761
+ let https;
8762
+ try {
8763
+ https = await import("https");
8764
+ } catch {
8765
+ return null;
8766
+ }
8696
8767
  return new Promise((resolve) => {
8697
8768
  try {
8698
8769
  const parsedUrl = new URL(url);
@@ -15210,7 +15281,7 @@ var cheerio49 = __toESM(require("cheerio"));
15210
15281
  init_http();
15211
15282
  async function analyzeHtmlCompliance(html, url, headers) {
15212
15283
  const issues = [];
15213
- const $ = cheerio49.load(html, { decodeEntities: false });
15284
+ const $ = cheerio49.load(html);
15214
15285
  const parsedUrl = new URL(url);
15215
15286
  const doctypeMatch = html.match(/<!DOCTYPE\s+([^>]+)>/i);
15216
15287
  const hasDoctype = doctypeMatch !== null;
@@ -26679,26 +26750,71 @@ async function generateFixForIssue(issue, context) {
26679
26750
  const fullUrl = url || "https://example.com";
26680
26751
  const siteName = new URL(fullUrl).hostname.replace("www.", "");
26681
26752
  switch (issue.code) {
26753
+ // Title issues
26682
26754
  case "MISSING_TITLE":
26755
+ case "TITLE_KEYWORD_MISMATCH":
26756
+ case "TITLE_H1_KEYWORD_MISMATCH":
26757
+ case "OUTDATED_YEAR_IN_TITLE":
26683
26758
  return generateTitleFix(context, siteName);
26759
+ // Meta description issues
26684
26760
  case "MISSING_META_DESC":
26685
26761
  return generateMetaDescFix(context, siteName);
26762
+ // Canonical issues
26686
26763
  case "MISSING_CANONICAL":
26764
+ case "CANONICAL_NO_HTTPS_REDIRECT":
26687
26765
  return generateCanonicalFix(context, fullUrl);
26766
+ // Viewport issues
26688
26767
  case "MISSING_VIEWPORT":
26768
+ case "HTML_NO_VIEWPORT":
26769
+ case "RESPONSIVE_NO_VIEWPORT":
26689
26770
  return generateViewportFix(context);
26771
+ // Open Graph issues
26690
26772
  case "MISSING_OG_TAGS":
26691
26773
  return generateOGFix(context, siteName, fullUrl);
26774
+ // Twitter Card issues
26692
26775
  case "MISSING_TWITTER_CARD":
26693
26776
  return generateTwitterFix(context, siteName);
26777
+ // Schema/structured data issues
26694
26778
  case "MISSING_SCHEMA":
26779
+ case "SCHEMA_ORG_MISSING":
26780
+ case "NO_ORGANIZATION_SCHEMA":
26781
+ case "NO_ENTITY_SCHEMA":
26782
+ case "FAQ_SCHEMA_MISSING":
26695
26783
  return generateSchemaFix(context, siteName, fullUrl);
26784
+ // Robots.txt issues
26696
26785
  case "MISSING_ROBOTS":
26786
+ case "ROBOTS_TXT_WARNINGS":
26787
+ case "ROBOTS_TXT_INVALID_SYNTAX":
26697
26788
  return generateRobotsFix(context, fullUrl);
26789
+ // Sitemap issues
26698
26790
  case "MISSING_SITEMAP":
26791
+ case "BING_SITEMAP_MISSING":
26699
26792
  return generateSitemapFix(context, fullUrl);
26793
+ // H1 issues
26700
26794
  case "MISSING_H1":
26795
+ case "NO_VISIBLE_HEADLINE":
26796
+ case "H1_MISSING_KEYWORD":
26701
26797
  return await generateH1Fix({ cwd });
26798
+ // SPA-specific: add meta management library recommendation
26799
+ case "SPA_NO_META_MANAGEMENT":
26800
+ return generateSPAMetaFix(context, framework);
26801
+ // Preconnect issues
26802
+ case "GOOGLE_FONTS_NO_PRECONNECT":
26803
+ case "MISSING_PRECONNECT":
26804
+ return generatePreconnectFix(context);
26805
+ // Favicon/icons
26806
+ case "HTML_NO_FAVICON":
26807
+ case "HTML_NO_APPLE_TOUCH_ICON":
26808
+ return generateFaviconFix(context);
26809
+ // Charset/lang
26810
+ case "HTML_NO_CHARSET":
26811
+ case "HTML_NOT_UTF8":
26812
+ return generateCharsetFix(context);
26813
+ case "HTML_NO_LANG":
26814
+ return generateLangFix(context);
26815
+ // AI/LLMs.txt
26816
+ case "AI_NO_LLMS_TXT":
26817
+ return generateLlmsTxtFix(context, siteName, fullUrl);
26702
26818
  default:
26703
26819
  return null;
26704
26820
  }
@@ -26927,6 +27043,159 @@ function generateSitemapFix(context, url) {
26927
27043
  explanation: "Created sitemap.xml to help search engines discover all pages"
26928
27044
  };
26929
27045
  }
27046
+ function generateSPAMetaFix(context, framework) {
27047
+ const { htmlPath } = context;
27048
+ if (framework.name.toLowerCase().includes("react") || framework.name === "Unknown") {
27049
+ return {
27050
+ issue: { code: "SPA_NO_META_MANAGEMENT", message: "SPA without dynamic meta tag management", severity: "warning" },
27051
+ file: "src/components/SEOHead.tsx",
27052
+ before: null,
27053
+ after: `import { Helmet } from 'react-helmet-async';
27054
+
27055
+ interface SEOHeadProps {
27056
+ title?: string;
27057
+ description?: string;
27058
+ image?: string;
27059
+ url?: string;
27060
+ }
27061
+
27062
+ export function SEOHead({
27063
+ title = 'Your Site Name',
27064
+ description = 'Your site description',
27065
+ image = '/og-image.png',
27066
+ url = window.location.href,
27067
+ }: SEOHeadProps) {
27068
+ return (
27069
+ <Helmet>
27070
+ <title>{title}</title>
27071
+ <meta name="description" content={description} />
27072
+ <link rel="canonical" href={url} />
27073
+
27074
+ {/* Open Graph */}
27075
+ <meta property="og:title" content={title} />
27076
+ <meta property="og:description" content={description} />
27077
+ <meta property="og:image" content={image} />
27078
+ <meta property="og:url" content={url} />
27079
+ <meta property="og:type" content="website" />
27080
+
27081
+ {/* Twitter */}
27082
+ <meta name="twitter:card" content="summary_large_image" />
27083
+ <meta name="twitter:title" content={title} />
27084
+ <meta name="twitter:description" content={description} />
27085
+ <meta name="twitter:image" content={image} />
27086
+ </Helmet>
27087
+ );
27088
+ }`,
27089
+ explanation: "Created SEOHead component using react-helmet-async for dynamic meta tags. Install: npm install react-helmet-async"
27090
+ };
27091
+ }
27092
+ return {
27093
+ issue: { code: "SPA_NO_META_MANAGEMENT", message: "SPA without meta management", severity: "warning" },
27094
+ file: htmlPath,
27095
+ before: null,
27096
+ after: "<!-- Add a meta management library for your framework -->",
27097
+ explanation: `Add dynamic meta tag management for ${framework.name}`,
27098
+ skipped: true,
27099
+ skipReason: `Framework-specific solution needed for ${framework.name}`
27100
+ };
27101
+ }
27102
+ function generatePreconnectFix(context) {
27103
+ const { htmlPath, htmlContent } = context;
27104
+ const preconnects = `<!-- Preconnect to external origins -->
27105
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
27106
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />`;
27107
+ return {
27108
+ issue: { code: "MISSING_PRECONNECT", message: "Missing preconnect hints", severity: "info" },
27109
+ file: htmlPath,
27110
+ before: "<head>",
27111
+ after: `<head>
27112
+ ${preconnects}`,
27113
+ explanation: "Added preconnect hints to speed up loading of external resources"
27114
+ };
27115
+ }
27116
+ function generateFaviconFix(context) {
27117
+ const { htmlPath } = context;
27118
+ const faviconTags = `<!-- Favicons -->
27119
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
27120
+ <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
27121
+ <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />`;
27122
+ return {
27123
+ issue: { code: "HTML_NO_FAVICON", message: "Missing favicon", severity: "info" },
27124
+ file: htmlPath,
27125
+ before: "<head>",
27126
+ after: `<head>
27127
+ ${faviconTags}`,
27128
+ explanation: "Added favicon links. Create favicon files in public/ directory."
27129
+ };
27130
+ }
27131
+ function generateCharsetFix(context) {
27132
+ const { htmlPath, htmlContent } = context;
27133
+ if (htmlContent.includes("charset")) {
27134
+ return {
27135
+ issue: { code: "HTML_NO_CHARSET", message: "Missing charset", severity: "warning" },
27136
+ file: htmlPath,
27137
+ before: null,
27138
+ after: '<meta charset="UTF-8" />',
27139
+ skipped: true,
27140
+ skipReason: "Charset already defined",
27141
+ explanation: "Charset is already present"
27142
+ };
27143
+ }
27144
+ return {
27145
+ issue: { code: "HTML_NO_CHARSET", message: "Missing charset declaration", severity: "warning" },
27146
+ file: htmlPath,
27147
+ before: "<head>",
27148
+ after: '<head>\n <meta charset="UTF-8" />',
27149
+ explanation: "Added UTF-8 charset declaration as first element in head"
27150
+ };
27151
+ }
27152
+ function generateLangFix(context) {
27153
+ const { htmlPath, htmlContent } = context;
27154
+ if (htmlContent.includes("<html") && !htmlContent.includes("lang=")) {
27155
+ return {
27156
+ issue: { code: "HTML_NO_LANG", message: "Missing lang attribute", severity: "warning" },
27157
+ file: htmlPath,
27158
+ before: "<html>",
27159
+ after: '<html lang="en">',
27160
+ explanation: "Added lang attribute for accessibility and SEO"
27161
+ };
27162
+ }
27163
+ return {
27164
+ issue: { code: "HTML_NO_LANG", message: "Missing lang attribute", severity: "warning" },
27165
+ file: htmlPath,
27166
+ before: "<html",
27167
+ after: '<html lang="en"',
27168
+ explanation: "Added lang attribute for accessibility and SEO"
27169
+ };
27170
+ }
27171
+ function generateLlmsTxtFix(context, siteName, url) {
27172
+ const llmsTxt = `# ${siteName}
27173
+ > ${siteName} - A brief description of your product/service
27174
+
27175
+ ## About
27176
+ ${siteName} is... [Add your description here]
27177
+
27178
+ ## Features
27179
+ - Feature 1
27180
+ - Feature 2
27181
+ - Feature 3
27182
+
27183
+ ## Links
27184
+ - Homepage: ${url}
27185
+ - Documentation: ${url}/docs
27186
+ - API: ${url}/api
27187
+
27188
+ ## Contact
27189
+ - Email: hello@${new URL(url).hostname}
27190
+ `;
27191
+ return {
27192
+ issue: { code: "AI_NO_LLMS_TXT", message: "No llms.txt file for AI crawlers", severity: "info" },
27193
+ file: "public/llms.txt",
27194
+ before: null,
27195
+ after: llmsTxt,
27196
+ explanation: "Created llms.txt to help AI systems understand your site. Customize the content."
27197
+ };
27198
+ }
26930
27199
  async function applyFixes(fixes, options) {
26931
27200
  const { cwd, dryRun = false } = options;
26932
27201
  const applied = [];
@@ -28725,6 +28994,105 @@ function escapeRegex2(str) {
28725
28994
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28726
28995
  }
28727
28996
 
28997
+ // src/geo/llm-citation-checker.ts
28998
+ var PROVIDER_NAMES = {
28999
+ openai: "ChatGPT",
29000
+ anthropic: "Claude",
29001
+ google: "Gemini",
29002
+ perplexity: "Perplexity"
29003
+ };
29004
+ var DEFAULT_PROVIDERS = ["openai", "anthropic", "google", "perplexity"];
29005
+ function generateRecommendationQueries(brand, industry) {
29006
+ const queries = [
29007
+ `What are the best ${brand.toLowerCase()} alternatives?`,
29008
+ `Can you recommend tools similar to ${brand}?`,
29009
+ `What do you think about ${brand}?`
29010
+ ];
29011
+ if (industry) {
29012
+ queries.push(`What are the best ${industry} tools?`);
29013
+ queries.push(`Recommend a good ${industry} solution`);
29014
+ }
29015
+ return queries;
29016
+ }
29017
+ async function checkLLMCitations(brand, domain, options = {}) {
29018
+ const {
29019
+ providers = DEFAULT_PROVIDERS,
29020
+ queries = generateRecommendationQueries(brand),
29021
+ ...trackingOptions
29022
+ } = options;
29023
+ const brandConfig = {
29024
+ brandName: brand,
29025
+ domains: [domain],
29026
+ alternativeNames: [brand.toLowerCase(), brand.toUpperCase()]
29027
+ };
29028
+ const query = queries[0];
29029
+ const results = await trackLLMVisibility(
29030
+ {
29031
+ keyword: query,
29032
+ brand: brandConfig,
29033
+ providers
29034
+ },
29035
+ trackingOptions
29036
+ );
29037
+ return results.map((result) => ({
29038
+ provider: result.provider,
29039
+ providerName: PROVIDER_NAMES[result.provider],
29040
+ mentioned: result.mentioned,
29041
+ position: result.position,
29042
+ sentiment: result.sentiment,
29043
+ context: result.contextSnippet || null,
29044
+ score: result.score,
29045
+ error: result.error
29046
+ }));
29047
+ }
29048
+ function calculateAIVisibilityScore(results) {
29049
+ if (results.length === 0) return 0;
29050
+ const mentionedCount = results.filter((r) => r.mentioned && !r.error).length;
29051
+ const validResults = results.filter((r) => !r.error);
29052
+ if (validResults.length === 0) return 0;
29053
+ let score = mentionedCount / validResults.length * 100;
29054
+ const topPositions = results.filter(
29055
+ (r) => r.mentioned && r.position !== null && r.position <= 3
29056
+ );
29057
+ if (topPositions.length > 0) {
29058
+ score = Math.min(100, score + 10);
29059
+ }
29060
+ const positiveResults = results.filter((r) => r.sentiment === "positive");
29061
+ if (positiveResults.length > mentionedCount / 2) {
29062
+ score = Math.min(100, score + 5);
29063
+ }
29064
+ return Math.round(score);
29065
+ }
29066
+ function getAIVisibilitySummary(results) {
29067
+ const score = calculateAIVisibilityScore(results);
29068
+ const mentionedIn = results.filter((r) => r.mentioned).map((r) => r.providerName);
29069
+ const notMentionedIn = results.filter((r) => !r.mentioned && !r.error).map((r) => r.providerName);
29070
+ const positions = results.filter((r) => r.position !== null).map((r) => r.position);
29071
+ const bestPosition = positions.length > 0 ? Math.min(...positions) : null;
29072
+ const sentiments = results.filter((r) => r.sentiment !== null).map((r) => r.sentiment);
29073
+ let overallSentiment = null;
29074
+ if (sentiments.length > 0) {
29075
+ const positiveCount = sentiments.filter((s) => s === "positive").length;
29076
+ const negativeCount = sentiments.filter((s) => s === "negative").length;
29077
+ if (positiveCount > 0 && negativeCount > 0) {
29078
+ overallSentiment = "mixed";
29079
+ } else if (positiveCount > negativeCount) {
29080
+ overallSentiment = "positive";
29081
+ } else if (negativeCount > positiveCount) {
29082
+ overallSentiment = "negative";
29083
+ } else {
29084
+ overallSentiment = "neutral";
29085
+ }
29086
+ }
29087
+ return {
29088
+ score,
29089
+ mentionedIn,
29090
+ notMentionedIn,
29091
+ bestPosition,
29092
+ overallSentiment
29093
+ };
29094
+ }
29095
+
28728
29096
  // src/frameworks/index.ts
28729
29097
  var frameworks_exports = {};
28730
29098
  __export(frameworks_exports, {
@@ -29481,6 +29849,7 @@ if (typeof globalThis !== "undefined") {
29481
29849
  applyFixes,
29482
29850
  buildGSCApiRequest,
29483
29851
  buildGSCRequest,
29852
+ calculateAIVisibilityScore,
29484
29853
  calculateBM25,
29485
29854
  calculateKeywordTFIDF,
29486
29855
  calculateNextRun,
@@ -29495,6 +29864,7 @@ if (typeof globalThis !== "undefined") {
29495
29864
  checkGitHubCLI,
29496
29865
  checkInternalRedirects,
29497
29866
  checkJSRenderingRatio,
29867
+ checkLLMCitations,
29498
29868
  checkLlmsTxt,
29499
29869
  checkMobileResources,
29500
29870
  checkPlaintextEmails,
@@ -29598,6 +29968,7 @@ if (typeof globalThis !== "undefined") {
29598
29968
  generatePDFReport,
29599
29969
  generatePRDescription,
29600
29970
  generateReactHelmetSocialMeta,
29971
+ generateRecommendationQueries,
29601
29972
  generateRemixMeta,
29602
29973
  generateSecretsDoc,
29603
29974
  generateSocialMetaFix,
@@ -29605,6 +29976,7 @@ if (typeof globalThis !== "undefined") {
29605
29976
  generateUncertaintyQuestions,
29606
29977
  generateWizardQuestions,
29607
29978
  generateWorkflow,
29979
+ getAIVisibilitySummary,
29608
29980
  getAutocompleteSuggestions,
29609
29981
  getDateRange,
29610
29982
  getExpandedSuggestions,