@ai-lighthouse/cli 1.0.0
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/.ai-lighthouse/audit_example.com_2025-12-15T12-10-43.json +183 -0
- package/.ai-lighthouse/audit_fayeed.dev_2026-01-07T19-32-28.html +743 -0
- package/.ai-lighthouse/audit_fayeed.dev_2026-01-07T19-33-02.html +757 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T11-53-21.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-04-06.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-05-10.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-09-45.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-11-07.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-13-28.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-14-59.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-18-07.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-18-44.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-21-38.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-22-21.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-22-46.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-23-18.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-15T12-24-43.json +205 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-15-08.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-15-57.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-17-11.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-22-17.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-22-42.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-23-56.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-25-24.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-25-40.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-27-02.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-27-20.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-29-56.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-32-27.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-33-00.json +168 -0
- package/.ai-lighthouse/audit_github.com_2025-12-17T12-34-49.json +168 -0
- package/.ai-lighthouse/audit_stripe.com_2025-12-15T12-11-31.json +168 -0
- package/.ai-lighthouse/audit_stripe.com_2025-12-15T12-11-45.json +168 -0
- package/.ai-lighthouse/audit_tailwindcss.com_2025-12-15T12-12-01.json +169 -0
- package/.ai-lighthouse/crawl_example.com_2025-12-15T12-03-08.json +24 -0
- package/.ai-lighthouse/crawl_example.com_2025-12-15T12-03-23.json +24 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-41-34.json +21 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-42-09.json +21 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-42-45.json +21 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-43-02.json +21 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-43-26.json +21 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-47-46.json +906 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-50-27.json +906 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T11-52-59.json +906 -0
- package/.ai-lighthouse/crawl_github.com_2025-12-15T12-03-33.json +28 -0
- package/CLI_UI_README.md +211 -0
- package/EXAMPLES.md +87 -0
- package/IMPLEMENTATION.md +215 -0
- package/README.md +166 -0
- package/USAGE.md +264 -0
- package/WIZARD_GUIDE.md +340 -0
- package/bin/cli.js +2 -0
- package/dist/commands/audit-interactive.d.ts +2 -0
- package/dist/commands/audit-interactive.js +106 -0
- package/dist/commands/audit-wizard.d.ts +2 -0
- package/dist/commands/audit-wizard.js +110 -0
- package/dist/commands/audit.d.ts +2 -0
- package/dist/commands/audit.js +940 -0
- package/dist/commands/crawl.d.ts +2 -0
- package/dist/commands/crawl.js +267 -0
- package/dist/commands/report.d.ts +2 -0
- package/dist/commands/report.js +304 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +16 -0
- package/dist/ui/AuditReportUI.d.ts +10 -0
- package/dist/ui/AuditReportUI.js +76 -0
- package/dist/ui/SetupWizard.d.ts +18 -0
- package/dist/ui/SetupWizard.js +179 -0
- package/dist/ui/components/AIUnderstandingSection.d.ts +6 -0
- package/dist/ui/components/AIUnderstandingSection.js +87 -0
- package/dist/ui/components/HallucinationSection.d.ts +6 -0
- package/dist/ui/components/HallucinationSection.js +84 -0
- package/dist/ui/components/IssuesSection.d.ts +6 -0
- package/dist/ui/components/IssuesSection.js +84 -0
- package/dist/ui/components/MessageAlignmentSection.d.ts +6 -0
- package/dist/ui/components/MessageAlignmentSection.js +108 -0
- package/dist/ui/components/OverviewSection.d.ts +6 -0
- package/dist/ui/components/OverviewSection.js +107 -0
- package/dist/ui/components/ScoreDisplay.d.ts +8 -0
- package/dist/ui/components/ScoreDisplay.js +41 -0
- package/dist/ui/components/TechnicalSection.d.ts +7 -0
- package/dist/ui/components/TechnicalSection.js +110 -0
- package/dist/utils/comprehensive-formatter.d.ts +5 -0
- package/dist/utils/comprehensive-formatter.js +370 -0
- package/package.json +49 -0
- package/src/commands/audit-interactive.ts +149 -0
- package/src/commands/audit-wizard.ts +137 -0
- package/src/commands/audit.ts +1012 -0
- package/src/commands/crawl.ts +307 -0
- package/src/commands/report.ts +321 -0
- package/src/index.ts +22 -0
- package/src/ui/AuditReportUI.tsx +151 -0
- package/src/ui/SetupWizard.tsx +294 -0
- package/src/ui/components/AIUnderstandingSection.tsx +183 -0
- package/src/ui/components/HallucinationSection.tsx +172 -0
- package/src/ui/components/IssuesSection.tsx +140 -0
- package/src/ui/components/MessageAlignmentSection.tsx +203 -0
- package/src/ui/components/OverviewSection.tsx +157 -0
- package/src/ui/components/ScoreDisplay.tsx +58 -0
- package/src/ui/components/TechnicalSection.tsx +200 -0
- package/src/utils/comprehensive-formatter.ts +455 -0
- package/test.sh +31 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
/**
|
|
3
|
+
* Comprehensive CLI formatter that displays all data shown on the website
|
|
4
|
+
*/
|
|
5
|
+
export function formatComprehensiveReport(result, aiReadiness) {
|
|
6
|
+
const sections = [];
|
|
7
|
+
// LLM/AI Understanding Section
|
|
8
|
+
if (result.llm) {
|
|
9
|
+
sections.push(formatLLMSection(result.llm));
|
|
10
|
+
}
|
|
11
|
+
// Chunking Section
|
|
12
|
+
if (result.chunking) {
|
|
13
|
+
sections.push(formatChunkingSection(result.chunking));
|
|
14
|
+
}
|
|
15
|
+
// Extractability Section
|
|
16
|
+
if (result.extractability) {
|
|
17
|
+
sections.push(formatExtractabilitySection(result.extractability));
|
|
18
|
+
}
|
|
19
|
+
// Hallucination Risk Section
|
|
20
|
+
if (result.hallucinationReport) {
|
|
21
|
+
sections.push(formatHallucinationSection(result.hallucinationReport));
|
|
22
|
+
}
|
|
23
|
+
// Mirror Report Section
|
|
24
|
+
if (result.mirrorReport) {
|
|
25
|
+
sections.push(formatMirrorReportSection(result.mirrorReport));
|
|
26
|
+
}
|
|
27
|
+
// Dimension Scores
|
|
28
|
+
if (aiReadiness?.dimensions) {
|
|
29
|
+
sections.push(formatDimensionsSection(aiReadiness.dimensions));
|
|
30
|
+
}
|
|
31
|
+
// Quick Wins
|
|
32
|
+
if (aiReadiness?.quickWins && aiReadiness.quickWins.length > 0) {
|
|
33
|
+
sections.push(formatQuickWinsSection(aiReadiness.quickWins));
|
|
34
|
+
}
|
|
35
|
+
return sections.join('\n\n');
|
|
36
|
+
}
|
|
37
|
+
function formatLLMSection(llm) {
|
|
38
|
+
const lines = [];
|
|
39
|
+
lines.push(chalk.bold.blue('📝 AI Understanding Analysis'));
|
|
40
|
+
lines.push('─'.repeat(70));
|
|
41
|
+
if (llm.summary) {
|
|
42
|
+
lines.push(chalk.bold('Summary:'));
|
|
43
|
+
lines.push(` ${llm.summary}`);
|
|
44
|
+
lines.push('');
|
|
45
|
+
}
|
|
46
|
+
if (llm.pageType) {
|
|
47
|
+
lines.push(chalk.bold('Inferred Page Type:'));
|
|
48
|
+
lines.push(` ${chalk.magenta.bold(llm.pageType)}`);
|
|
49
|
+
if (llm.pageTypeInsights && llm.pageTypeInsights.length > 0) {
|
|
50
|
+
lines.push('');
|
|
51
|
+
lines.push(chalk.bold('💡 AI-Generated Insights:'));
|
|
52
|
+
llm.pageTypeInsights.forEach((insight) => {
|
|
53
|
+
lines.push(` ${chalk.cyan('•')} ${insight}`);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
lines.push('');
|
|
57
|
+
}
|
|
58
|
+
if (llm.keyTopics && llm.keyTopics.length > 0) {
|
|
59
|
+
lines.push(chalk.bold('Key Topics:'));
|
|
60
|
+
lines.push(` ${llm.keyTopics.map((t) => chalk.blue(t)).join(', ')}`);
|
|
61
|
+
lines.push('');
|
|
62
|
+
}
|
|
63
|
+
const metadata = [];
|
|
64
|
+
if (llm.readingLevel) {
|
|
65
|
+
metadata.push(`Reading Level: ${llm.readingLevel.description}`);
|
|
66
|
+
}
|
|
67
|
+
if (llm.sentiment) {
|
|
68
|
+
metadata.push(`Sentiment: ${llm.sentiment}`);
|
|
69
|
+
}
|
|
70
|
+
if (llm.technicalDepth) {
|
|
71
|
+
metadata.push(`Technical Depth: ${llm.technicalDepth}`);
|
|
72
|
+
}
|
|
73
|
+
if (metadata.length > 0) {
|
|
74
|
+
lines.push(chalk.bold('Metadata:'));
|
|
75
|
+
metadata.forEach(m => lines.push(` ${m}`));
|
|
76
|
+
lines.push('');
|
|
77
|
+
}
|
|
78
|
+
if (llm.topEntities && llm.topEntities.length > 0) {
|
|
79
|
+
lines.push(chalk.bold('🔍 Key Entities:'));
|
|
80
|
+
llm.topEntities.slice(0, 5).forEach((entity) => {
|
|
81
|
+
const relevance = entity.relevance ? ` - ${Math.round(entity.relevance * 100)}% relevance` : '';
|
|
82
|
+
lines.push(` ${chalk.cyan('•')} ${chalk.bold(entity.name)} ${chalk.dim(`(${entity.type})${relevance}`)}`);
|
|
83
|
+
});
|
|
84
|
+
lines.push('');
|
|
85
|
+
}
|
|
86
|
+
if (llm.questions && llm.questions.length > 0) {
|
|
87
|
+
lines.push(chalk.bold('❓ Questions AI Can Answer:'));
|
|
88
|
+
llm.questions.slice(0, 5).forEach((q, idx) => {
|
|
89
|
+
const difficulty = chalk.dim(`[${q.difficulty.toUpperCase()}]`);
|
|
90
|
+
lines.push(` ${idx + 1}. ${difficulty} ${q.question}`);
|
|
91
|
+
});
|
|
92
|
+
lines.push('');
|
|
93
|
+
}
|
|
94
|
+
if (llm.suggestedFAQ && llm.suggestedFAQ.length > 0) {
|
|
95
|
+
lines.push(chalk.bold('💡 Suggested FAQs:'));
|
|
96
|
+
llm.suggestedFAQ
|
|
97
|
+
.filter((f) => f.importance === 'high')
|
|
98
|
+
.slice(0, 3)
|
|
99
|
+
.forEach((faq, idx) => {
|
|
100
|
+
lines.push(` ${idx + 1}. Q: ${chalk.yellow(faq.question)}`);
|
|
101
|
+
lines.push(` A: ${chalk.dim(faq.suggestedAnswer)}`);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
function formatChunkingSection(chunking) {
|
|
107
|
+
const lines = [];
|
|
108
|
+
lines.push(chalk.bold.green('📄 Content Chunking Analysis'));
|
|
109
|
+
lines.push('─'.repeat(70));
|
|
110
|
+
const grid = [
|
|
111
|
+
['Strategy', chunking.chunkingStrategy],
|
|
112
|
+
['Total Chunks', chunking.totalChunks.toString()],
|
|
113
|
+
['Avg Tokens/Chunk', chunking.averageTokensPerChunk.toString()],
|
|
114
|
+
['Avg Noise Ratio', `${(chunking.averageNoiseRatio * 100).toFixed(1)}%`],
|
|
115
|
+
];
|
|
116
|
+
grid.forEach(([label, value]) => {
|
|
117
|
+
lines.push(` ${chalk.bold(label + ':').padEnd(25)} ${chalk.cyan(value)}`);
|
|
118
|
+
});
|
|
119
|
+
if (chunking.chunkingStrategy === 'heading-based') {
|
|
120
|
+
lines.push('');
|
|
121
|
+
lines.push(chalk.green(' ✓ Heading-based chunking is ideal for AI comprehension'));
|
|
122
|
+
}
|
|
123
|
+
else if (chunking.chunkingStrategy === 'paragraph-based') {
|
|
124
|
+
lines.push('');
|
|
125
|
+
lines.push(chalk.yellow(' ⚠ Consider adding headings for better semantic structure'));
|
|
126
|
+
}
|
|
127
|
+
if (chunking.chunks && chunking.chunks.length > 0) {
|
|
128
|
+
lines.push('');
|
|
129
|
+
lines.push(chalk.bold('Chunk Distribution:'));
|
|
130
|
+
// Show token distribution
|
|
131
|
+
const tokenCounts = chunking.chunks.map((c) => c.tokenCount);
|
|
132
|
+
const min = Math.min(...tokenCounts);
|
|
133
|
+
const max = Math.max(...tokenCounts);
|
|
134
|
+
const avg = tokenCounts.reduce((a, b) => a + b, 0) / tokenCounts.length;
|
|
135
|
+
lines.push(` Min Tokens: ${min}, Max Tokens: ${max}, Avg: ${avg.toFixed(0)}`);
|
|
136
|
+
// Show noise distribution
|
|
137
|
+
const noiseRatios = chunking.chunks.map((c) => c.noiseRatio);
|
|
138
|
+
const avgNoise = noiseRatios.reduce((a, b) => a + b, 0) / noiseRatios.length;
|
|
139
|
+
lines.push(` Avg Noise per Chunk: ${(avgNoise * 100).toFixed(1)}%`);
|
|
140
|
+
}
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
function formatExtractabilitySection(extractability) {
|
|
144
|
+
const lines = [];
|
|
145
|
+
lines.push(chalk.bold.yellow('🔄 Extractability Analysis'));
|
|
146
|
+
lines.push('─'.repeat(70));
|
|
147
|
+
const grid = [
|
|
148
|
+
['Overall Score', `${extractability.score.extractabilityScore}/100`],
|
|
149
|
+
['Server-Rendered', `${extractability.score.serverRenderedPercent}%`],
|
|
150
|
+
];
|
|
151
|
+
grid.forEach(([label, value]) => {
|
|
152
|
+
lines.push(` ${chalk.bold(label + ':').padEnd(25)} ${chalk.cyan(value)}`);
|
|
153
|
+
});
|
|
154
|
+
lines.push('');
|
|
155
|
+
lines.push(chalk.bold('Content Type Extractability:'));
|
|
156
|
+
Object.entries(extractability.contentTypes).forEach(([type, data]) => {
|
|
157
|
+
const percentage = data.percentage;
|
|
158
|
+
const color = percentage >= 80 ? chalk.green : percentage >= 50 ? chalk.yellow : chalk.red;
|
|
159
|
+
lines.push(` ${chalk.bold(type.charAt(0).toUpperCase() + type.slice(1) + ':').padEnd(15)} ${color(`${percentage}%`)} (${data.extractable}/${data.total})`);
|
|
160
|
+
});
|
|
161
|
+
const overallScore = extractability.score.extractabilityScore;
|
|
162
|
+
if (overallScore >= 80) {
|
|
163
|
+
lines.push('');
|
|
164
|
+
lines.push(chalk.green(' ✓ Good extractability - AI can easily read your content'));
|
|
165
|
+
}
|
|
166
|
+
else if (overallScore < 50) {
|
|
167
|
+
lines.push('');
|
|
168
|
+
lines.push(chalk.red(' ⚠ Low extractability - Consider server-side rendering'));
|
|
169
|
+
}
|
|
170
|
+
return lines.join('\n');
|
|
171
|
+
}
|
|
172
|
+
function formatHallucinationSection(report) {
|
|
173
|
+
const lines = [];
|
|
174
|
+
lines.push(chalk.bold.red('⚠️ Hallucination Risk Assessment'));
|
|
175
|
+
lines.push('─'.repeat(70));
|
|
176
|
+
const riskScore = report.hallucinationRiskScore;
|
|
177
|
+
const riskColor = riskScore >= 70 ? chalk.red : riskScore >= 40 ? chalk.yellow : chalk.green;
|
|
178
|
+
lines.push(` ${chalk.bold('Risk Score:')} ${riskColor.bold(`${riskScore}/100`)}`);
|
|
179
|
+
if (report.factCheckSummary) {
|
|
180
|
+
lines.push('');
|
|
181
|
+
lines.push(chalk.bold('Fact Check Summary:'));
|
|
182
|
+
const summary = report.factCheckSummary;
|
|
183
|
+
lines.push(` Total Facts: ${chalk.cyan(summary.totalFacts)}`);
|
|
184
|
+
lines.push(` Verified: ${chalk.green(summary.verifiedFacts)}`);
|
|
185
|
+
lines.push(` Unverified: ${chalk.yellow(summary.unverifiedFacts)}`);
|
|
186
|
+
lines.push(` Contradictions: ${chalk.red(summary.contradictions)}`);
|
|
187
|
+
if (summary.ambiguities !== undefined) {
|
|
188
|
+
lines.push(` Ambiguities: ${chalk.yellow(summary.ambiguities)}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (report.factCheckSummary && report.factCheckSummary.unverifiedFacts > 0) {
|
|
192
|
+
lines.push('');
|
|
193
|
+
lines.push(chalk.yellow('💡 Tip: Add citations and links to verify claims and reduce AI hallucination risk'));
|
|
194
|
+
}
|
|
195
|
+
if (report.triggers && report.triggers.length > 0) {
|
|
196
|
+
const highSeverityTriggers = report.triggers.filter((t) => t.severity === 'high' || t.severity === 'critical');
|
|
197
|
+
if (highSeverityTriggers.length > 0) {
|
|
198
|
+
lines.push('');
|
|
199
|
+
lines.push(chalk.bold('🚨 High-Risk Triggers:'));
|
|
200
|
+
highSeverityTriggers.slice(0, 5).forEach((trigger, idx) => {
|
|
201
|
+
lines.push(` ${idx + 1}. ${chalk.red(`[${trigger.severity.toUpperCase()}]`)} ${trigger.type}`);
|
|
202
|
+
lines.push(` ${chalk.dim(trigger.description)}`);
|
|
203
|
+
if (trigger.confidence) {
|
|
204
|
+
lines.push(` ${chalk.dim(`Confidence: ${Math.round(trigger.confidence * 100)}%`)}`);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (report.recommendations && report.recommendations.length > 0) {
|
|
210
|
+
lines.push('');
|
|
211
|
+
lines.push(chalk.bold('💡 Recommendations:'));
|
|
212
|
+
report.recommendations.slice(0, 3).forEach((rec, idx) => {
|
|
213
|
+
lines.push(` ${idx + 1}. ${rec}`);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return lines.join('\n');
|
|
217
|
+
}
|
|
218
|
+
function formatMirrorReportSection(report) {
|
|
219
|
+
const lines = [];
|
|
220
|
+
lines.push(chalk.bold.magenta('🔍 AI Misunderstanding Check'));
|
|
221
|
+
lines.push('─'.repeat(70));
|
|
222
|
+
const alignmentColor = report.summary.alignmentScore >= 80 ? chalk.green :
|
|
223
|
+
report.summary.alignmentScore >= 60 ? chalk.yellow : chalk.red;
|
|
224
|
+
const clarityColor = report.summary.clarityScore >= 80 ? chalk.green :
|
|
225
|
+
report.summary.clarityScore >= 60 ? chalk.yellow : chalk.red;
|
|
226
|
+
lines.push(` ${chalk.bold('Alignment Score:').padEnd(25)} ${alignmentColor.bold(`${report.summary.alignmentScore}/100`)}`);
|
|
227
|
+
lines.push(` ${chalk.bold('Clarity Score:').padEnd(25)} ${clarityColor.bold(`${report.summary.clarityScore}/100`)}`);
|
|
228
|
+
lines.push(` ${chalk.bold('Critical Issues:').padEnd(25)} ${chalk.red(report.summary.critical)}`);
|
|
229
|
+
lines.push(` ${chalk.bold('Major Issues:').padEnd(25)} ${chalk.yellow(report.summary.major)}`);
|
|
230
|
+
// AI Interpretation - What AI Actually Understood
|
|
231
|
+
if (report.llmInterpretation) {
|
|
232
|
+
lines.push('');
|
|
233
|
+
lines.push(chalk.bold.blue('🤖 What AI Actually Understood'));
|
|
234
|
+
lines.push(chalk.dim(` (${Math.round(report.llmInterpretation.confidence * 100)}% confident)`));
|
|
235
|
+
if (report.llmInterpretation.productName) {
|
|
236
|
+
lines.push(` ${chalk.bold('Product:')} ${report.llmInterpretation.productName}`);
|
|
237
|
+
}
|
|
238
|
+
if (report.llmInterpretation.purpose) {
|
|
239
|
+
lines.push(` ${chalk.bold('Purpose:')} ${report.llmInterpretation.purpose}`);
|
|
240
|
+
}
|
|
241
|
+
if (report.llmInterpretation.valueProposition) {
|
|
242
|
+
lines.push(` ${chalk.bold.magenta('💎 Value:')} ${report.llmInterpretation.valueProposition}`);
|
|
243
|
+
}
|
|
244
|
+
if (report.llmInterpretation.keyBenefits && report.llmInterpretation.keyBenefits.length > 0) {
|
|
245
|
+
lines.push(` ${chalk.bold('Benefits:')}`);
|
|
246
|
+
report.llmInterpretation.keyBenefits.forEach((benefit) => {
|
|
247
|
+
lines.push(` • ${benefit}`);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (report.llmInterpretation.keyFeatures && report.llmInterpretation.keyFeatures.length > 0) {
|
|
251
|
+
lines.push(` ${chalk.bold('Features:')}`);
|
|
252
|
+
report.llmInterpretation.keyFeatures.slice(0, 3).forEach((feature) => {
|
|
253
|
+
lines.push(` • ${feature}`);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (report.llmInterpretation.targetAudience) {
|
|
257
|
+
lines.push(` ${chalk.bold('Audience:')} ${report.llmInterpretation.targetAudience}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (report.mismatches && report.mismatches.length > 0) {
|
|
261
|
+
const priorityMismatches = report.mismatches.filter((m) => m.severity === 'critical' || m.severity === 'major');
|
|
262
|
+
if (priorityMismatches.length > 0) {
|
|
263
|
+
lines.push('');
|
|
264
|
+
lines.push(chalk.bold('Priority Mismatches:'));
|
|
265
|
+
priorityMismatches.slice(0, 5).forEach((mismatch, idx) => {
|
|
266
|
+
const icon = mismatch.severity === 'critical' ? '🔴' : '🟡';
|
|
267
|
+
lines.push(` ${icon} ${idx + 1}. ${chalk.bold(mismatch.field)}`);
|
|
268
|
+
lines.push(` ${chalk.dim(mismatch.description)}`);
|
|
269
|
+
lines.push(` ${chalk.cyan('→')} ${mismatch.recommendation}`);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (report.recommendations && report.recommendations.length > 0) {
|
|
274
|
+
lines.push('');
|
|
275
|
+
lines.push(chalk.bold('💡 Top Recommendations:'));
|
|
276
|
+
report.recommendations.slice(0, 3).forEach((rec, idx) => {
|
|
277
|
+
lines.push(` ${idx + 1}. ${rec}`);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return lines.join('\n');
|
|
281
|
+
}
|
|
282
|
+
function formatDimensionsSection(dimensions) {
|
|
283
|
+
const lines = [];
|
|
284
|
+
lines.push(chalk.bold.cyan('🎯 Dimension Analysis'));
|
|
285
|
+
lines.push('─'.repeat(70));
|
|
286
|
+
const dimensionDescriptions = {
|
|
287
|
+
technical: '⚙️ Technical',
|
|
288
|
+
contentQuality: '📝 Content Quality',
|
|
289
|
+
crawlability: '🕷️ Crawlability',
|
|
290
|
+
discoverability: '🔍 Discoverability',
|
|
291
|
+
knowledge: '🧠 Knowledge',
|
|
292
|
+
extractability: '🔄 Extractability',
|
|
293
|
+
comprehensibility: '💡 Comprehensibility',
|
|
294
|
+
trustworthiness: '✅ Trustworthiness',
|
|
295
|
+
accessibility: '♿ Accessibility',
|
|
296
|
+
};
|
|
297
|
+
Object.entries(dimensions).forEach(([key, dim]) => {
|
|
298
|
+
const name = dimensionDescriptions[key] || key;
|
|
299
|
+
const scoreColor = dim.score >= 90 ? chalk.green :
|
|
300
|
+
dim.score >= 75 ? chalk.yellow :
|
|
301
|
+
dim.score >= 60 ? chalk.hex('#FFA500') : chalk.red;
|
|
302
|
+
lines.push('');
|
|
303
|
+
lines.push(`${name}: ${scoreColor.bold(`${Math.round(dim.score)}/100`)} ${chalk.dim(`(${dim.status})`)}`);
|
|
304
|
+
if (dim.strengths && dim.strengths.length > 0) {
|
|
305
|
+
lines.push(` ${chalk.green('Strengths:')} ${dim.strengths.join(', ')}`);
|
|
306
|
+
}
|
|
307
|
+
if (dim.weaknesses && dim.weaknesses.length > 0) {
|
|
308
|
+
lines.push(` ${chalk.yellow('Weaknesses:')} ${dim.weaknesses.join(', ')}`);
|
|
309
|
+
}
|
|
310
|
+
if (dim.recommendation) {
|
|
311
|
+
lines.push(` ${chalk.cyan('→')} ${dim.recommendation}`);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
return lines.join('\n');
|
|
315
|
+
}
|
|
316
|
+
function formatQuickWinsSection(quickWins) {
|
|
317
|
+
const lines = [];
|
|
318
|
+
lines.push(chalk.bold.yellow('⚡ Quick Wins (High Impact, Low Effort)'));
|
|
319
|
+
lines.push('─'.repeat(70));
|
|
320
|
+
quickWins.slice(0, 5).forEach((win, idx) => {
|
|
321
|
+
lines.push('');
|
|
322
|
+
lines.push(`${chalk.bold(`${idx + 1}.`)} ${chalk.yellow(win.issue)}`);
|
|
323
|
+
lines.push(` ${chalk.dim(`Impact: ${win.impact} · Effort: ${win.effort}`)}`);
|
|
324
|
+
lines.push(` ${chalk.cyan('→')} ${win.fix}`);
|
|
325
|
+
});
|
|
326
|
+
return lines.join('\n');
|
|
327
|
+
}
|
|
328
|
+
export function formatDetailedIssues(issues) {
|
|
329
|
+
const lines = [];
|
|
330
|
+
lines.push(chalk.bold('⚠️ All Issues'));
|
|
331
|
+
lines.push('─'.repeat(70));
|
|
332
|
+
// Group by severity
|
|
333
|
+
const grouped = {
|
|
334
|
+
critical: issues.filter(i => i.severity === 'critical'),
|
|
335
|
+
high: issues.filter(i => i.severity === 'high'),
|
|
336
|
+
medium: issues.filter(i => i.severity === 'medium'),
|
|
337
|
+
low: issues.filter(i => i.severity === 'low'),
|
|
338
|
+
};
|
|
339
|
+
// Stats
|
|
340
|
+
lines.push('');
|
|
341
|
+
lines.push(chalk.bold('Issue Count by Severity:'));
|
|
342
|
+
lines.push(` Critical: ${chalk.red.bold(grouped.critical.length)}`);
|
|
343
|
+
lines.push(` High: ${chalk.yellow.bold(grouped.high.length)}`);
|
|
344
|
+
lines.push(` Medium: ${chalk.blue.bold(grouped.medium.length)}`);
|
|
345
|
+
lines.push(` Low: ${chalk.dim(grouped.low.length)}`);
|
|
346
|
+
// Show all issues by severity
|
|
347
|
+
for (const [severity, severityIssues] of Object.entries(grouped)) {
|
|
348
|
+
if (severityIssues.length === 0)
|
|
349
|
+
continue;
|
|
350
|
+
lines.push('');
|
|
351
|
+
lines.push(chalk.bold(`${severity.toUpperCase()} Issues:`));
|
|
352
|
+
severityIssues.forEach((issue, idx) => {
|
|
353
|
+
const icon = severity === 'critical' ? '🔴' :
|
|
354
|
+
severity === 'high' ? '🟠' :
|
|
355
|
+
severity === 'medium' ? '🟡' : '🔵';
|
|
356
|
+
lines.push('');
|
|
357
|
+
lines.push(`${icon} ${idx + 1}. ${chalk.bold(issue.message || issue.title)}`);
|
|
358
|
+
lines.push(` ${chalk.dim(`Category: ${issue.category} · Impact: ${issue.impact}`)}`);
|
|
359
|
+
if (issue.evidence) {
|
|
360
|
+
const evidenceText = typeof issue.evidence === 'string' ? issue.evidence : issue.evidence.join(', ');
|
|
361
|
+
lines.push(` ${chalk.dim(evidenceText.substring(0, 100))}${evidenceText.length > 100 ? '...' : ''}`);
|
|
362
|
+
}
|
|
363
|
+
if (issue.element) {
|
|
364
|
+
lines.push(` ${chalk.dim(issue.element.substring(0, 100))}${issue.element.length > 100 ? '...' : ''}`);
|
|
365
|
+
}
|
|
366
|
+
lines.push(` ${chalk.cyan('💡 Fix:')} ${issue.suggested_fix || issue.remediation}`);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
return lines.join('\n');
|
|
370
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ai-lighthouse/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI Lighthouse CLI - Audit websites for AI readiness",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ai-lighthouse": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "tsx src/index.ts",
|
|
11
|
+
"build": "echo 'Build skipped - using tsx runtime'",
|
|
12
|
+
"check-types": "tsc --noEmit",
|
|
13
|
+
"cli": "node --loader tsx src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"lighthouse",
|
|
18
|
+
"audit",
|
|
19
|
+
"seo",
|
|
20
|
+
"accessibility",
|
|
21
|
+
"llm"
|
|
22
|
+
],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@ai-lighthouse/scanner": "workspace:*",
|
|
27
|
+
"chalk": "^5.3.0",
|
|
28
|
+
"commander": "^12.1.0",
|
|
29
|
+
"html-pdf-node": "^1.0.8",
|
|
30
|
+
"ink": "^6.6.0",
|
|
31
|
+
"ink-big-text": "^2.0.0",
|
|
32
|
+
"ink-box": "^2.0.0",
|
|
33
|
+
"ink-gradient": "^3.0.0",
|
|
34
|
+
"ink-link": "^5.0.0",
|
|
35
|
+
"ink-select-input": "^6.2.0",
|
|
36
|
+
"ink-spinner": "^5.0.0",
|
|
37
|
+
"ink-table": "^3.1.0",
|
|
38
|
+
"ink-text-input": "^6.0.0",
|
|
39
|
+
"open": "^10.1.0",
|
|
40
|
+
"ora": "^8.1.1",
|
|
41
|
+
"react": "19.2.0",
|
|
42
|
+
"react-devtools": "^7.0.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.10.1",
|
|
46
|
+
"tsx": "^4.21.0",
|
|
47
|
+
"typescript": "5.9.2"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { analyzeUrlWithRules } from '@ai-lighthouse/scanner';
|
|
3
|
+
import { calculateAIReadiness, exportAuditReport } from '@ai-lighthouse/scanner';
|
|
4
|
+
import type { ScanOptions } from '@ai-lighthouse/scanner';
|
|
5
|
+
import { render } from 'ink';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { AuditReportUI } from '../ui/AuditReportUI.js';
|
|
8
|
+
|
|
9
|
+
interface AuditOptions {
|
|
10
|
+
output?: string;
|
|
11
|
+
rules?: string;
|
|
12
|
+
depth?: number;
|
|
13
|
+
pages?: string;
|
|
14
|
+
cacheTtl?: number;
|
|
15
|
+
threshold?: number;
|
|
16
|
+
maxChunkTokens?: number;
|
|
17
|
+
chunkingStrategy?: 'auto' | 'heading-based' | 'paragraph-based';
|
|
18
|
+
enableChunking?: boolean;
|
|
19
|
+
enableExtractability?: boolean;
|
|
20
|
+
enableHallucination?: boolean;
|
|
21
|
+
enableLlm?: boolean;
|
|
22
|
+
minImpact?: number;
|
|
23
|
+
minConfidence?: number;
|
|
24
|
+
maxIssues?: number;
|
|
25
|
+
llmProvider?: string;
|
|
26
|
+
llmModel?: string;
|
|
27
|
+
llmBaseUrl?: string;
|
|
28
|
+
llmApiKey?: string;
|
|
29
|
+
interactive?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function auditInteractiveCommand(program: Command) {
|
|
33
|
+
program
|
|
34
|
+
.command('audit-interactive')
|
|
35
|
+
.description('Audit a website for AI readiness with interactive UI')
|
|
36
|
+
.argument('<url>', 'URL to audit')
|
|
37
|
+
.option('-r, --rules <preset>', 'Rule preset: default, strict, minimal', 'default')
|
|
38
|
+
.option('-d, --depth <number>', 'Crawl depth (for multi-page audits)', parseInt, 1)
|
|
39
|
+
.option('-p, --pages <urls>', 'Comma-separated list of specific pages to audit')
|
|
40
|
+
.option('--cache-ttl <seconds>', 'Cache TTL in seconds to avoid re-fetching', parseInt)
|
|
41
|
+
.option('--threshold <score>', 'Minimum score threshold (exit 1 if below)', parseInt)
|
|
42
|
+
.option('--max-chunk-tokens <number>', 'Maximum tokens per content chunk', parseInt, 1200)
|
|
43
|
+
.option('--chunking-strategy <strategy>', 'Chunking strategy: auto, heading-based, paragraph-based', 'auto')
|
|
44
|
+
.option('--enable-chunking', 'Enable detailed content chunking analysis', false)
|
|
45
|
+
.option('--enable-extractability', 'Enable extractability mapping', false)
|
|
46
|
+
.option('--enable-hallucination', 'Enable hallucination detection', false)
|
|
47
|
+
.option('--enable-llm', 'Enable LLM comprehension analysis', false)
|
|
48
|
+
.option('--min-impact <number>', 'Minimum impact score to include', parseInt, 8)
|
|
49
|
+
.option('--min-confidence <number>', 'Minimum confidence to include (0-1)', parseFloat, 0.7)
|
|
50
|
+
.option('--max-issues <number>', 'Maximum issues to return', parseInt, 20)
|
|
51
|
+
.option('--llm-provider <provider>', 'LLM provider: openai, anthropic, ollama, local')
|
|
52
|
+
.option('--llm-model <model>', 'LLM model name')
|
|
53
|
+
.option('--llm-base-url <url>', 'LLM API base URL')
|
|
54
|
+
.option('--llm-api-key <key>', 'LLM API key')
|
|
55
|
+
.action(async (url: string, options: AuditOptions) => {
|
|
56
|
+
// Show loading UI
|
|
57
|
+
const { waitUntilExit, clear, rerender } = render(
|
|
58
|
+
React.createElement(AuditReportUI, {
|
|
59
|
+
url,
|
|
60
|
+
result: {},
|
|
61
|
+
aiReadiness: {},
|
|
62
|
+
loading: true,
|
|
63
|
+
currentStep: 'Starting audit...',
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
// Validate URL
|
|
69
|
+
const urlObj = new URL(url);
|
|
70
|
+
|
|
71
|
+
// Build scan options
|
|
72
|
+
const scanOptions: ScanOptions = {
|
|
73
|
+
maxChunkTokens: options.maxChunkTokens,
|
|
74
|
+
chunkingStrategy: options.chunkingStrategy,
|
|
75
|
+
enableChunking: options.enableChunking,
|
|
76
|
+
enableExtractability: options.enableExtractability,
|
|
77
|
+
enableHallucinationDetection: options.enableHallucination,
|
|
78
|
+
enableLLM: options.enableLlm,
|
|
79
|
+
minImpactScore: options.minImpact,
|
|
80
|
+
minConfidence: options.minConfidence,
|
|
81
|
+
maxIssues: options.maxIssues,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Configure LLM if enabled
|
|
85
|
+
if (options.enableLlm && options.llmProvider) {
|
|
86
|
+
scanOptions.llmConfig = {
|
|
87
|
+
provider: options.llmProvider as any,
|
|
88
|
+
model: options.llmModel,
|
|
89
|
+
baseUrl: options.llmBaseUrl,
|
|
90
|
+
apiKey: options.llmApiKey,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Update loading step
|
|
95
|
+
rerender(
|
|
96
|
+
React.createElement(AuditReportUI, {
|
|
97
|
+
url: urlObj.href,
|
|
98
|
+
result: {},
|
|
99
|
+
aiReadiness: {},
|
|
100
|
+
loading: true,
|
|
101
|
+
currentStep: 'Scanning page...',
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
// Run the audit
|
|
106
|
+
const result = await analyzeUrlWithRules(url, scanOptions);
|
|
107
|
+
|
|
108
|
+
// Update loading step
|
|
109
|
+
rerender(
|
|
110
|
+
React.createElement(AuditReportUI, {
|
|
111
|
+
url: urlObj.href,
|
|
112
|
+
result,
|
|
113
|
+
aiReadiness: {},
|
|
114
|
+
loading: true,
|
|
115
|
+
currentStep: 'Calculating AI readiness scores...',
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Calculate AI readiness
|
|
120
|
+
const aiReadiness = calculateAIReadiness(result);
|
|
121
|
+
|
|
122
|
+
// Clear loading and show results
|
|
123
|
+
clear();
|
|
124
|
+
const finalRender = render(
|
|
125
|
+
React.createElement(AuditReportUI, {
|
|
126
|
+
url: urlObj.href,
|
|
127
|
+
result,
|
|
128
|
+
aiReadiness,
|
|
129
|
+
loading: false,
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Wait for user to exit
|
|
134
|
+
await finalRender.waitUntilExit();
|
|
135
|
+
|
|
136
|
+
// Check threshold
|
|
137
|
+
if (options.threshold !== undefined) {
|
|
138
|
+
const overallScore = aiReadiness.overall;
|
|
139
|
+
if (overallScore !== undefined && overallScore < options.threshold) {
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
clear();
|
|
145
|
+
console.error('Audit failed:', error instanceof Error ? error.message : error);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|