recker 1.0.30 → 1.0.32-next.02f2bae
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/cli/index.js +2653 -197
- package/dist/cli/tui/shell-search.js +10 -8
- package/dist/cli/tui/shell.d.ts +29 -0
- package/dist/cli/tui/shell.js +1733 -9
- package/dist/mcp/search/hybrid-search.js +4 -2
- package/dist/seo/analyzer.d.ts +7 -0
- package/dist/seo/analyzer.js +200 -4
- package/dist/seo/rules/ai-search.d.ts +2 -0
- package/dist/seo/rules/ai-search.js +423 -0
- package/dist/seo/rules/canonical.d.ts +12 -0
- package/dist/seo/rules/canonical.js +249 -0
- package/dist/seo/rules/crawl.js +113 -0
- package/dist/seo/rules/cwv.js +0 -95
- package/dist/seo/rules/i18n.js +27 -0
- package/dist/seo/rules/images.js +23 -27
- package/dist/seo/rules/index.js +14 -0
- package/dist/seo/rules/internal-linking.js +6 -6
- package/dist/seo/rules/links.js +321 -0
- package/dist/seo/rules/meta.js +24 -0
- package/dist/seo/rules/mobile.js +0 -20
- package/dist/seo/rules/performance.js +124 -0
- package/dist/seo/rules/redirects.d.ts +16 -0
- package/dist/seo/rules/redirects.js +193 -0
- package/dist/seo/rules/resources.d.ts +2 -0
- package/dist/seo/rules/resources.js +373 -0
- package/dist/seo/rules/security.js +290 -0
- package/dist/seo/rules/technical-advanced.d.ts +10 -0
- package/dist/seo/rules/technical-advanced.js +283 -0
- package/dist/seo/rules/technical.js +74 -18
- package/dist/seo/rules/types.d.ts +103 -3
- package/dist/seo/seo-spider.d.ts +2 -0
- package/dist/seo/seo-spider.js +47 -2
- package/dist/seo/types.d.ts +48 -28
- package/dist/seo/utils/index.d.ts +1 -0
- package/dist/seo/utils/index.js +1 -0
- package/dist/seo/utils/similarity.d.ts +47 -0
- package/dist/seo/utils/similarity.js +273 -0
- package/dist/seo/validators/index.d.ts +3 -0
- package/dist/seo/validators/index.js +3 -0
- package/dist/seo/validators/llms-txt.d.ts +57 -0
- package/dist/seo/validators/llms-txt.js +317 -0
- package/dist/seo/validators/robots.d.ts +54 -0
- package/dist/seo/validators/robots.js +382 -0
- package/dist/seo/validators/sitemap.d.ts +69 -0
- package/dist/seo/validators/sitemap.js +424 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Fuse from 'fuse.js';
|
|
2
|
-
import { cosineSimilarity,
|
|
2
|
+
import { cosineSimilarity, levenshtein } from './math.js';
|
|
3
3
|
import { loadEmbeddings } from '../embeddings-loader.js';
|
|
4
4
|
import { StateError } from '../../core/errors.js';
|
|
5
5
|
let cachedEmbeddings = null;
|
|
@@ -99,7 +99,9 @@ export class HybridSearch {
|
|
|
99
99
|
for (const result of semanticResults) {
|
|
100
100
|
const existing = results.get(result.id);
|
|
101
101
|
if (existing) {
|
|
102
|
-
|
|
102
|
+
const maxScore = Math.max(existing.score, result.score);
|
|
103
|
+
const bonus = Math.min(existing.score, result.score) * 0.3;
|
|
104
|
+
existing.score = Math.min(1.0, maxScore + bonus);
|
|
103
105
|
existing.source = 'hybrid';
|
|
104
106
|
}
|
|
105
107
|
else {
|
package/dist/seo/analyzer.d.ts
CHANGED
|
@@ -26,6 +26,13 @@ export declare class SeoAnalyzer {
|
|
|
26
26
|
private analyzeTrustSignals;
|
|
27
27
|
private calculateTextHtmlRatio;
|
|
28
28
|
private convertToCheckResults;
|
|
29
|
+
private buildSummary;
|
|
30
|
+
private calculateMetaCompleteness;
|
|
31
|
+
private calculateSocialCompleteness;
|
|
32
|
+
private calculateTechnicalCompleteness;
|
|
33
|
+
private calculateContentCompleteness;
|
|
34
|
+
private calculateImageCompleteness;
|
|
35
|
+
private calculateLinkCompleteness;
|
|
29
36
|
private analyzeHeadings;
|
|
30
37
|
private analyzeContent;
|
|
31
38
|
private buildLinkAnalysis;
|
package/dist/seo/analyzer.js
CHANGED
|
@@ -49,11 +49,21 @@ export class SeoAnalyzer {
|
|
|
49
49
|
const ruleResults = this.rulesEngine.evaluate(context);
|
|
50
50
|
const checks = this.convertToCheckResults(ruleResults);
|
|
51
51
|
const { score, grade } = this.calculateScore(checks);
|
|
52
|
+
const summary = this.buildSummary(ruleResults, checks, {
|
|
53
|
+
content,
|
|
54
|
+
imageAnalysis,
|
|
55
|
+
linkAnalysis,
|
|
56
|
+
meta,
|
|
57
|
+
og,
|
|
58
|
+
twitter,
|
|
59
|
+
technical,
|
|
60
|
+
});
|
|
52
61
|
return {
|
|
53
62
|
url,
|
|
54
63
|
timestamp: new Date(),
|
|
55
64
|
grade,
|
|
56
65
|
score,
|
|
66
|
+
summary,
|
|
57
67
|
checks,
|
|
58
68
|
title: meta.title ? { text: meta.title, length: meta.title.length } : undefined,
|
|
59
69
|
metaDescription: meta.description ? { text: meta.description, length: meta.description.length } : undefined,
|
|
@@ -72,16 +82,17 @@ export class SeoAnalyzer {
|
|
|
72
82
|
image: Array.isArray(twitter.image) ? twitter.image[0] : twitter.image,
|
|
73
83
|
site: twitter.site,
|
|
74
84
|
} : undefined,
|
|
85
|
+
structuredData: {
|
|
86
|
+
count: jsonLd.length,
|
|
87
|
+
types: jsonLd.map((j) => j['@type']).filter(Boolean),
|
|
88
|
+
items: jsonLd,
|
|
89
|
+
},
|
|
75
90
|
headings: headings,
|
|
76
91
|
content,
|
|
77
92
|
links: linkAnalysis,
|
|
78
93
|
images: imageAnalysis,
|
|
79
94
|
social,
|
|
80
95
|
technical,
|
|
81
|
-
jsonLd: {
|
|
82
|
-
count: jsonLd.length,
|
|
83
|
-
types: jsonLd.map((j) => j['@type']).filter(Boolean),
|
|
84
|
-
},
|
|
85
96
|
};
|
|
86
97
|
}
|
|
87
98
|
buildRuleContext(data) {
|
|
@@ -503,6 +514,191 @@ export class SeoAnalyzer {
|
|
|
503
514
|
evidence: r.evidence,
|
|
504
515
|
}));
|
|
505
516
|
}
|
|
517
|
+
buildSummary(ruleResults, checks, data) {
|
|
518
|
+
const passed = checks.filter(c => c.status === 'pass').length;
|
|
519
|
+
const warnings = checks.filter(c => c.status === 'warn').length;
|
|
520
|
+
const errors = checks.filter(c => c.status === 'fail').length;
|
|
521
|
+
const infos = checks.filter(c => c.status === 'info').length;
|
|
522
|
+
const totalChecks = checks.length;
|
|
523
|
+
const scoringChecks = totalChecks - infos;
|
|
524
|
+
const passRate = scoringChecks > 0 ? Math.round((passed / scoringChecks) * 100) : 100;
|
|
525
|
+
const issuesByCategory = {};
|
|
526
|
+
for (const result of ruleResults) {
|
|
527
|
+
const cat = result.category;
|
|
528
|
+
if (!issuesByCategory[cat]) {
|
|
529
|
+
issuesByCategory[cat] = { passed: 0, warnings: 0, errors: 0 };
|
|
530
|
+
}
|
|
531
|
+
if (result.status === 'pass')
|
|
532
|
+
issuesByCategory[cat].passed++;
|
|
533
|
+
else if (result.status === 'warn')
|
|
534
|
+
issuesByCategory[cat].warnings++;
|
|
535
|
+
else if (result.status === 'fail')
|
|
536
|
+
issuesByCategory[cat].errors++;
|
|
537
|
+
}
|
|
538
|
+
const topIssues = ruleResults
|
|
539
|
+
.filter(r => r.status === 'fail' || r.status === 'warn')
|
|
540
|
+
.sort((a, b) => {
|
|
541
|
+
if (a.status === 'fail' && b.status !== 'fail')
|
|
542
|
+
return -1;
|
|
543
|
+
if (a.status !== 'fail' && b.status === 'fail')
|
|
544
|
+
return 1;
|
|
545
|
+
return 0;
|
|
546
|
+
})
|
|
547
|
+
.slice(0, 5)
|
|
548
|
+
.map(r => ({
|
|
549
|
+
name: r.name,
|
|
550
|
+
message: r.message,
|
|
551
|
+
category: r.category,
|
|
552
|
+
severity: (r.status === 'fail' ? 'error' : 'warning'),
|
|
553
|
+
}));
|
|
554
|
+
const quickWins = [];
|
|
555
|
+
if (!data.meta.title)
|
|
556
|
+
quickWins.push('Add a page title');
|
|
557
|
+
if (!data.meta.description)
|
|
558
|
+
quickWins.push('Add a meta description');
|
|
559
|
+
if (!data.og.title && !data.og.description)
|
|
560
|
+
quickWins.push('Add OpenGraph meta tags for social sharing');
|
|
561
|
+
if (!data.twitter.card)
|
|
562
|
+
quickWins.push('Add Twitter Card meta tags');
|
|
563
|
+
if (!data.technical.hasCanonical)
|
|
564
|
+
quickWins.push('Add a canonical URL');
|
|
565
|
+
if (!data.technical.hasLang)
|
|
566
|
+
quickWins.push('Add lang attribute to <html>');
|
|
567
|
+
if (data.imageAnalysis.withoutAlt > 0)
|
|
568
|
+
quickWins.push(`Add alt text to ${data.imageAnalysis.withoutAlt} image(s)`);
|
|
569
|
+
if (data.linkAnalysis.withoutText > 0)
|
|
570
|
+
quickWins.push(`Add text to ${data.linkAnalysis.withoutText} empty link(s)`);
|
|
571
|
+
const limitedQuickWins = quickWins.slice(0, 5);
|
|
572
|
+
const htmlSize = this.$('html').html()?.length;
|
|
573
|
+
const domElements = this.$('*').length;
|
|
574
|
+
const vitals = {
|
|
575
|
+
htmlSize,
|
|
576
|
+
domElements,
|
|
577
|
+
ttfb: this.options.responseHeaders ? undefined : undefined,
|
|
578
|
+
totalTime: undefined,
|
|
579
|
+
wordCount: data.content.wordCount,
|
|
580
|
+
readingTime: data.content.readingTimeMinutes,
|
|
581
|
+
imageCount: data.imageAnalysis.total,
|
|
582
|
+
linkCount: data.linkAnalysis.total,
|
|
583
|
+
};
|
|
584
|
+
const completeness = {
|
|
585
|
+
meta: this.calculateMetaCompleteness(data.meta),
|
|
586
|
+
social: this.calculateSocialCompleteness(data.og, data.twitter),
|
|
587
|
+
technical: this.calculateTechnicalCompleteness(data.technical),
|
|
588
|
+
content: this.calculateContentCompleteness(data.content),
|
|
589
|
+
images: this.calculateImageCompleteness(data.imageAnalysis),
|
|
590
|
+
links: this.calculateLinkCompleteness(data.linkAnalysis),
|
|
591
|
+
};
|
|
592
|
+
return {
|
|
593
|
+
totalChecks,
|
|
594
|
+
passed,
|
|
595
|
+
warnings,
|
|
596
|
+
errors,
|
|
597
|
+
infos,
|
|
598
|
+
passRate,
|
|
599
|
+
issuesByCategory,
|
|
600
|
+
topIssues,
|
|
601
|
+
quickWins: limitedQuickWins,
|
|
602
|
+
vitals,
|
|
603
|
+
completeness,
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
calculateMetaCompleteness(meta) {
|
|
607
|
+
let score = 0;
|
|
608
|
+
const total = 5;
|
|
609
|
+
if (meta.title)
|
|
610
|
+
score++;
|
|
611
|
+
if (meta.description)
|
|
612
|
+
score++;
|
|
613
|
+
if (meta.canonical)
|
|
614
|
+
score++;
|
|
615
|
+
if (meta.viewport)
|
|
616
|
+
score++;
|
|
617
|
+
if (meta.charset)
|
|
618
|
+
score++;
|
|
619
|
+
return Math.round((score / total) * 100);
|
|
620
|
+
}
|
|
621
|
+
calculateSocialCompleteness(og, twitter) {
|
|
622
|
+
let score = 0;
|
|
623
|
+
const total = 8;
|
|
624
|
+
if (og.title)
|
|
625
|
+
score++;
|
|
626
|
+
if (og.description)
|
|
627
|
+
score++;
|
|
628
|
+
if (og.image)
|
|
629
|
+
score++;
|
|
630
|
+
if (og.url)
|
|
631
|
+
score++;
|
|
632
|
+
if (twitter.card)
|
|
633
|
+
score++;
|
|
634
|
+
if (twitter.title)
|
|
635
|
+
score++;
|
|
636
|
+
if (twitter.description)
|
|
637
|
+
score++;
|
|
638
|
+
if (twitter.image)
|
|
639
|
+
score++;
|
|
640
|
+
return Math.round((score / total) * 100);
|
|
641
|
+
}
|
|
642
|
+
calculateTechnicalCompleteness(technical) {
|
|
643
|
+
let score = 0;
|
|
644
|
+
const total = 5;
|
|
645
|
+
if (technical.hasCanonical)
|
|
646
|
+
score++;
|
|
647
|
+
if (technical.hasViewport)
|
|
648
|
+
score++;
|
|
649
|
+
if (technical.hasCharset)
|
|
650
|
+
score++;
|
|
651
|
+
if (technical.hasLang)
|
|
652
|
+
score++;
|
|
653
|
+
if (technical.hasRobotsMeta)
|
|
654
|
+
score++;
|
|
655
|
+
return Math.round((score / total) * 100);
|
|
656
|
+
}
|
|
657
|
+
calculateContentCompleteness(content) {
|
|
658
|
+
let score = 0;
|
|
659
|
+
const total = 5;
|
|
660
|
+
if (content.wordCount >= 300)
|
|
661
|
+
score++;
|
|
662
|
+
if (content.paragraphCount >= 3)
|
|
663
|
+
score++;
|
|
664
|
+
if (content.listCount > 0)
|
|
665
|
+
score++;
|
|
666
|
+
if (content.readingTimeMinutes >= 1)
|
|
667
|
+
score++;
|
|
668
|
+
if (content.strongTagCount > 0 || content.emTagCount > 0)
|
|
669
|
+
score++;
|
|
670
|
+
return Math.round((score / total) * 100);
|
|
671
|
+
}
|
|
672
|
+
calculateImageCompleteness(images) {
|
|
673
|
+
if (images.total === 0)
|
|
674
|
+
return 100;
|
|
675
|
+
let score = 0;
|
|
676
|
+
const total = 4;
|
|
677
|
+
if (images.withoutAlt === 0)
|
|
678
|
+
score++;
|
|
679
|
+
if (images.lazy > 0)
|
|
680
|
+
score++;
|
|
681
|
+
if (images.missingDimensions === 0)
|
|
682
|
+
score++;
|
|
683
|
+
if (images.modernFormats > 0)
|
|
684
|
+
score++;
|
|
685
|
+
return Math.round((score / total) * 100);
|
|
686
|
+
}
|
|
687
|
+
calculateLinkCompleteness(links) {
|
|
688
|
+
if (links.total === 0)
|
|
689
|
+
return 100;
|
|
690
|
+
let score = 0;
|
|
691
|
+
const total = 4;
|
|
692
|
+
if (links.internal > 0)
|
|
693
|
+
score++;
|
|
694
|
+
if (links.external > 0)
|
|
695
|
+
score++;
|
|
696
|
+
if (links.withoutText === 0)
|
|
697
|
+
score++;
|
|
698
|
+
if (links.broken === 0)
|
|
699
|
+
score++;
|
|
700
|
+
return Math.round((score / total) * 100);
|
|
701
|
+
}
|
|
506
702
|
analyzeHeadings() {
|
|
507
703
|
const issues = [];
|
|
508
704
|
const structure = [];
|