@rankcli/agent-runtime 0.0.1

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.
Files changed (178) hide show
  1. package/README.md +242 -0
  2. package/dist/analyzer-2CSWIQGD.mjs +6 -0
  3. package/dist/chunk-YNZYHEYM.mjs +774 -0
  4. package/dist/index.d.mts +4012 -0
  5. package/dist/index.d.ts +4012 -0
  6. package/dist/index.js +29672 -0
  7. package/dist/index.mjs +28602 -0
  8. package/package.json +53 -0
  9. package/scripts/build-deno.ts +134 -0
  10. package/src/audit/ai/analyzer.ts +347 -0
  11. package/src/audit/ai/index.ts +29 -0
  12. package/src/audit/ai/prompts/content-analysis.ts +271 -0
  13. package/src/audit/ai/types.ts +179 -0
  14. package/src/audit/checks/additional-checks.ts +439 -0
  15. package/src/audit/checks/ai-citation-worthiness.ts +399 -0
  16. package/src/audit/checks/ai-content-structure.ts +325 -0
  17. package/src/audit/checks/ai-readiness.ts +339 -0
  18. package/src/audit/checks/anchor-text.ts +179 -0
  19. package/src/audit/checks/answer-conciseness.ts +322 -0
  20. package/src/audit/checks/asset-minification.ts +270 -0
  21. package/src/audit/checks/bing-optimization.ts +206 -0
  22. package/src/audit/checks/brand-mention-optimization.ts +349 -0
  23. package/src/audit/checks/caching-headers.ts +305 -0
  24. package/src/audit/checks/canonical-advanced.ts +150 -0
  25. package/src/audit/checks/canonical-domain.ts +196 -0
  26. package/src/audit/checks/citation-quality.ts +358 -0
  27. package/src/audit/checks/client-rendering.ts +542 -0
  28. package/src/audit/checks/color-contrast.ts +342 -0
  29. package/src/audit/checks/content-freshness.ts +170 -0
  30. package/src/audit/checks/content-science.ts +589 -0
  31. package/src/audit/checks/conversion-elements.ts +526 -0
  32. package/src/audit/checks/crawlability.ts +220 -0
  33. package/src/audit/checks/directory-listing.ts +172 -0
  34. package/src/audit/checks/dom-analysis.ts +191 -0
  35. package/src/audit/checks/dom-size.ts +246 -0
  36. package/src/audit/checks/duplicate-content.ts +194 -0
  37. package/src/audit/checks/eeat-signals.ts +990 -0
  38. package/src/audit/checks/entity-seo.ts +396 -0
  39. package/src/audit/checks/featured-snippet.ts +473 -0
  40. package/src/audit/checks/freshness-signals.ts +443 -0
  41. package/src/audit/checks/funnel-intent.ts +463 -0
  42. package/src/audit/checks/hreflang.ts +174 -0
  43. package/src/audit/checks/html-compliance.ts +302 -0
  44. package/src/audit/checks/image-dimensions.ts +167 -0
  45. package/src/audit/checks/images.ts +160 -0
  46. package/src/audit/checks/indexnow.ts +275 -0
  47. package/src/audit/checks/interactive-tools.ts +475 -0
  48. package/src/audit/checks/internal-link-graph.ts +436 -0
  49. package/src/audit/checks/keyword-analysis.ts +239 -0
  50. package/src/audit/checks/keyword-cannibalization.ts +385 -0
  51. package/src/audit/checks/keyword-placement.ts +471 -0
  52. package/src/audit/checks/links.ts +203 -0
  53. package/src/audit/checks/llms-txt.ts +224 -0
  54. package/src/audit/checks/local-seo.ts +296 -0
  55. package/src/audit/checks/mobile.ts +167 -0
  56. package/src/audit/checks/modern-images.ts +226 -0
  57. package/src/audit/checks/navboost-signals.ts +395 -0
  58. package/src/audit/checks/on-page.ts +209 -0
  59. package/src/audit/checks/page-resources.ts +285 -0
  60. package/src/audit/checks/pagination.ts +180 -0
  61. package/src/audit/checks/performance.ts +153 -0
  62. package/src/audit/checks/platform-presence.ts +580 -0
  63. package/src/audit/checks/redirect-analysis.ts +153 -0
  64. package/src/audit/checks/redirect-chain.ts +389 -0
  65. package/src/audit/checks/resource-hints.ts +420 -0
  66. package/src/audit/checks/responsive-css.ts +247 -0
  67. package/src/audit/checks/responsive-images.ts +396 -0
  68. package/src/audit/checks/review-ecosystem.ts +415 -0
  69. package/src/audit/checks/robots-validation.ts +373 -0
  70. package/src/audit/checks/security-headers.ts +172 -0
  71. package/src/audit/checks/security.ts +144 -0
  72. package/src/audit/checks/serp-preview.ts +251 -0
  73. package/src/audit/checks/site-maturity.ts +444 -0
  74. package/src/audit/checks/social-meta.test.ts +275 -0
  75. package/src/audit/checks/social-meta.ts +134 -0
  76. package/src/audit/checks/soft-404.ts +151 -0
  77. package/src/audit/checks/structured-data.ts +238 -0
  78. package/src/audit/checks/tech-detection.ts +496 -0
  79. package/src/audit/checks/topical-clusters.ts +435 -0
  80. package/src/audit/checks/tracker-bloat.ts +462 -0
  81. package/src/audit/checks/tracking-verification.test.ts +371 -0
  82. package/src/audit/checks/tracking-verification.ts +636 -0
  83. package/src/audit/checks/url-safety.ts +682 -0
  84. package/src/audit/deno-entry.ts +66 -0
  85. package/src/audit/discovery/index.ts +15 -0
  86. package/src/audit/discovery/link-crawler.ts +232 -0
  87. package/src/audit/discovery/repo-routes.ts +347 -0
  88. package/src/audit/engine.ts +620 -0
  89. package/src/audit/fixes/index.ts +209 -0
  90. package/src/audit/fixes/social-meta-fixes.test.ts +329 -0
  91. package/src/audit/fixes/social-meta-fixes.ts +463 -0
  92. package/src/audit/index.ts +74 -0
  93. package/src/audit/runner.test.ts +299 -0
  94. package/src/audit/runner.ts +130 -0
  95. package/src/audit/types.ts +1953 -0
  96. package/src/content/featured-snippet.ts +367 -0
  97. package/src/content/generator.test.ts +534 -0
  98. package/src/content/generator.ts +501 -0
  99. package/src/content/headline.ts +317 -0
  100. package/src/content/index.ts +62 -0
  101. package/src/content/intent.ts +258 -0
  102. package/src/content/keyword-density.ts +349 -0
  103. package/src/content/readability.ts +262 -0
  104. package/src/executor.ts +336 -0
  105. package/src/fixer.ts +416 -0
  106. package/src/frameworks/detector.test.ts +248 -0
  107. package/src/frameworks/detector.ts +371 -0
  108. package/src/frameworks/index.ts +68 -0
  109. package/src/frameworks/recipes/angular.yaml +171 -0
  110. package/src/frameworks/recipes/astro.yaml +206 -0
  111. package/src/frameworks/recipes/django.yaml +180 -0
  112. package/src/frameworks/recipes/laravel.yaml +137 -0
  113. package/src/frameworks/recipes/nextjs.yaml +268 -0
  114. package/src/frameworks/recipes/nuxt.yaml +175 -0
  115. package/src/frameworks/recipes/rails.yaml +188 -0
  116. package/src/frameworks/recipes/react.yaml +202 -0
  117. package/src/frameworks/recipes/sveltekit.yaml +154 -0
  118. package/src/frameworks/recipes/vue.yaml +137 -0
  119. package/src/frameworks/recipes/wordpress.yaml +209 -0
  120. package/src/frameworks/suggestion-engine.ts +320 -0
  121. package/src/geo/geo-content.test.ts +305 -0
  122. package/src/geo/geo-content.ts +266 -0
  123. package/src/geo/geo-history.test.ts +473 -0
  124. package/src/geo/geo-history.ts +433 -0
  125. package/src/geo/geo-tracker.test.ts +359 -0
  126. package/src/geo/geo-tracker.ts +411 -0
  127. package/src/geo/index.ts +10 -0
  128. package/src/git/commit-helper.test.ts +261 -0
  129. package/src/git/commit-helper.ts +329 -0
  130. package/src/git/index.ts +12 -0
  131. package/src/git/pr-helper.test.ts +284 -0
  132. package/src/git/pr-helper.ts +307 -0
  133. package/src/index.ts +66 -0
  134. package/src/keywords/ai-keyword-engine.ts +1062 -0
  135. package/src/keywords/ai-summarizer.ts +387 -0
  136. package/src/keywords/ci-mode.ts +555 -0
  137. package/src/keywords/engine.ts +359 -0
  138. package/src/keywords/index.ts +151 -0
  139. package/src/keywords/llm-judge.ts +357 -0
  140. package/src/keywords/nlp-analysis.ts +706 -0
  141. package/src/keywords/prioritizer.ts +295 -0
  142. package/src/keywords/site-crawler.ts +342 -0
  143. package/src/keywords/sources/autocomplete.ts +139 -0
  144. package/src/keywords/sources/competitive-search.ts +450 -0
  145. package/src/keywords/sources/competitor-analysis.ts +374 -0
  146. package/src/keywords/sources/dataforseo.ts +206 -0
  147. package/src/keywords/sources/free-sources.ts +294 -0
  148. package/src/keywords/sources/gsc.ts +123 -0
  149. package/src/keywords/topic-grouping.ts +327 -0
  150. package/src/keywords/types.ts +144 -0
  151. package/src/keywords/wizard.ts +457 -0
  152. package/src/loader.ts +40 -0
  153. package/src/reports/index.ts +7 -0
  154. package/src/reports/report-generator.test.ts +293 -0
  155. package/src/reports/report-generator.ts +713 -0
  156. package/src/scheduler/alerts.test.ts +458 -0
  157. package/src/scheduler/alerts.ts +328 -0
  158. package/src/scheduler/index.ts +8 -0
  159. package/src/scheduler/scheduled-audit.test.ts +377 -0
  160. package/src/scheduler/scheduled-audit.ts +149 -0
  161. package/src/test/integration-test.ts +325 -0
  162. package/src/tools/analyzer.ts +373 -0
  163. package/src/tools/crawl.ts +293 -0
  164. package/src/tools/files.ts +301 -0
  165. package/src/tools/h1-fixer.ts +249 -0
  166. package/src/tools/index.ts +67 -0
  167. package/src/tracking/github-action.ts +326 -0
  168. package/src/tracking/google-analytics.ts +265 -0
  169. package/src/tracking/index.ts +45 -0
  170. package/src/tracking/report-generator.ts +386 -0
  171. package/src/tracking/search-console.ts +335 -0
  172. package/src/types.ts +134 -0
  173. package/src/utils/http.ts +302 -0
  174. package/src/wasm-adapter.ts +297 -0
  175. package/src/wasm-entry.ts +14 -0
  176. package/tsconfig.json +17 -0
  177. package/tsup.wasm.config.ts +26 -0
  178. package/vitest.config.ts +15 -0
