aeo-linter 0.1.3 → 0.1.5
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 +43 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,18 +4,21 @@
|
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import fs from 'node:fs/promises';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import { Runner, TerminalReporter, HtmlReporter, defaultConfig } from '@drowlink/aeo-linter-core';
|
|
7
|
+
import { Runner, TerminalReporter, HtmlReporter, defaultConfig, evaluateQualityGates, } from '@drowlink/aeo-linter-core';
|
|
8
8
|
export async function runCli() {
|
|
9
9
|
const program = new Command();
|
|
10
10
|
program
|
|
11
11
|
.name('aeo-linter')
|
|
12
12
|
.description('Answer Engine Optimization (AEO/GEO) Linter - Google Lighthouse Architecture')
|
|
13
|
-
.version('0.1.
|
|
13
|
+
.version('0.1.4')
|
|
14
14
|
.argument('<url>', 'Target webpage URL to audit')
|
|
15
15
|
.option('-j, --json', 'Output full report in JSON format')
|
|
16
16
|
.option('--html', 'Generate an interactive visual HTML report dashboard')
|
|
17
17
|
.option('-o, --output <file>', 'File path to save the report (.html or .json)')
|
|
18
18
|
.option('-c, --categories <categories>', 'Comma-separated list of categories to audit')
|
|
19
|
+
.option('--fail-under <score>', 'Fail with exit code 1 if overall score is below threshold (0-100)', parseFloat)
|
|
20
|
+
.option('--assert-category <assertions...>', 'Assert minimum score for category (e.g. "ai-accessibility=90,structured-data=80")')
|
|
21
|
+
.option('-q, --quiet', 'Suppress progress logs')
|
|
19
22
|
.action(async (url, options) => {
|
|
20
23
|
try {
|
|
21
24
|
// Validate URL format
|
|
@@ -52,7 +55,7 @@ export async function runCli() {
|
|
|
52
55
|
categories: filteredCategories,
|
|
53
56
|
};
|
|
54
57
|
}
|
|
55
|
-
const isQuiet = Boolean(options.json && !options.output);
|
|
58
|
+
const isQuiet = Boolean(options.quiet || (options.json && !options.output));
|
|
56
59
|
if (!isQuiet) {
|
|
57
60
|
console.log(`\x1b[36m⚡ Starting AEO audit for:\x1b[0m ${validUrl}`);
|
|
58
61
|
}
|
|
@@ -75,13 +78,17 @@ export async function runCli() {
|
|
|
75
78
|
content = HtmlReporter.generate(report);
|
|
76
79
|
}
|
|
77
80
|
await fs.writeFile(outPath, content, 'utf-8');
|
|
78
|
-
|
|
81
|
+
if (!isQuiet) {
|
|
82
|
+
console.log(`\n\x1b[32m✔ Report successfully saved to:\x1b[0m ${outPath}`);
|
|
83
|
+
}
|
|
79
84
|
}
|
|
80
85
|
else if (options.html) {
|
|
81
86
|
const defaultHtmlPath = path.resolve(process.cwd(), `aeo-report-${Date.now()}.html`);
|
|
82
87
|
const content = HtmlReporter.generate(report);
|
|
83
88
|
await fs.writeFile(defaultHtmlPath, content, 'utf-8');
|
|
84
|
-
|
|
89
|
+
if (!isQuiet) {
|
|
90
|
+
console.log(`\n\x1b[32m✔ Interactive HTML report generated at:\x1b[0m ${defaultHtmlPath}`);
|
|
91
|
+
}
|
|
85
92
|
}
|
|
86
93
|
else if (options.json) {
|
|
87
94
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -89,6 +96,37 @@ export async function runCli() {
|
|
|
89
96
|
else {
|
|
90
97
|
console.log(TerminalReporter.generate(report));
|
|
91
98
|
}
|
|
99
|
+
// CI/CD Quality Gate Assertions Evaluation
|
|
100
|
+
const categoryAssertions = {};
|
|
101
|
+
if (options.assertCategory) {
|
|
102
|
+
const list = Array.isArray(options.assertCategory)
|
|
103
|
+
? options.assertCategory.join(',').split(',')
|
|
104
|
+
: String(options.assertCategory).split(',');
|
|
105
|
+
for (const item of list) {
|
|
106
|
+
const [cat, valStr] = item.split('=').map((s) => s.trim());
|
|
107
|
+
if (cat && valStr) {
|
|
108
|
+
const val = parseFloat(valStr);
|
|
109
|
+
if (!isNaN(val))
|
|
110
|
+
categoryAssertions[cat] = val;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (typeof options.failUnder === 'number' || Object.keys(categoryAssertions).length > 0) {
|
|
115
|
+
const gateResult = evaluateQualityGates(report, {
|
|
116
|
+
failUnder: options.failUnder,
|
|
117
|
+
categoryAssertions: Object.keys(categoryAssertions).length > 0 ? categoryAssertions : undefined,
|
|
118
|
+
});
|
|
119
|
+
if (!gateResult.passed) {
|
|
120
|
+
console.error('\n\x1b[41m\x1b[37m ✖ AEO CI/CD Quality Gate Failed \x1b[0m');
|
|
121
|
+
for (const f of gateResult.failures) {
|
|
122
|
+
console.error(` \x1b[31m✖ ${f.name}:\x1b[0m Score \x1b[1m${f.actual}\x1b[0m is below required threshold \x1b[1m${f.expected}\x1b[0m`);
|
|
123
|
+
}
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.log(`\n\x1b[32m✔ AEO Quality Gate Passed: All assertions met successfully (Overall: ${report.overallScore}/100)\x1b[0m`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
92
130
|
}
|
|
93
131
|
catch (err) {
|
|
94
132
|
console.error(`\x1b[31mError during AEO audit:\x1b[0m`, err instanceof Error ? err.message : err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aeo-linter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Command-line interface for Answer Engine Optimization (AEO/GEO) Linter",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aeo-linter": "./bin/aeo-linter.js"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"author": "DrowLink",
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@drowlink/aeo-linter-core": "^0.1.
|
|
34
|
+
"@drowlink/aeo-linter-core": "^0.1.5",
|
|
35
35
|
"commander": "^12.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|