@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.
- package/README.md +242 -0
- package/dist/analyzer-2CSWIQGD.mjs +6 -0
- package/dist/chunk-YNZYHEYM.mjs +774 -0
- package/dist/index.d.mts +4012 -0
- package/dist/index.d.ts +4012 -0
- package/dist/index.js +29672 -0
- package/dist/index.mjs +28602 -0
- package/package.json +53 -0
- package/scripts/build-deno.ts +134 -0
- package/src/audit/ai/analyzer.ts +347 -0
- package/src/audit/ai/index.ts +29 -0
- package/src/audit/ai/prompts/content-analysis.ts +271 -0
- package/src/audit/ai/types.ts +179 -0
- package/src/audit/checks/additional-checks.ts +439 -0
- package/src/audit/checks/ai-citation-worthiness.ts +399 -0
- package/src/audit/checks/ai-content-structure.ts +325 -0
- package/src/audit/checks/ai-readiness.ts +339 -0
- package/src/audit/checks/anchor-text.ts +179 -0
- package/src/audit/checks/answer-conciseness.ts +322 -0
- package/src/audit/checks/asset-minification.ts +270 -0
- package/src/audit/checks/bing-optimization.ts +206 -0
- package/src/audit/checks/brand-mention-optimization.ts +349 -0
- package/src/audit/checks/caching-headers.ts +305 -0
- package/src/audit/checks/canonical-advanced.ts +150 -0
- package/src/audit/checks/canonical-domain.ts +196 -0
- package/src/audit/checks/citation-quality.ts +358 -0
- package/src/audit/checks/client-rendering.ts +542 -0
- package/src/audit/checks/color-contrast.ts +342 -0
- package/src/audit/checks/content-freshness.ts +170 -0
- package/src/audit/checks/content-science.ts +589 -0
- package/src/audit/checks/conversion-elements.ts +526 -0
- package/src/audit/checks/crawlability.ts +220 -0
- package/src/audit/checks/directory-listing.ts +172 -0
- package/src/audit/checks/dom-analysis.ts +191 -0
- package/src/audit/checks/dom-size.ts +246 -0
- package/src/audit/checks/duplicate-content.ts +194 -0
- package/src/audit/checks/eeat-signals.ts +990 -0
- package/src/audit/checks/entity-seo.ts +396 -0
- package/src/audit/checks/featured-snippet.ts +473 -0
- package/src/audit/checks/freshness-signals.ts +443 -0
- package/src/audit/checks/funnel-intent.ts +463 -0
- package/src/audit/checks/hreflang.ts +174 -0
- package/src/audit/checks/html-compliance.ts +302 -0
- package/src/audit/checks/image-dimensions.ts +167 -0
- package/src/audit/checks/images.ts +160 -0
- package/src/audit/checks/indexnow.ts +275 -0
- package/src/audit/checks/interactive-tools.ts +475 -0
- package/src/audit/checks/internal-link-graph.ts +436 -0
- package/src/audit/checks/keyword-analysis.ts +239 -0
- package/src/audit/checks/keyword-cannibalization.ts +385 -0
- package/src/audit/checks/keyword-placement.ts +471 -0
- package/src/audit/checks/links.ts +203 -0
- package/src/audit/checks/llms-txt.ts +224 -0
- package/src/audit/checks/local-seo.ts +296 -0
- package/src/audit/checks/mobile.ts +167 -0
- package/src/audit/checks/modern-images.ts +226 -0
- package/src/audit/checks/navboost-signals.ts +395 -0
- package/src/audit/checks/on-page.ts +209 -0
- package/src/audit/checks/page-resources.ts +285 -0
- package/src/audit/checks/pagination.ts +180 -0
- package/src/audit/checks/performance.ts +153 -0
- package/src/audit/checks/platform-presence.ts +580 -0
- package/src/audit/checks/redirect-analysis.ts +153 -0
- package/src/audit/checks/redirect-chain.ts +389 -0
- package/src/audit/checks/resource-hints.ts +420 -0
- package/src/audit/checks/responsive-css.ts +247 -0
- package/src/audit/checks/responsive-images.ts +396 -0
- package/src/audit/checks/review-ecosystem.ts +415 -0
- package/src/audit/checks/robots-validation.ts +373 -0
- package/src/audit/checks/security-headers.ts +172 -0
- package/src/audit/checks/security.ts +144 -0
- package/src/audit/checks/serp-preview.ts +251 -0
- package/src/audit/checks/site-maturity.ts +444 -0
- package/src/audit/checks/social-meta.test.ts +275 -0
- package/src/audit/checks/social-meta.ts +134 -0
- package/src/audit/checks/soft-404.ts +151 -0
- package/src/audit/checks/structured-data.ts +238 -0
- package/src/audit/checks/tech-detection.ts +496 -0
- package/src/audit/checks/topical-clusters.ts +435 -0
- package/src/audit/checks/tracker-bloat.ts +462 -0
- package/src/audit/checks/tracking-verification.test.ts +371 -0
- package/src/audit/checks/tracking-verification.ts +636 -0
- package/src/audit/checks/url-safety.ts +682 -0
- package/src/audit/deno-entry.ts +66 -0
- package/src/audit/discovery/index.ts +15 -0
- package/src/audit/discovery/link-crawler.ts +232 -0
- package/src/audit/discovery/repo-routes.ts +347 -0
- package/src/audit/engine.ts +620 -0
- package/src/audit/fixes/index.ts +209 -0
- package/src/audit/fixes/social-meta-fixes.test.ts +329 -0
- package/src/audit/fixes/social-meta-fixes.ts +463 -0
- package/src/audit/index.ts +74 -0
- package/src/audit/runner.test.ts +299 -0
- package/src/audit/runner.ts +130 -0
- package/src/audit/types.ts +1953 -0
- package/src/content/featured-snippet.ts +367 -0
- package/src/content/generator.test.ts +534 -0
- package/src/content/generator.ts +501 -0
- package/src/content/headline.ts +317 -0
- package/src/content/index.ts +62 -0
- package/src/content/intent.ts +258 -0
- package/src/content/keyword-density.ts +349 -0
- package/src/content/readability.ts +262 -0
- package/src/executor.ts +336 -0
- package/src/fixer.ts +416 -0
- package/src/frameworks/detector.test.ts +248 -0
- package/src/frameworks/detector.ts +371 -0
- package/src/frameworks/index.ts +68 -0
- package/src/frameworks/recipes/angular.yaml +171 -0
- package/src/frameworks/recipes/astro.yaml +206 -0
- package/src/frameworks/recipes/django.yaml +180 -0
- package/src/frameworks/recipes/laravel.yaml +137 -0
- package/src/frameworks/recipes/nextjs.yaml +268 -0
- package/src/frameworks/recipes/nuxt.yaml +175 -0
- package/src/frameworks/recipes/rails.yaml +188 -0
- package/src/frameworks/recipes/react.yaml +202 -0
- package/src/frameworks/recipes/sveltekit.yaml +154 -0
- package/src/frameworks/recipes/vue.yaml +137 -0
- package/src/frameworks/recipes/wordpress.yaml +209 -0
- package/src/frameworks/suggestion-engine.ts +320 -0
- package/src/geo/geo-content.test.ts +305 -0
- package/src/geo/geo-content.ts +266 -0
- package/src/geo/geo-history.test.ts +473 -0
- package/src/geo/geo-history.ts +433 -0
- package/src/geo/geo-tracker.test.ts +359 -0
- package/src/geo/geo-tracker.ts +411 -0
- package/src/geo/index.ts +10 -0
- package/src/git/commit-helper.test.ts +261 -0
- package/src/git/commit-helper.ts +329 -0
- package/src/git/index.ts +12 -0
- package/src/git/pr-helper.test.ts +284 -0
- package/src/git/pr-helper.ts +307 -0
- package/src/index.ts +66 -0
- package/src/keywords/ai-keyword-engine.ts +1062 -0
- package/src/keywords/ai-summarizer.ts +387 -0
- package/src/keywords/ci-mode.ts +555 -0
- package/src/keywords/engine.ts +359 -0
- package/src/keywords/index.ts +151 -0
- package/src/keywords/llm-judge.ts +357 -0
- package/src/keywords/nlp-analysis.ts +706 -0
- package/src/keywords/prioritizer.ts +295 -0
- package/src/keywords/site-crawler.ts +342 -0
- package/src/keywords/sources/autocomplete.ts +139 -0
- package/src/keywords/sources/competitive-search.ts +450 -0
- package/src/keywords/sources/competitor-analysis.ts +374 -0
- package/src/keywords/sources/dataforseo.ts +206 -0
- package/src/keywords/sources/free-sources.ts +294 -0
- package/src/keywords/sources/gsc.ts +123 -0
- package/src/keywords/topic-grouping.ts +327 -0
- package/src/keywords/types.ts +144 -0
- package/src/keywords/wizard.ts +457 -0
- package/src/loader.ts +40 -0
- package/src/reports/index.ts +7 -0
- package/src/reports/report-generator.test.ts +293 -0
- package/src/reports/report-generator.ts +713 -0
- package/src/scheduler/alerts.test.ts +458 -0
- package/src/scheduler/alerts.ts +328 -0
- package/src/scheduler/index.ts +8 -0
- package/src/scheduler/scheduled-audit.test.ts +377 -0
- package/src/scheduler/scheduled-audit.ts +149 -0
- package/src/test/integration-test.ts +325 -0
- package/src/tools/analyzer.ts +373 -0
- package/src/tools/crawl.ts +293 -0
- package/src/tools/files.ts +301 -0
- package/src/tools/h1-fixer.ts +249 -0
- package/src/tools/index.ts +67 -0
- package/src/tracking/github-action.ts +326 -0
- package/src/tracking/google-analytics.ts +265 -0
- package/src/tracking/index.ts +45 -0
- package/src/tracking/report-generator.ts +386 -0
- package/src/tracking/search-console.ts +335 -0
- package/src/types.ts +134 -0
- package/src/utils/http.ts +302 -0
- package/src/wasm-adapter.ts +297 -0
- package/src/wasm-entry.ts +14 -0
- package/tsconfig.json +17 -0
- package/tsup.wasm.config.ts +26 -0
- 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
|
+
}
|