@@ -0,0 +1,266 @@
1
+ /**
2
+ * GEO Content Module
3
+ *
4
+ * Generate AI-citation-friendly content with structured data,
5
+ * comparison tables, FAQs, and key facts formatted for LLM parsing.
6
+ */
7
+
8
+ export interface KeyFact {
9
+ label: string;
10
+ value: string | number;
11
+ }
12
+
13
+ export interface FAQItem {
14
+ question: string;
15
+ answer: string;
16
+ }
17
+
18
+ export interface ComparisonRow {
19
+ feature: string;
20
+ brand: string | boolean;
21
+ competitor?: string | boolean;
22
+ competitors?: Record<string, string | boolean>;
23
+ }
24
+
25
+ export interface ComparisonConfig {
26
+ brandName: string;
27
+ competitorName?: string;
28
+ competitorNames?: string[];
29
+ useCheckmarks?: boolean;
30
+ }
31
+
32
+ export interface AIContentConfig {
33
+ productName: string;
34
+ tagline?: string;
35
+ description?: string;
36
+ keyFacts?: KeyFact[];
37
+ faqs?: FAQItem[];
38
+ comparison?: {
39
+ competitorName: string;
40
+ rows: ComparisonRow[];
41
+ };
42
+ }
43
+
44
+ export interface KeyFactsOptions {
45
+ format?: 'bullets' | 'paragraph' | 'inline';
46
+ }
47
+
48
+ export interface FAQSchemaOptions {
49
+ format?: 'json-ld' | 'markdown';
50
+ }
51
+
52
+ export interface OptimizeOptions {
53
+ brandName?: string;
54
+ highlightNumbers?: boolean;
55
+ structureLists?: boolean;
56
+ emphasizeBrand?: boolean;
57
+ addSourcePlaceholder?: boolean;
58
+ }
59
+
60
+ /**
61
+ * Generate formatted key facts for AI citation
62
+ */
63
+ export function generateKeyFacts(
64
+ facts: KeyFact[],
65
+ options: KeyFactsOptions = {}
66
+ ): string {
67
+ const format = options.format || 'bullets';
68
+
69
+ const formatted = facts.map(fact => `**${fact.label}:** ${fact.value}`);
70
+
71
+ switch (format) {
72
+ case 'bullets':
73
+ return formatted.map(f => `- ${f}`).join('\n');
74
+ case 'paragraph':
75
+ return formatted.join('. ') + '.';
76
+ case 'inline':
77
+ return formatted.join(' | ');
78
+ default:
79
+ return formatted.join('\n');
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Generate FAQ schema (JSON-LD or Markdown)
85
+ */
86
+ export function generateFAQSchema(
87
+ faqs: FAQItem[],
88
+ options: FAQSchemaOptions = {}
89
+ ): string {
90
+ const format = options.format || 'json-ld';
91
+
92
+ if (format === 'markdown') {
93
+ const lines = ['## FAQ', ''];
94
+ for (const faq of faqs) {
95
+ lines.push(`### ${faq.question}`);
96
+ lines.push('');
97
+ lines.push(faq.answer);
98
+ lines.push('');
99
+ }
100
+ return lines.join('\n').trim();
101
+ }
102
+
103
+ // JSON-LD format
104
+ const schema = {
105
+ '@context': 'https://schema.org',
106
+ '@type': 'FAQPage',
107
+ mainEntity: faqs.map(faq => ({
108
+ '@type': 'Question',
109
+ name: faq.question,
110
+ acceptedAnswer: {
111
+ '@type': 'Answer',
112
+ text: faq.answer,
113
+ },
114
+ })),
115
+ };
116
+
117
+ return JSON.stringify(schema, null, 2);
118
+ }
119
+
120
+ /**
121
+ * Generate comparison table in markdown
122
+ */
123
+ export function generateComparisonTable(
124
+ rows: ComparisonRow[],
125
+ config: ComparisonConfig
126
+ ): string {
127
+ const { brandName, useCheckmarks } = config;
128
+
129
+ // Determine competitor columns
130
+ const competitorNames = config.competitorNames ||
131
+ (config.competitorName ? [config.competitorName] : []);
132
+
133
+ // Build header
134
+ const headers = ['Feature', brandName, ...competitorNames];
135
+ const headerRow = `| ${headers.join(' | ')} |`;
136
+ const separatorRow = `| ${headers.map(() => '---').join(' | ')} |`;
137
+
138
+ // Build rows
139
+ const dataRows = rows.map(row => {
140
+ const brandValue = formatCellValue(row.brand, useCheckmarks);
141
+
142
+ let competitorValues: string[];
143
+ if (row.competitors) {
144
+ competitorValues = competitorNames.map(name =>
145
+ formatCellValue(row.competitors?.[name] ?? '-', useCheckmarks)
146
+ );
147
+ } else {
148
+ competitorValues = [formatCellValue(row.competitor ?? '-', useCheckmarks)];
149
+ }
150
+
151
+ return `| ${row.feature} | ${brandValue} | ${competitorValues.join(' | ')} |`;
152
+ });
153
+
154
+ return [headerRow, separatorRow, ...dataRows].join('\n');
155
+ }
156
+
157
+ /**
158
+ * Format cell value for comparison table
159
+ */
160
+ function formatCellValue(value: string | boolean | undefined, useCheckmarks?: boolean): string {
161
+ if (typeof value === 'boolean') {
162
+ if (useCheckmarks) {
163
+ return value ? '✓' : '✗';
164
+ }
165
+ return value ? 'Yes' : 'No';
166
+ }
167
+ return String(value ?? '-');
168
+ }
169
+
170
+ /**
171
+ * Generate complete AI-citable content block
172
+ */
173
+ export function generateAICitableContent(config: AIContentConfig): string {
174
+ const sections: string[] = [];
175
+
176
+ // Header with product name
177
+ sections.push(`# ${config.productName}`);
178
+ sections.push('');
179
+
180
+ // Tagline
181
+ if (config.tagline) {
182
+ sections.push(`**${config.tagline}**`);
183
+ sections.push('');
184
+ }
185
+
186
+ // Description
187
+ if (config.description) {
188
+ sections.push(config.description);
189
+ sections.push('');
190
+ }
191
+
192
+ // Key Facts
193
+ if (config.keyFacts && config.keyFacts.length > 0) {
194
+ sections.push('## Key Facts');
195
+ sections.push('');
196
+ sections.push(generateKeyFacts(config.keyFacts, { format: 'bullets' }));
197
+ sections.push('');
198
+ }
199
+
200
+ // Comparison Table
201
+ if (config.comparison) {
202
+ sections.push(`## ${config.productName} vs ${config.comparison.competitorName}`);
203
+ sections.push('');
204
+ sections.push(generateComparisonTable(config.comparison.rows, {
205
+ brandName: config.productName,
206
+ competitorName: config.comparison.competitorName,
207
+ }));
208
+ sections.push('');
209
+ }
210
+
211
+ // FAQ Section
212
+ if (config.faqs && config.faqs.length > 0) {
213
+ sections.push(generateFAQSchema(config.faqs, { format: 'markdown' }));
214
+ sections.push('');
215
+ }
216
+
217
+ return sections.join('\n').trim();
218
+ }
219
+
220
+ /**
221
+ * Optimize existing content for AI citation
222
+ */
223
+ export function optimizeForAI(
224
+ content: string,
225
+ options: OptimizeOptions = {}
226
+ ): string {
227
+ let optimized = content;
228
+
229
+ // Highlight numbers
230
+ if (options.highlightNumbers) {
231
+ // Match numbers not already in bold/code and not part of dates
232
+ optimized = optimized.replace(
233
+ /(?<!\*\*)(?<![`\d])\b(\d+(?:,\d{3})*(?:\.\d+)?)\b(?!\*\*)(?![`\d])/g,
234
+ '**$1**'
235
+ );
236
+ }
237
+
238
+ // Structure comma-separated lists
239
+ if (options.structureLists) {
240
+ // Match patterns like "includes: x, y, and z"
241
+ optimized = optimized.replace(
242
+ /:\s*([^.]+),\s*([^.]+),\s*and\s+([^.]+)\./gi,
243
+ ':\n- $1\n- $2\n- $3'
244
+ );
245
+ }
246
+
247
+ // Emphasize brand name
248
+ if (options.brandName && options.emphasizeBrand) {
249
+ const brandRegex = new RegExp(`(?<!\\*\\*)\\b(${escapeRegex(options.brandName)})\\b(?!\\*\\*)`, 'g');
250
+ optimized = optimized.replace(brandRegex, '**$1**');
251
+ }
252
+
253
+ // Add source placeholder
254
+ if (options.addSourcePlaceholder) {
255
+ optimized = optimized.trim() + '\n\n*Source: [Your Website URL]*';
256
+ }
257
+
258
+ return optimized;
259
+ }
260
+
261
+ /**
262
+ * Escape special regex characters
263
+ */
264
+ function escapeRegex(str: string): string {
265
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
266
+ }