@forkpoint/agent-lighthouse-core 0.2.0 → 0.2.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/README.md +27 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +65 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +65 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -3
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @forkpoint/agent-lighthouse-core
|
|
2
|
+
|
|
3
|
+
Core TypeScript scanner engine for Agent Lighthouse.
|
|
4
|
+
|
|
5
|
+
Use this package when you want to embed AI-agent readiness audits in your own service, build tooling, CI system, or reporting flow.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { runScan } from "@forkpoint/agent-lighthouse-core";
|
|
11
|
+
|
|
12
|
+
const report = await runScan("https://example.com");
|
|
13
|
+
|
|
14
|
+
console.log(report.overallScore);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The engine runs deterministic audits for `llms.txt`, AI crawler access, Schema.org, WebMCP, OpenAPI discovery, AEO/GEO content structure, accessibility, and technical readiness.
|
|
18
|
+
|
|
19
|
+
## Links
|
|
20
|
+
|
|
21
|
+
- Documentation: https://forkpoint.github.io/agent-lighthouse/
|
|
22
|
+
- Repository: https://github.com/ForkPoint/agent-lighthouse
|
|
23
|
+
- CLI package: https://www.npmjs.com/package/@forkpoint/agent-lighthouse
|
|
24
|
+
|
|
25
|
+
## License
|
|
26
|
+
|
|
27
|
+
GPL-3.0-only
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -603,7 +603,8 @@ function extractImages($) {
|
|
|
603
603
|
width: $(el).attr("width") ?? void 0,
|
|
604
604
|
height: $(el).attr("height") ?? void 0,
|
|
605
605
|
loading: $(el).attr("loading") ?? void 0,
|
|
606
|
-
role: $(el).attr("role") ?? void 0
|
|
606
|
+
role: $(el).attr("role") ?? void 0,
|
|
607
|
+
ariaHidden: $(el).attr("aria-hidden") ?? void 0
|
|
607
608
|
});
|
|
608
609
|
});
|
|
609
610
|
return images;
|
|
@@ -4743,9 +4744,6 @@ function matchesAnyType2(schema, types) {
|
|
|
4743
4744
|
function allSchemas3(ctx) {
|
|
4744
4745
|
return ctx.pages.flatMap((p) => flattenJsonLd(p.structuredData ?? p.jsonLd));
|
|
4745
4746
|
}
|
|
4746
|
-
function hasProps3(obj, keys) {
|
|
4747
|
-
return keys.filter((k) => !obj[k]);
|
|
4748
|
-
}
|
|
4749
4747
|
var ServiceProductSchemaAudit = class extends Audit {
|
|
4750
4748
|
static meta = {
|
|
4751
4749
|
id: "3.8",
|
|
@@ -4798,13 +4796,19 @@ var ServiceProductSchemaAudit = class extends Audit {
|
|
|
4798
4796
|
}
|
|
4799
4797
|
);
|
|
4800
4798
|
}
|
|
4801
|
-
const requiredProps = ["name", "description", "provider"];
|
|
4802
4799
|
const first2 = serviceProducts[0];
|
|
4803
|
-
const
|
|
4800
|
+
const isProduct = matchesAnyType2(first2, ["Product"]);
|
|
4801
|
+
const hasName = Boolean(first2["name"]);
|
|
4802
|
+
const hasDescription = Boolean(first2["description"]);
|
|
4803
|
+
const hasProviderOrBrand = isProduct ? Boolean(first2["brand"] || first2["manufacturer"] || first2["provider"] || first2["offers"]) : Boolean(first2["provider"]);
|
|
4804
|
+
const missing = [];
|
|
4805
|
+
if (!hasName) missing.push("name");
|
|
4806
|
+
if (!hasDescription) missing.push("description");
|
|
4807
|
+
if (!hasProviderOrBrand) missing.push(isProduct ? "brand/offers" : "provider");
|
|
4804
4808
|
const valid = missing.length === 0;
|
|
4805
4809
|
if (valid) {
|
|
4806
4810
|
return this.pass(
|
|
4807
|
-
`Service/Product schema found with name, description, and provider.`,
|
|
4811
|
+
`Service/Product schema found with name, description, and ${isProduct ? "brand/offers" : "provider"}.`,
|
|
4808
4812
|
"Service or Product schema with name, description, and provider.",
|
|
4809
4813
|
`Complete Service/Product schema (${serviceProducts.length} total)`
|
|
4810
4814
|
);
|
|
@@ -5450,7 +5454,7 @@ function matchesAnyType7(schema, types) {
|
|
|
5450
5454
|
function allSchemas8(ctx) {
|
|
5451
5455
|
return ctx.pages.flatMap((p) => flattenJsonLd(p.structuredData ?? p.jsonLd));
|
|
5452
5456
|
}
|
|
5453
|
-
function
|
|
5457
|
+
function hasProps3(obj, keys) {
|
|
5454
5458
|
return keys.filter((k) => !obj[k]);
|
|
5455
5459
|
}
|
|
5456
5460
|
var AuthorSchemaAudit = class extends Audit {
|
|
@@ -5531,11 +5535,11 @@ var AuthorSchemaAudit = class extends Audit {
|
|
|
5531
5535
|
}
|
|
5532
5536
|
const requiredProps = ["name", "jobTitle", "sameAs", "affiliation"];
|
|
5533
5537
|
const bestPerson = allPersons.reduce((best, p) => {
|
|
5534
|
-
const bestMissing =
|
|
5535
|
-
const currentMissing =
|
|
5538
|
+
const bestMissing = hasProps3(best, requiredProps).length;
|
|
5539
|
+
const currentMissing = hasProps3(p, requiredProps).length;
|
|
5536
5540
|
return currentMissing < bestMissing ? p : best;
|
|
5537
5541
|
}, allPersons[0]);
|
|
5538
|
-
const missing =
|
|
5542
|
+
const missing = hasProps3(bestPerson, requiredProps);
|
|
5539
5543
|
const complete = missing.length === 0;
|
|
5540
5544
|
if (complete) {
|
|
5541
5545
|
return this.pass(
|
|
@@ -11456,7 +11460,7 @@ var DecorativeImagesAudit = class extends Audit {
|
|
|
11456
11460
|
for (const img of images) {
|
|
11457
11461
|
if (img.alt === "") {
|
|
11458
11462
|
decorativeCount++;
|
|
11459
|
-
if (img.role === "presentation") {
|
|
11463
|
+
if (img.role === "presentation" || img.role === "none" || img.ariaHidden === "true") {
|
|
11460
11464
|
correctlyMarked++;
|
|
11461
11465
|
}
|
|
11462
11466
|
}
|
|
@@ -12680,8 +12684,19 @@ var CorsAiFilesAudit = class extends Audit {
|
|
|
12680
12684
|
async audit(ctx) {
|
|
12681
12685
|
const page = ctx.pages?.[0];
|
|
12682
12686
|
const aiPaths = ["/llms.txt", "/.well-known/ai-catalog.json"];
|
|
12687
|
+
const hasRootFiles = ctx.rootFiles && Object.keys(ctx.rootFiles).length > 0;
|
|
12688
|
+
const existingAiPaths = hasRootFiles ? aiPaths.filter((p) => ctx.rootFiles[p]?.status === 200) : aiPaths;
|
|
12689
|
+
if (hasRootFiles && existingAiPaths.length === 0) {
|
|
12690
|
+
return this.warn(
|
|
12691
|
+
"No AI files (/llms.txt, /.well-known/ai-catalog.json) found to check CORS headers.",
|
|
12692
|
+
"OPTIONS requests to /llms.txt and /.well-known/ai-catalog.json return Access-Control-Allow-Origin",
|
|
12693
|
+
"No applicable AI files found",
|
|
12694
|
+
void 0,
|
|
12695
|
+
page?.url
|
|
12696
|
+
);
|
|
12697
|
+
}
|
|
12683
12698
|
const corsResults = [];
|
|
12684
|
-
for (const path of
|
|
12699
|
+
for (const path of existingAiPaths) {
|
|
12685
12700
|
try {
|
|
12686
12701
|
const result = await ctx.fetch({
|
|
12687
12702
|
url: `${ctx.baseUrl}${path}`,
|
|
@@ -15171,9 +15186,33 @@ var AboutCredentialsAudit = class extends Audit {
|
|
|
15171
15186
|
}
|
|
15172
15187
|
};
|
|
15173
15188
|
async audit(ctx) {
|
|
15174
|
-
const aboutPaths = [
|
|
15175
|
-
|
|
15176
|
-
|
|
15189
|
+
const aboutPaths = [
|
|
15190
|
+
"/about/",
|
|
15191
|
+
"/about-us/",
|
|
15192
|
+
"/about",
|
|
15193
|
+
"/pages/about",
|
|
15194
|
+
"/pages/about-us",
|
|
15195
|
+
"/pages/our-story",
|
|
15196
|
+
"/our-story"
|
|
15197
|
+
];
|
|
15198
|
+
let aboutResult = void 0;
|
|
15199
|
+
for (const path of aboutPaths) {
|
|
15200
|
+
const file = ctx.rootFiles[path];
|
|
15201
|
+
if (file && file.status === 200 && file.body) {
|
|
15202
|
+
aboutResult = file;
|
|
15203
|
+
break;
|
|
15204
|
+
}
|
|
15205
|
+
}
|
|
15206
|
+
if (!aboutResult && ctx.pages) {
|
|
15207
|
+
const matchingPage = ctx.pages.find((p) => {
|
|
15208
|
+
const urlLower = p.url.toLowerCase();
|
|
15209
|
+
return urlLower.includes("/about") || urlLower.includes("/our-story") || urlLower.includes("/who-we-are");
|
|
15210
|
+
});
|
|
15211
|
+
if (matchingPage?.fetchResult?.status === 200 && matchingPage.fetchResult.body) {
|
|
15212
|
+
aboutResult = matchingPage.fetchResult;
|
|
15213
|
+
}
|
|
15214
|
+
}
|
|
15215
|
+
if (!aboutResult) {
|
|
15177
15216
|
for (const path of aboutPaths) {
|
|
15178
15217
|
try {
|
|
15179
15218
|
const result = await ctx.fetch({
|
|
@@ -15442,7 +15481,11 @@ var TRUST_PATTERNS = [
|
|
|
15442
15481
|
/\baward/i,
|
|
15443
15482
|
/\bas\s+seen\s+(in|on)\b/i,
|
|
15444
15483
|
/\bpartner(s|ed|ship)?\b/i,
|
|
15445
|
-
/\bcertif(ied|icate|ication)\b/i
|
|
15484
|
+
/\bcertif(ied|icate|ication)\b/i,
|
|
15485
|
+
/\b(money[-\s]back\s+guarantee|satisfaction\s+guarantee|guaranteed)\b/i,
|
|
15486
|
+
/\b(reviews|customer\s+rating|verified\s+(buyer|customer|review)|happy\s+customers)\b/i,
|
|
15487
|
+
/\b(sustainable|organic|fair\s+trade|b\s+corp|handcrafted|handmade)\b/i,
|
|
15488
|
+
/\b(secure\s+checkout|free\s+returns|free\s+shipping)\b/i
|
|
15446
15489
|
];
|
|
15447
15490
|
var TrustSignalsAudit = class extends Audit {
|
|
15448
15491
|
static meta = {
|
|
@@ -22148,7 +22191,11 @@ async function runScan(url, onProgress, pageOverrides, signal) {
|
|
|
22148
22191
|
"/policies/terms-of-service",
|
|
22149
22192
|
"/about/",
|
|
22150
22193
|
"/about-us/",
|
|
22151
|
-
"/about"
|
|
22194
|
+
"/about",
|
|
22195
|
+
"/pages/about",
|
|
22196
|
+
"/pages/about-us",
|
|
22197
|
+
"/pages/our-story",
|
|
22198
|
+
"/our-story"
|
|
22152
22199
|
];
|
|
22153
22200
|
logger.debug({ count: rootFilePaths.length }, "[orchestrator] Phase 1: Fetching root files");
|
|
22154
22201
|
const rootResults = await Promise.all(
|