indxel-cli 0.1.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/LICENSE +21 -0
- package/README.md +289 -0
- package/dist/bin.js +1135 -0
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1136 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/detect.ts","../src/templates.ts","../src/commands/check.ts","../src/scanner.ts","../src/formatter.ts","../src/store.ts","../src/commands/crawl.ts","../src/commands/keywords.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\nimport { checkCommand } from \"./commands/check.js\";\nimport { crawlCommand } from \"./commands/crawl.js\";\nimport { keywordsCommand } from \"./commands/keywords.js\";\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name(\"indxel\")\n .description(\"Infrastructure SEO developer-first. ESLint pour le SEO.\")\n .version(\"0.1.0\");\n\n program.addCommand(initCommand);\n program.addCommand(checkCommand);\n program.addCommand(crawlCommand);\n program.addCommand(keywordsCommand);\n\n return program;\n}\n\nexport { initCommand, checkCommand, crawlCommand, keywordsCommand };\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { detectProject } from \"../detect.js\";\nimport {\n seoConfigTemplate,\n sitemapTemplate,\n robotsTemplate,\n} from \"../templates.js\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Initialize indxel in your Next.js project\")\n .option(\"--cwd <path>\", \"Project directory\", process.cwd())\n .option(\"--force\", \"Overwrite existing files\", false)\n .action(async (opts) => {\n const cwd = opts.cwd;\n const spinner = ora(\"Detecting project...\").start();\n\n // 1. Detect project\n const project = await detectProject(cwd);\n\n if (!project.isNextJs) {\n spinner.fail(\"Not a Next.js project\");\n console.log(\n chalk.dim(\" indxel currently supports Next.js projects only.\"),\n );\n console.log(\n chalk.dim(\" Make sure you're in a directory with a next.config file.\"),\n );\n process.exit(1);\n }\n\n spinner.succeed(\n `Detected Next.js ${project.nextVersion ?? \"\"} (${project.usesAppRouter ? \"App Router\" : \"Pages Router\"})`,\n );\n\n const ext = project.isTypeScript ? \"ts\" : \"js\";\n const filesCreated: string[] = [];\n\n // 2. Generate seo.config.ts\n if (!project.hasSeoConfig || opts.force) {\n const configPath = join(cwd, `seo.config.${ext}`);\n await writeFile(configPath, seoConfigTemplate(project.isTypeScript), \"utf-8\");\n filesCreated.push(`seo.config.${ext}`);\n console.log(chalk.green(\" ✓\") + ` Generated seo.config.${ext}`);\n } else {\n console.log(chalk.dim(` - seo.config.${ext} already exists (skip)`));\n }\n\n // 3. Generate sitemap.ts\n if (!project.hasSitemap || opts.force) {\n const sitemapPath = join(cwd, project.appDir, `sitemap.${ext}`);\n await writeFile(sitemapPath, sitemapTemplate(project.isTypeScript), \"utf-8\");\n filesCreated.push(`${project.appDir}/sitemap.${ext}`);\n console.log(chalk.green(\" ✓\") + ` Generated ${project.appDir}/sitemap.${ext}`);\n } else {\n console.log(chalk.dim(` - sitemap already exists (skip)`));\n }\n\n // 4. Generate robots.ts\n if (!project.hasRobots || opts.force) {\n const robotsPath = join(cwd, project.appDir, `robots.${ext}`);\n await writeFile(robotsPath, robotsTemplate(project.isTypeScript), \"utf-8\");\n filesCreated.push(`${project.appDir}/robots.${ext}`);\n console.log(chalk.green(\" ✓\") + ` Generated ${project.appDir}/robots.${ext}`);\n } else {\n console.log(chalk.dim(` - robots already exists (skip)`));\n }\n\n // 5. Summary\n console.log(\"\");\n if (filesCreated.length > 0) {\n console.log(\n chalk.bold(` ${filesCreated.length} file${filesCreated.length > 1 ? \"s\" : \"\"} created.`),\n );\n } else {\n console.log(chalk.dim(\" Nothing to create — all files already exist.\"));\n console.log(chalk.dim(\" Use --force to overwrite.\"));\n }\n\n console.log(\"\");\n console.log(chalk.dim(\" Next steps:\"));\n console.log(chalk.dim(` 1. Edit seo.config.${ext} with your site details`));\n console.log(chalk.dim(\" 2. Run \") + chalk.bold(\"npx indxel check\") + chalk.dim(\" to audit your pages\"));\n console.log(\"\");\n });\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ProjectInfo {\n /** Root directory of the project */\n root: string;\n /** Whether this is a Next.js project */\n isNextJs: boolean;\n /** Next.js version if detected */\n nextVersion?: string;\n /** Whether it uses App Router (has src/app or app directory) */\n usesAppRouter: boolean;\n /** The app directory path (relative) */\n appDir: string;\n /** Whether TypeScript is used */\n isTypeScript: boolean;\n /** Whether seo.config.ts/js already exists */\n hasSeoConfig: boolean;\n /** Whether sitemap.ts/js exists */\n hasSitemap: boolean;\n /** Whether robots.ts/js exists */\n hasRobots: boolean;\n}\n\n/** Detect project type and configuration from the given directory. */\nexport async function detectProject(cwd: string): Promise<ProjectInfo> {\n const info: ProjectInfo = {\n root: cwd,\n isNextJs: false,\n usesAppRouter: false,\n appDir: \"app\",\n isTypeScript: false,\n hasSeoConfig: false,\n hasSitemap: false,\n hasRobots: false,\n };\n\n // Check for Next.js config files\n const nextConfigs = [\n \"next.config.ts\",\n \"next.config.js\",\n \"next.config.mjs\",\n \"next.config.cjs\",\n ];\n info.isNextJs = nextConfigs.some((f) => existsSync(join(cwd, f)));\n\n // Read Next.js version from package.json\n const pkgPath = join(cwd, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(await readFile(pkgPath, \"utf-8\"));\n const nextDep = pkg.dependencies?.next ?? pkg.devDependencies?.next;\n if (nextDep) {\n info.isNextJs = true;\n info.nextVersion = nextDep.replace(/[\\^~>=<]/g, \"\").trim();\n }\n } catch {\n // Ignore parse errors\n }\n }\n\n // Check for TypeScript\n info.isTypeScript =\n existsSync(join(cwd, \"tsconfig.json\")) ||\n existsSync(join(cwd, \"tsconfig.ts\"));\n\n // Detect App Router directory\n if (existsSync(join(cwd, \"src\", \"app\"))) {\n info.usesAppRouter = true;\n info.appDir = \"src/app\";\n } else if (existsSync(join(cwd, \"app\"))) {\n info.usesAppRouter = true;\n info.appDir = \"app\";\n }\n\n // Check for existing SEO files (check both .ts and .js regardless of project type)\n info.hasSeoConfig =\n existsSync(join(cwd, \"seo.config.ts\")) ||\n existsSync(join(cwd, \"seo.config.js\"));\n\n info.hasSitemap =\n existsSync(join(cwd, info.appDir, \"sitemap.ts\")) ||\n existsSync(join(cwd, info.appDir, \"sitemap.js\")) ||\n existsSync(join(cwd, info.appDir, \"sitemap.xml\"));\n\n info.hasRobots =\n existsSync(join(cwd, info.appDir, \"robots.ts\")) ||\n existsSync(join(cwd, info.appDir, \"robots.js\")) ||\n existsSync(join(cwd, info.appDir, \"robots.txt\"));\n\n return info;\n}\n","/** Generate the seo.config.ts template */\nexport function seoConfigTemplate(isTypeScript: boolean): string {\n if (isTypeScript) {\n return `import { defineSEO } from 'indxel'\n\nexport default defineSEO({\n siteName: 'My Site',\n siteUrl: 'https://example.com',\n titleTemplate: '%s | My Site',\n defaultDescription: 'A short description of your site for search engines.',\n defaultOGImage: '/og-image.png',\n locale: 'en_US',\n // twitter: {\n // handle: '@yourhandle',\n // cardType: 'summary_large_image',\n // },\n // organization: {\n // name: 'My Company',\n // logo: '/logo.png',\n // url: 'https://example.com',\n // },\n})\n`;\n }\n\n return `const { defineSEO } = require('indxel')\n\nmodule.exports = defineSEO({\n siteName: 'My Site',\n siteUrl: 'https://example.com',\n titleTemplate: '%s | My Site',\n defaultDescription: 'A short description of your site for search engines.',\n defaultOGImage: '/og-image.png',\n locale: 'en_US',\n})\n`;\n}\n\n/** Generate the sitemap.ts template */\nexport function sitemapTemplate(isTypeScript: boolean): string {\n if (isTypeScript) {\n return `import type { MetadataRoute } from 'next'\n\nexport default function sitemap(): MetadataRoute.Sitemap {\n const baseUrl = 'https://example.com'\n\n return [\n {\n url: baseUrl,\n lastModified: new Date(),\n changeFrequency: 'weekly',\n priority: 1,\n },\n // Add more pages here or generate dynamically:\n //\n // const posts = await getPosts()\n // return posts.map(post => ({\n // url: \\`\\${baseUrl}/blog/\\${post.slug}\\`,\n // lastModified: post.updatedAt,\n // changeFrequency: 'monthly',\n // priority: 0.7,\n // }))\n ]\n}\n`;\n }\n\n return `/** @returns {import('next').MetadataRoute.Sitemap} */\nexport default function sitemap() {\n const baseUrl = 'https://example.com'\n\n return [\n {\n url: baseUrl,\n lastModified: new Date(),\n changeFrequency: 'weekly',\n priority: 1,\n },\n ]\n}\n`;\n}\n\n/** Generate the robots.ts template */\nexport function robotsTemplate(isTypeScript: boolean): string {\n if (isTypeScript) {\n return `import type { MetadataRoute } from 'next'\n\nexport default function robots(): MetadataRoute.Robots {\n const baseUrl = 'https://example.com'\n\n return {\n rules: [\n {\n userAgent: '*',\n allow: '/',\n disallow: ['/api/', '/private/'],\n },\n ],\n sitemap: \\`\\${baseUrl}/sitemap.xml\\`,\n }\n}\n`;\n }\n\n return `/** @returns {import('next').MetadataRoute.Robots} */\nexport default function robots() {\n const baseUrl = 'https://example.com'\n\n return {\n rules: [\n {\n userAgent: '*',\n allow: '/',\n disallow: ['/api/', '/private/'],\n },\n ],\n sitemap: \\`\\${baseUrl}/sitemap.xml\\`,\n }\n}\n`;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { validateMetadata } from \"indxel\";\nimport { detectProject } from \"../detect.js\";\nimport { scanPages } from \"../scanner.js\";\nimport {\n formatPageResult,\n formatSummary,\n formatJSON,\n formatDiff,\n computeSummary,\n type CheckResult,\n} from \"../formatter.js\";\nimport { saveCheckResult, loadPreviousCheck } from \"../store.js\";\n\nexport const checkCommand = new Command(\"check\")\n .description(\"Audit SEO metadata for all pages in your project\")\n .option(\"--cwd <path>\", \"Project directory\", process.cwd())\n .option(\"--ci\", \"CI/CD mode — strict, exit 1 on any error\", false)\n .option(\"--diff\", \"Compare with previous check run\", false)\n .option(\"--json\", \"Output results as JSON\", false)\n .option(\"--strict\", \"Treat warnings as errors\", false)\n .action(async (opts) => {\n const cwd = opts.cwd;\n const isCI = opts.ci;\n const isStrict = opts.strict || isCI;\n const showDiff = opts.diff;\n const jsonOutput = opts.json;\n\n // 1. Detect project\n const spinner = ora(\"Detecting project...\").start();\n const project = await detectProject(cwd);\n\n if (!project.isNextJs) {\n spinner.fail(\"Not a Next.js project\");\n if (!jsonOutput) {\n console.log(chalk.dim(\" Run this command from a Next.js project root.\"));\n }\n process.exit(1);\n }\n\n if (!project.usesAppRouter) {\n spinner.fail(\"App Router not detected\");\n if (!jsonOutput) {\n console.log(chalk.dim(\" indxel requires Next.js App Router (src/app or app directory).\"));\n }\n process.exit(1);\n }\n\n // 2. Scan pages\n spinner.text = \"Scanning pages...\";\n const pages = await scanPages(cwd, project.appDir);\n\n if (pages.length === 0) {\n spinner.fail(\"No pages found\");\n if (!jsonOutput) {\n console.log(chalk.dim(` No page.tsx/ts files found in ${project.appDir}/`));\n }\n process.exit(1);\n }\n\n spinner.succeed(`Found ${pages.length} page${pages.length > 1 ? \"s\" : \"\"}`);\n\n // 3. Validate each page\n if (!jsonOutput) {\n console.log(\"\");\n console.log(chalk.bold(` Checking ${pages.length} pages...`));\n console.log(\"\");\n }\n\n const results: CheckResult[] = [];\n\n for (const page of pages) {\n const validation = validateMetadata(page.extractedMetadata, {\n strict: isStrict,\n });\n\n const result: CheckResult = { page, validation };\n results.push(result);\n\n if (!jsonOutput) {\n console.log(formatPageResult(result));\n }\n }\n\n // 4. Compute summary\n const summary = computeSummary(results);\n\n // 5. Save results for future diff\n await saveCheckResult(cwd, summary);\n\n // 6. Show diff if requested\n if (showDiff && !jsonOutput) {\n const previous = await loadPreviousCheck(cwd);\n if (previous) {\n console.log(formatDiff(summary, previous.summary));\n } else {\n console.log(chalk.dim(\"\\n No previous check found. Run again to see a diff.\\n\"));\n }\n }\n\n // 7. Output\n if (jsonOutput) {\n console.log(formatJSON(summary));\n } else {\n console.log(formatSummary(summary));\n }\n\n // 8. Exit code (non-zero on errors for both CI and interactive use)\n if (summary.criticalErrors > 0) {\n process.exit(1);\n }\n });\n","import { readFile } from \"node:fs/promises\";\nimport { join, relative, dirname, sep } from \"node:path\";\nimport { glob } from \"glob\";\nimport type { ResolvedMetadata } from \"indxel\";\n\nexport interface PageInfo {\n /** File path relative to project root */\n filePath: string;\n /** Route path (e.g., \"/blog/[slug]\") */\n route: string;\n /** Whether the page exports metadata or generateMetadata */\n hasMetadata: boolean;\n /** Whether the page exports generateMetadata (dynamic) */\n hasDynamicMetadata: boolean;\n /** Extracted static metadata fields (best effort from source parsing) */\n extractedMetadata: ResolvedMetadata;\n}\n\n/**\n * Scan the app directory for all page files and extract metadata info.\n * This does static analysis of the source code (no build required).\n */\nexport async function scanPages(\n projectRoot: string,\n appDir: string,\n): Promise<PageInfo[]> {\n const appDirFull = join(projectRoot, appDir);\n\n // Find all page.tsx/page.ts/page.jsx/page.js files\n const pageFiles = await glob(\"**/page.{tsx,ts,jsx,js}\", {\n cwd: appDirFull,\n ignore: [\"**/node_modules/**\", \"**/_*/**\"],\n });\n\n const pages: PageInfo[] = [];\n\n for (const file of pageFiles) {\n const fullPath = join(appDirFull, file);\n const content = await readFile(fullPath, \"utf-8\");\n const route = filePathToRoute(file);\n\n const page: PageInfo = {\n filePath: join(appDir, file),\n route,\n hasMetadata: false,\n hasDynamicMetadata: false,\n extractedMetadata: createEmptyMetadata(),\n };\n\n // Check for metadata exports\n page.hasDynamicMetadata = hasExport(content, \"generateMetadata\");\n page.hasMetadata = page.hasDynamicMetadata || hasExport(content, \"metadata\");\n\n // Extract static metadata (best effort)\n page.extractedMetadata = extractStaticMetadata(content);\n\n pages.push(page);\n }\n\n // Also check layout files for metadata\n const layoutFiles = await glob(\"**/layout.{tsx,ts,jsx,js}\", {\n cwd: appDirFull,\n ignore: [\"**/node_modules/**\", \"**/_*/**\"],\n });\n\n for (const file of layoutFiles) {\n const fullPath = join(appDirFull, file);\n const content = await readFile(fullPath, \"utf-8\");\n const route = filePathToRoute(file).replace(/\\/layout$/, \"\") || \"/\";\n\n // Check if the root layout has metadata (common pattern)\n const hasMetadataExport = hasExport(content, \"metadata\") || hasExport(content, \"generateMetadata\");\n if (hasMetadataExport) {\n // Enrich matching pages with layout metadata awareness\n const layoutMeta = extractStaticMetadata(content);\n for (const page of pages) {\n if (page.route.startsWith(route) || route === \"/\") {\n // Merge layout metadata as fallback (page-level takes precedence)\n mergeMetadata(page.extractedMetadata, layoutMeta);\n if (!page.hasMetadata) {\n page.hasMetadata = true;\n }\n }\n }\n }\n }\n\n return pages.sort((a, b) => a.route.localeCompare(b.route));\n}\n\n/** Convert a file path like \"blog/[slug]/page.tsx\" to route \"/blog/[slug]\" */\nfunction filePathToRoute(filePath: string): string {\n const dir = dirname(filePath);\n if (dir === \".\") return \"/\";\n // Normalize separators and add leading slash\n const route = \"/\" + dir.split(sep).join(\"/\");\n // Remove route groups like (marketing)\n return route.replace(/\\/\\([^)]+\\)/g, \"\") || \"/\";\n}\n\n/** Check if source code exports a given name */\nfunction hasExport(source: string, name: string): boolean {\n // Match: export const metadata, export async function generateMetadata, export function generateMetadata\n const patterns = [\n new RegExp(`export\\\\s+(const|let|var)\\\\s+${name}\\\\b`),\n new RegExp(`export\\\\s+(async\\\\s+)?function\\\\s+${name}\\\\b`),\n new RegExp(`export\\\\s+\\\\{[^}]*\\\\b${name}\\\\b[^}]*\\\\}`),\n ];\n return patterns.some((p) => p.test(source));\n}\n\n/**\n * Extract metadata from static `export const metadata = { ... }` patterns.\n * This is best-effort source code parsing (not AST — fast and simple).\n */\nfunction extractStaticMetadata(source: string): ResolvedMetadata {\n const meta = createEmptyMetadata();\n\n // Extract title from metadata object\n const titleMatch = source.match(\n /title\\s*:\\s*(?:[\"'`]([^\"'`]+)[\"'`]|`([^`]*)`)/,\n );\n if (titleMatch) {\n meta.title = titleMatch[1] ?? titleMatch[2] ?? null;\n }\n\n // Extract description\n const descMatch = source.match(\n /description\\s*:\\s*(?:[\"'`]([^\"'`]+)[\"'`]|`([^`]*)`)/,\n );\n if (descMatch) {\n meta.description = descMatch[1] ?? descMatch[2] ?? null;\n }\n\n // Check for openGraph object\n if (/openGraph\\s*:\\s*\\{/.test(source)) {\n // Extract OG title\n const ogTitleMatch = source.match(\n /openGraph\\s*:\\s*\\{[^}]*title\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/s,\n );\n if (ogTitleMatch) meta.ogTitle = ogTitleMatch[1];\n\n // Extract OG description\n const ogDescMatch = source.match(\n /openGraph\\s*:\\s*\\{[^}]*description\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/s,\n );\n if (ogDescMatch) meta.ogDescription = ogDescMatch[1];\n\n // Check for images\n if (/images\\s*:\\s*\\[/.test(source)) {\n meta.ogImage = \"[detected]\";\n }\n }\n\n // Check for twitter config\n if (/twitter\\s*:\\s*\\{/.test(source)) {\n const cardMatch = source.match(\n /card\\s*:\\s*[\"'`](summary|summary_large_image)[\"'`]/,\n );\n if (cardMatch) meta.twitterCard = cardMatch[1];\n }\n\n // Check for robots\n if (/robots\\s*:\\s*\\{/.test(source) || /robots\\s*:\\s*[\"'`]/.test(source)) {\n const robotsMatch = source.match(\n /robots\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/,\n );\n if (robotsMatch) meta.robots = robotsMatch[1];\n }\n\n // Check for alternates/canonical\n if (/alternates\\s*:\\s*\\{/.test(source)) {\n const canonicalMatch = source.match(\n /canonical\\s*:\\s*[\"'`]([^\"'`]+)[\"'`]/,\n );\n if (canonicalMatch) meta.canonical = canonicalMatch[1];\n }\n\n // Check for structured data (JSON-LD script tags)\n if (/application\\/ld\\+json/.test(source) || /generateLD/.test(source) || /JsonLD/.test(source)) {\n meta.structuredData = [{ \"@context\": \"https://schema.org\", \"@type\": \"detected\" }];\n }\n\n // Check for viewport\n if (/viewport\\s*[:=]/.test(source)) {\n meta.viewport = \"detected\";\n }\n\n // Check for icons/favicon\n if (/icons\\s*:\\s*\\{/.test(source) || /favicon/.test(source)) {\n meta.favicon = \"detected\";\n }\n\n return meta;\n}\n\nfunction createEmptyMetadata(): ResolvedMetadata {\n return {\n title: null,\n description: null,\n canonical: null,\n ogTitle: null,\n ogDescription: null,\n ogImage: null,\n ogType: null,\n twitterCard: null,\n twitterTitle: null,\n twitterDescription: null,\n robots: null,\n alternates: null,\n structuredData: null,\n viewport: null,\n favicon: null,\n };\n}\n\n/** Merge source metadata into target (target takes precedence if already set) */\nfunction mergeMetadata(target: ResolvedMetadata, source: ResolvedMetadata): void {\n for (const key of Object.keys(source) as (keyof ResolvedMetadata)[]) {\n if (target[key] === null || target[key] === undefined) {\n (target as Record<string, unknown>)[key] = source[key];\n }\n }\n}\n","import chalk from \"chalk\";\nimport type { ValidationResult } from \"indxel\";\nimport type { PageInfo } from \"./scanner.js\";\n\nexport interface CheckResult {\n page: PageInfo;\n validation: ValidationResult;\n}\n\nexport interface CheckSummary {\n results: CheckResult[];\n totalPages: number;\n passedPages: number;\n averageScore: number;\n grade: string;\n criticalErrors: number;\n}\n\n/** Format a single page check result for terminal output */\nexport function formatPageResult(result: CheckResult): string {\n const { page, validation } = result;\n const lines: string[] = [];\n\n const scoreColor = getScoreColor(validation.score);\n const icon = validation.errors.length > 0 ? chalk.red(\"x\") : chalk.green(\"✓\");\n\n lines.push(\n ` ${icon} ${chalk.bold(page.route)} ${scoreColor(`${validation.score}/100`)}`,\n );\n\n // Show errors\n for (const error of validation.errors) {\n lines.push(` ${chalk.red(\"x\")} ${error.message ?? error.name}`);\n }\n\n // Show warnings (only if there are also errors, to reduce noise)\n if (validation.errors.length > 0) {\n for (const warning of validation.warnings) {\n lines.push(` ${chalk.yellow(\"!\")} ${warning.message ?? warning.name}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Format the complete check summary for terminal output */\nexport function formatSummary(summary: CheckSummary): string {\n const lines: string[] = [];\n const { totalPages, passedPages, averageScore, criticalErrors } = summary;\n\n lines.push(\"\");\n lines.push(chalk.dim(\" ─────────────────────────────────────\"));\n lines.push(\"\");\n\n // Overall score\n const scoreColor = getScoreColor(averageScore);\n lines.push(\n ` Score: ${scoreColor(chalk.bold(`${averageScore}/100`))} (${summary.grade})`,\n );\n\n // Pages summary\n const pagesColor = passedPages === totalPages ? chalk.green : chalk.yellow;\n lines.push(\n ` Pages: ${pagesColor(`${passedPages}/${totalPages}`)} pass SEO validation`,\n );\n\n // Error count\n if (criticalErrors > 0) {\n lines.push(\"\");\n lines.push(\n chalk.red(` ${criticalErrors} critical issue${criticalErrors > 1 ? \"s\" : \"\"}. Fix before deploying.`),\n );\n } else {\n lines.push(\"\");\n lines.push(chalk.green(\" All pages pass. Ship it.\"));\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\n/** Format results for --json output */\nexport function formatJSON(summary: CheckSummary): string {\n return JSON.stringify(\n {\n score: summary.averageScore,\n grade: summary.grade,\n totalPages: summary.totalPages,\n passedPages: summary.passedPages,\n criticalErrors: summary.criticalErrors,\n pages: summary.results.map((r) => ({\n route: r.page.route,\n file: r.page.filePath,\n score: r.validation.score,\n grade: r.validation.grade,\n errors: r.validation.errors.map((e) => ({\n id: e.id,\n message: e.message,\n })),\n warnings: r.validation.warnings.map((w) => ({\n id: w.id,\n message: w.message,\n })),\n })),\n },\n null,\n 2,\n );\n}\n\n/** Format a diff between two check runs */\nexport function formatDiff(\n current: CheckSummary,\n previous: CheckSummary,\n): string {\n const lines: string[] = [];\n\n lines.push(\"\");\n lines.push(chalk.bold(\" SEO Diff:\"));\n lines.push(\"\");\n\n const scoreDelta = current.averageScore - previous.averageScore;\n const scoreArrow = scoreDelta > 0 ? chalk.green(`+${scoreDelta}`) : scoreDelta < 0 ? chalk.red(`${scoreDelta}`) : chalk.dim(\"0\");\n lines.push(\n ` Score: ${previous.averageScore} -> ${current.averageScore} (${scoreArrow})`,\n );\n lines.push(\"\");\n\n // Build route maps\n const prevMap = new Map(previous.results.map((r) => [r.page.route, r]));\n const currMap = new Map(current.results.map((r) => [r.page.route, r]));\n\n // Regressions\n const regressions: string[] = [];\n for (const [route, curr] of currMap) {\n const prev = prevMap.get(route);\n if (!prev) continue;\n if (curr.validation.score < prev.validation.score) {\n regressions.push(\n ` ${chalk.red(\"-\")} ${route} ${prev.validation.score} -> ${curr.validation.score}`,\n );\n }\n }\n\n // Improvements\n const improvements: string[] = [];\n for (const [route, curr] of currMap) {\n const prev = prevMap.get(route);\n if (!prev) continue;\n if (curr.validation.score > prev.validation.score) {\n improvements.push(\n ` ${chalk.green(\"+\")} ${route} ${prev.validation.score} -> ${curr.validation.score}`,\n );\n }\n }\n\n // New pages\n const newPages: string[] = [];\n for (const route of currMap.keys()) {\n if (!prevMap.has(route)) {\n newPages.push(` ${chalk.blue(\"+\")} ${route} ${chalk.dim(\"[new]\")}`);\n }\n }\n\n // Removed pages\n const removed: string[] = [];\n for (const route of prevMap.keys()) {\n if (!currMap.has(route)) {\n removed.push(` ${chalk.dim(\"-\")} ${route} ${chalk.dim(\"[removed]\")}`);\n }\n }\n\n if (regressions.length > 0) {\n lines.push(chalk.red(` REGRESSIONS (${regressions.length}):`));\n lines.push(...regressions);\n lines.push(\"\");\n }\n\n if (improvements.length > 0) {\n lines.push(chalk.green(` IMPROVEMENTS (${improvements.length}):`));\n lines.push(...improvements);\n lines.push(\"\");\n }\n\n if (newPages.length > 0) {\n lines.push(chalk.blue(` NEW PAGES (${newPages.length}):`));\n lines.push(...newPages);\n lines.push(\"\");\n }\n\n if (removed.length > 0) {\n lines.push(chalk.dim(` REMOVED (${removed.length}):`));\n lines.push(...removed);\n lines.push(\"\");\n }\n\n if (regressions.length === 0 && improvements.length === 0 && newPages.length === 0 && removed.length === 0) {\n lines.push(chalk.dim(\" No changes detected.\"));\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Color a score value based on its range */\nfunction getScoreColor(score: number): (text: string) => string {\n if (score >= 90) return chalk.green;\n if (score >= 70) return chalk.yellow;\n return chalk.red;\n}\n\n/** Compute summary from results */\nexport function computeSummary(results: CheckResult[]): CheckSummary {\n const totalPages = results.length;\n const passedPages = results.filter((r) => r.validation.errors.length === 0).length;\n const averageScore =\n totalPages > 0\n ? Math.round(results.reduce((sum, r) => sum + r.validation.score, 0) / totalPages)\n : 0;\n const criticalErrors = results.reduce((sum, r) => sum + r.validation.errors.length, 0);\n\n let grade: string;\n if (averageScore >= 90) grade = \"A\";\n else if (averageScore >= 80) grade = \"B\";\n else if (averageScore >= 70) grade = \"C\";\n else if (averageScore >= 60) grade = \"D\";\n else grade = \"F\";\n\n return { results, totalPages, passedPages, averageScore, grade, criticalErrors };\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { CheckSummary } from \"./formatter.js\";\n\nconst STORE_DIR = \".indxel\";\nconst LAST_CHECK_FILE = \"last-check.json\";\n\nexport interface StoredCheck {\n timestamp: string;\n summary: CheckSummary;\n}\n\n/** Save the current check results for future diff comparison */\nexport async function saveCheckResult(\n cwd: string,\n summary: CheckSummary,\n): Promise<void> {\n const storeDir = join(cwd, STORE_DIR);\n\n if (!existsSync(storeDir)) {\n await mkdir(storeDir, { recursive: true });\n }\n\n const stored: StoredCheck = {\n timestamp: new Date().toISOString(),\n summary: {\n ...summary,\n // Serialize results with minimal data needed for diff\n results: summary.results.map((r) => ({\n page: {\n filePath: r.page.filePath,\n route: r.page.route,\n hasMetadata: r.page.hasMetadata,\n hasDynamicMetadata: r.page.hasDynamicMetadata,\n extractedMetadata: r.page.extractedMetadata,\n },\n validation: r.validation,\n })),\n },\n };\n\n await writeFile(\n join(storeDir, LAST_CHECK_FILE),\n JSON.stringify(stored, null, 2),\n \"utf-8\",\n );\n}\n\n/** Load the previous check result (or null if none exists) */\nexport async function loadPreviousCheck(\n cwd: string,\n): Promise<StoredCheck | null> {\n const filePath = join(cwd, STORE_DIR, LAST_CHECK_FILE);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const data = await readFile(filePath, \"utf-8\");\n return JSON.parse(data) as StoredCheck;\n } catch {\n return null;\n }\n}\n\n/** Get the .indxel directory path */\nexport function getStoreDir(cwd: string): string {\n return join(cwd, STORE_DIR);\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n crawlSite,\n fetchSitemap,\n compareSitemap,\n fetchRobots,\n checkUrlsAgainstRobots,\n verifyAssets,\n} from \"indxel\";\nimport type { CrawledPage } from \"indxel\";\n\nexport const crawlCommand = new Command(\"crawl\")\n .description(\"Crawl a live site, audit every page, check sitemap, robots.txt, and assets\")\n .argument(\"<url>\", \"URL to start crawling (e.g., https://yoursite.com)\")\n .option(\"--max-pages <n>\", \"Maximum pages to crawl\", \"50\")\n .option(\"--max-depth <n>\", \"Maximum link depth\", \"5\")\n .option(\"--delay <ms>\", \"Delay between requests in ms\", \"200\")\n .option(\"--json\", \"Output results as JSON\", false)\n .option(\"--strict\", \"Treat warnings as errors\", false)\n .option(\"--skip-assets\", \"Skip asset verification\", false)\n .option(\"--skip-sitemap\", \"Skip sitemap check\", false)\n .option(\"--skip-robots\", \"Skip robots.txt check\", false)\n .option(\"--ignore <patterns>\", \"Comma-separated path patterns to exclude from analysis (e.g. /app/*,/admin/*)\")\n .option(\"--push\", \"Push results to Indxel dashboard\", false)\n .option(\"--api-key <key>\", \"API key for --push (or set INDXEL_API_KEY env var)\")\n .action(async (url: string, opts) => {\n const jsonOutput = opts.json;\n const maxPages = parseInt(opts.maxPages, 10);\n const maxDepth = parseInt(opts.maxDepth, 10);\n const delay = parseInt(opts.delay, 10);\n\n // Ensure URL has protocol\n if (!url.startsWith(\"http://\") && !url.startsWith(\"https://\")) {\n url = `https://${url}`;\n }\n\n if (!jsonOutput) {\n console.log(\"\");\n console.log(chalk.bold(` indxel crawl`) + chalk.dim(` — ${url}`));\n console.log(\"\");\n }\n\n // 1. Robots.txt\n let robotsResult = null;\n if (!opts.skipRobots) {\n const robotsSpinner = jsonOutput ? null : ora(\"Checking robots.txt...\").start();\n robotsResult = await fetchRobots(url);\n\n if (!jsonOutput) {\n if (robotsResult.found) {\n robotsSpinner!.succeed(\"robots.txt found\");\n for (const w of robotsResult.warnings) {\n console.log(chalk.yellow(` ⚠ ${w}`));\n }\n if (robotsResult.sitemapUrls.length > 0) {\n console.log(chalk.dim(` Sitemap references: ${robotsResult.sitemapUrls.join(\", \")}`));\n }\n } else {\n robotsSpinner!.warn(\"robots.txt not found\");\n for (const e of robotsResult.errors) {\n console.log(chalk.dim(` ${e}`));\n }\n }\n console.log(\"\");\n }\n }\n\n // 2. Crawl\n const crawlSpinner = jsonOutput ? null : ora(\"Crawling...\").start();\n let crawledCount = 0;\n\n // Parse ignore patterns\n const ignorePatterns: string[] = opts.ignore\n ? opts.ignore.split(\",\").map((p: string) => p.trim()).filter(Boolean)\n : [];\n\n const crawlResult = await crawlSite(url, {\n maxPages,\n maxDepth,\n delay,\n strict: opts.strict,\n ignorePatterns,\n onPageCrawled: (page: CrawledPage) => {\n crawledCount++;\n if (crawlSpinner) {\n crawlSpinner.text = `Crawling... ${crawledCount} pages (current: ${page.url})`;\n }\n },\n });\n\n if (!jsonOutput) {\n crawlSpinner!.succeed(`Crawled ${crawlResult.totalPages} pages in ${(crawlResult.durationMs / 1000).toFixed(1)}s`);\n console.log(\"\");\n\n // Page results\n for (const page of crawlResult.pages) {\n if (page.error) {\n console.log(chalk.red(` ✗ ${page.url}`) + chalk.dim(` — ${page.error}`));\n continue;\n }\n\n const scoreColor =\n page.validation.score >= 90\n ? chalk.green\n : page.validation.score >= 70\n ? chalk.yellow\n : chalk.red;\n const icon =\n page.validation.errors.length > 0 ? chalk.red(\"✗\") : chalk.green(\"✓\");\n\n console.log(\n ` ${icon} ${page.url} ${scoreColor(`${page.validation.score}/100`)}`,\n );\n\n for (const error of page.validation.errors) {\n console.log(chalk.red(` ✗ ${error.message ?? error.description}`));\n }\n for (const warning of page.validation.warnings) {\n console.log(chalk.yellow(` ⚠ ${warning.message ?? warning.description}`));\n }\n }\n\n console.log(\"\");\n }\n\n // 3. Sitemap check\n let sitemapComparison = null;\n if (!opts.skipSitemap) {\n const sitemapSpinner = jsonOutput ? null : ora(\"Checking sitemap.xml...\").start();\n const sitemapResult = await fetchSitemap(url);\n\n if (!jsonOutput) {\n if (sitemapResult.found) {\n sitemapSpinner!.succeed(`sitemap.xml found — ${sitemapResult.urls.length} URLs`);\n\n // Compare with crawled pages\n const crawledUrls = crawlResult.pages\n .filter((p) => !p.error)\n .map((p) => p.url);\n sitemapComparison = compareSitemap(\n sitemapResult.urls.map((u) => u.loc),\n crawledUrls,\n );\n\n if (sitemapComparison.inCrawlOnly.length > 0) {\n console.log(chalk.yellow(` ⚠ ${sitemapComparison.inCrawlOnly.length} crawled pages missing from sitemap:`));\n for (const u of sitemapComparison.inCrawlOnly.slice(0, 10)) {\n console.log(chalk.dim(` - ${u}`));\n }\n }\n if (sitemapComparison.inSitemapOnly.length > 0) {\n console.log(chalk.yellow(` ⚠ ${sitemapComparison.inSitemapOnly.length} sitemap URLs not reachable:`));\n for (const u of sitemapComparison.inSitemapOnly.slice(0, 10)) {\n console.log(chalk.dim(` - ${u}`));\n }\n }\n if (sitemapComparison.issues.length === 0) {\n console.log(chalk.green(` ✓ Sitemap matches crawled pages`));\n }\n } else {\n sitemapSpinner!.warn(\"sitemap.xml not found\");\n for (const e of sitemapResult.errors) {\n console.log(chalk.dim(` ${e}`));\n }\n }\n console.log(\"\");\n }\n }\n\n // 4. Robots.txt URL check\n let robotsBlockedPages = null;\n if (robotsResult?.found && robotsResult.directives.length > 0) {\n const crawledUrls = crawlResult.pages.filter((p) => !p.error).map((p) => p.url);\n robotsBlockedPages = checkUrlsAgainstRobots(\n robotsResult.directives,\n crawledUrls,\n );\n const blocked = robotsBlockedPages.filter((c) => c.blocked);\n\n if (!jsonOutput && blocked.length > 0) {\n console.log(chalk.yellow(` ⚠ ${blocked.length} crawled pages are blocked by robots.txt:`));\n for (const b of blocked) {\n console.log(chalk.dim(` - ${b.path} (${b.blockedBy})`));\n }\n console.log(\"\");\n }\n }\n\n // 5. Asset verification\n let assetResult = null;\n if (!opts.skipAssets) {\n const assetSpinner = jsonOutput ? null : ora(\"Verifying assets (og:image, favicon, ...)...\").start();\n\n const pagesForAssetCheck = crawlResult.pages\n .filter((p) => !p.error)\n .map((p) => ({ url: p.url, metadata: p.metadata }));\n assetResult = await verifyAssets(pagesForAssetCheck);\n\n if (!jsonOutput) {\n assetSpinner!.succeed(`Verified ${assetResult.totalChecked} assets`);\n\n const brokenAssets = assetResult.checks.filter((c) => !c.ok);\n const warningAssets = assetResult.checks.filter((c) => c.warning);\n\n for (const asset of brokenAssets) {\n console.log(\n chalk.red(` ✗ ${asset.type}`) +\n chalk.dim(` ${asset.url}`) +\n chalk.red(` — ${asset.error ?? `HTTP ${asset.status}`}`),\n );\n }\n for (const asset of warningAssets) {\n console.log(\n chalk.yellow(` ⚠ ${asset.type}`) +\n chalk.dim(` ${asset.url}`) +\n chalk.yellow(` — ${asset.warning}`),\n );\n }\n if (brokenAssets.length === 0 && warningAssets.length === 0) {\n console.log(chalk.green(` ✓ All assets respond correctly`));\n }\n console.log(\"\");\n }\n }\n\n // 6. Cross-page analysis\n if (!jsonOutput) {\n const a = crawlResult.analysis;\n\n // Duplicate titles\n if (a.duplicateTitles.length > 0) {\n console.log(chalk.bold(\"- Duplicate titles\"));\n for (const dup of a.duplicateTitles.slice(0, 5)) {\n console.log(chalk.red(` ✗ \"${dup.title.length > 60 ? dup.title.slice(0, 57) + \"...\" : dup.title}\"`) + chalk.dim(` (${dup.urls.length} pages)`));\n for (const u of dup.urls.slice(0, 3)) console.log(chalk.dim(` ${u}`));\n if (dup.urls.length > 3) console.log(chalk.dim(` ...and ${dup.urls.length - 3} more`));\n }\n if (a.duplicateTitles.length > 5) console.log(chalk.dim(` ...and ${a.duplicateTitles.length - 5} more groups`));\n console.log(\"\");\n }\n\n // Duplicate descriptions\n if (a.duplicateDescriptions.length > 0) {\n console.log(chalk.bold(\"- Duplicate descriptions\"));\n for (const dup of a.duplicateDescriptions.slice(0, 5)) {\n const desc = dup.description.length > 60 ? dup.description.slice(0, 57) + \"...\" : dup.description;\n console.log(chalk.red(` ✗ \"${desc}\"`) + chalk.dim(` (${dup.urls.length} pages)`));\n for (const u of dup.urls.slice(0, 3)) console.log(chalk.dim(` ${u}`));\n if (dup.urls.length > 3) console.log(chalk.dim(` ...and ${dup.urls.length - 3} more`));\n }\n if (a.duplicateDescriptions.length > 5) console.log(chalk.dim(` ...and ${a.duplicateDescriptions.length - 5} more groups`));\n console.log(\"\");\n }\n\n // H1 issues\n if (a.h1Issues.length > 0) {\n const missing = a.h1Issues.filter(h => h.issue === \"missing\");\n const multiple = a.h1Issues.filter(h => h.issue === \"multiple\");\n console.log(chalk.bold(\"- H1 heading issues\"));\n if (missing.length > 0) {\n console.log(chalk.red(` ✗ ${missing.length} pages missing H1`));\n for (const h of missing.slice(0, 5)) console.log(chalk.dim(` ${h.url}`));\n if (missing.length > 5) console.log(chalk.dim(` ...and ${missing.length - 5} more`));\n }\n if (multiple.length > 0) {\n console.log(chalk.yellow(` ⚠ ${multiple.length} pages with multiple H1s`));\n for (const h of multiple.slice(0, 5)) console.log(chalk.dim(` ${h.url} (${h.count} H1s)`));\n if (multiple.length > 5) console.log(chalk.dim(` ...and ${multiple.length - 5} more`));\n }\n console.log(\"\");\n }\n\n // Broken internal links\n if (a.brokenInternalLinks.length > 0) {\n console.log(chalk.bold(\"- Broken internal links\"));\n for (const bl of a.brokenInternalLinks.slice(0, 10)) {\n console.log(chalk.red(` ✗ ${bl.to}`) + chalk.dim(` ← linked from ${bl.from} (${bl.status})`));\n }\n if (a.brokenInternalLinks.length > 10) console.log(chalk.dim(` ...and ${a.brokenInternalLinks.length - 10} more`));\n console.log(\"\");\n }\n\n // Redirects\n if (a.redirects.length > 0) {\n console.log(chalk.bold(\"- Redirect chains\"));\n for (const r of a.redirects.slice(0, 10)) {\n console.log(chalk.yellow(` ⚠ ${r.url}`));\n for (const step of r.chain) console.log(chalk.dim(` ${step}`));\n }\n if (a.redirects.length > 10) console.log(chalk.dim(` ...and ${a.redirects.length - 10} more`));\n console.log(\"\");\n }\n\n // Thin content\n if (a.thinContentPages.length > 0) {\n const realThin = a.thinContentPages.filter(tc => !tc.isAppPage);\n const appThin = a.thinContentPages.filter(tc => tc.isAppPage);\n\n if (realThin.length > 0) {\n console.log(chalk.bold(\"- Thin content\") + chalk.dim(\" (< 200 words)\"));\n for (const tc of realThin.slice(0, 10)) {\n console.log(chalk.yellow(` ⚠ ${tc.url}`) + chalk.dim(` — ${tc.wordCount} words`));\n }\n if (realThin.length > 10) console.log(chalk.dim(` ...and ${realThin.length - 10} more`));\n console.log(\"\");\n }\n if (appThin.length > 0) {\n console.log(chalk.bold(\"- App/wizard pages\") + chalk.dim(\" (client-rendered, low word count expected)\"));\n for (const tc of appThin.slice(0, 5)) {\n console.log(chalk.dim(` ℹ ${tc.url} — ${tc.wordCount} words`));\n }\n if (appThin.length > 5) console.log(chalk.dim(` ...and ${appThin.length - 5} more`));\n console.log(\"\");\n }\n }\n\n // Orphan pages\n if (a.orphanPages.length > 0) {\n console.log(chalk.bold(\"- Orphan pages\") + chalk.dim(\" (0 internal links pointing to them)\"));\n for (const o of a.orphanPages.slice(0, 10)) console.log(chalk.yellow(` ⚠ ${o}`));\n if (a.orphanPages.length > 10) console.log(chalk.dim(` ...and ${a.orphanPages.length - 10} more`));\n console.log(\"\");\n }\n\n // Slowest pages\n if (a.slowestPages.length > 0 && a.slowestPages[0].responseTimeMs > 1000) {\n console.log(chalk.bold(\"- Slowest pages\"));\n for (const sp of a.slowestPages.filter(p => p.responseTimeMs > 1000).slice(0, 5)) {\n const color = sp.responseTimeMs > 3000 ? chalk.red : chalk.yellow;\n console.log(color(` ⚠ ${sp.url}`) + chalk.dim(` — ${(sp.responseTimeMs / 1000).toFixed(1)}s`));\n }\n console.log(\"\");\n }\n\n // Structured data summary\n if (a.structuredDataSummary.length > 0) {\n console.log(chalk.bold(\"- Structured data (JSON-LD)\"));\n for (const sd of a.structuredDataSummary) {\n console.log(chalk.green(` ✓ ${sd.type}`) + chalk.dim(` — ${sd.count} page${sd.count > 1 ? \"s\" : \"\"}`));\n }\n const pagesWithSD = crawlResult.pages.filter(p => !p.error && p.structuredDataTypes.length > 0).length;\n const pagesWithout = crawlResult.pages.filter(p => !p.error).length - pagesWithSD;\n if (pagesWithout > 0) {\n console.log(chalk.yellow(` ⚠ ${pagesWithout} pages without any structured data`));\n }\n console.log(\"\");\n } else {\n console.log(chalk.bold(\"- Structured data (JSON-LD)\"));\n console.log(chalk.red(` ✗ No structured data found on any page`));\n console.log(\"\");\n }\n }\n\n // 7. Summary\n if (jsonOutput) {\n console.log(\n JSON.stringify(\n {\n crawl: crawlResult,\n robots: robotsResult,\n sitemap: sitemapComparison,\n assets: assetResult,\n },\n null,\n 2,\n ),\n );\n } else {\n const scoreColor =\n crawlResult.averageScore >= 90\n ? chalk.green\n : crawlResult.averageScore >= 70\n ? chalk.yellow\n : chalk.red;\n\n console.log(chalk.bold(\" ─── Summary ───\"));\n console.log(\"\");\n console.log(` Pages crawled: ${chalk.bold(String(crawlResult.totalPages))}`);\n console.log(` Average score: ${scoreColor(chalk.bold(`${crawlResult.averageScore}/100`))} (${crawlResult.grade})`);\n console.log(` Errors: ${crawlResult.totalErrors > 0 ? chalk.red(String(crawlResult.totalErrors)) : chalk.green(\"0\")}`);\n console.log(` Warnings: ${crawlResult.totalWarnings > 0 ? chalk.yellow(String(crawlResult.totalWarnings)) : chalk.green(\"0\")}`);\n if (assetResult) {\n console.log(` Broken assets: ${assetResult.totalBroken > 0 ? chalk.red(String(assetResult.totalBroken)) : chalk.green(\"0\")}`);\n }\n if (crawlResult.skippedUrls.length > 0) {\n console.log(chalk.dim(` Skipped: ${crawlResult.skippedUrls.length} URLs (over limit)`));\n }\n console.log(\"\");\n }\n\n // 8. Push to dashboard\n if (opts.push) {\n const apiKey = opts.apiKey || process.env.INDXEL_API_KEY;\n if (!apiKey) {\n if (!jsonOutput) {\n console.log(chalk.red(\" ✗ --push requires an API key. Use --api-key or set INDXEL_API_KEY.\"));\n console.log(chalk.dim(\" Get your key at https://indxel.com/dashboard/settings\"));\n console.log(\"\");\n }\n } else {\n const pushSpinner = jsonOutput ? null : ora(\"Pushing results to Indxel...\").start();\n try {\n const pushUrl = process.env.INDXEL_API_URL || \"https://www.indxel.com\";\n const res = await fetch(`${pushUrl}/api/cli/push`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n crawl: crawlResult,\n robots: robotsResult,\n sitemap: sitemapComparison,\n assets: assetResult,\n }),\n });\n if (res.ok) {\n const data = (await res.json()) as { checkId?: string };\n if (pushSpinner) pushSpinner.succeed(`Pushed to dashboard — check ${data.checkId}`);\n } else {\n const data = (await res.json().catch(() => ({}))) as { error?: string };\n if (pushSpinner) pushSpinner.fail(`Push failed: ${data.error || res.statusText}`);\n }\n } catch (err) {\n if (pushSpinner) pushSpinner.fail(`Push failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (!jsonOutput) console.log(\"\");\n }\n }\n\n // Exit code\n if (crawlResult.totalErrors > 0) {\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { researchKeywords, crawlSite, analyzeContentGaps } from \"indxel\";\n\nexport const keywordsCommand = new Command(\"keywords\")\n .description(\"Research keyword opportunities and find content gaps\")\n .argument(\"<seed>\", \"Seed keyword or topic to research\")\n .option(\"--locale <locale>\", \"Language locale\", \"en\")\n .option(\"--country <country>\", \"Country code\", \"us\")\n .option(\"--site <url>\", \"Site URL to analyze content gaps against\")\n .option(\"--max-pages <n>\", \"Maximum pages to crawl for gap analysis\", \"30\")\n .option(\"--json\", \"Output results as JSON\", false)\n .action(async (seed: string, opts) => {\n const jsonOutput = opts.json;\n\n if (!jsonOutput) {\n console.log(\"\");\n console.log(chalk.bold(` indxel keywords`) + chalk.dim(` — \"${seed}\"`));\n console.log(\"\");\n }\n\n // 1. Keyword research\n const kwSpinner = jsonOutput ? null : ora(\"Researching keywords...\").start();\n const kwResult = await researchKeywords(seed, {\n locale: opts.locale,\n country: opts.country,\n });\n\n if (!jsonOutput) {\n kwSpinner!.succeed(`Found ${kwResult.totalKeywords} keywords`);\n console.log(\"\");\n\n if (kwResult.suggestions.length > 0) {\n console.log(chalk.bold(` Direct suggestions (${kwResult.suggestions.length})`));\n for (const s of kwResult.suggestions) {\n console.log(` ${chalk.hex(\"#F4A261\")(s.keyword)}`);\n }\n console.log(\"\");\n }\n\n if (kwResult.questions.length > 0) {\n console.log(chalk.bold(` Questions (${kwResult.questions.length})`));\n for (const q of kwResult.questions.slice(0, 20)) {\n console.log(` ${chalk.cyan(\"?\")} ${q.keyword}`);\n }\n console.log(\"\");\n }\n\n if (kwResult.longTail.length > 0) {\n console.log(chalk.bold(` Long-tail (${kwResult.longTail.length})`));\n for (const lt of kwResult.longTail.slice(0, 20)) {\n console.log(chalk.dim(` ${lt.keyword}`));\n }\n if (kwResult.longTail.length > 20) {\n console.log(chalk.dim(` ... and ${kwResult.longTail.length - 20} more`));\n }\n console.log(\"\");\n }\n }\n\n // 2. Content gap analysis (if site URL provided)\n let gapResult = null;\n if (opts.site) {\n let siteUrl = opts.site;\n if (!siteUrl.startsWith(\"http://\") && !siteUrl.startsWith(\"https://\")) {\n siteUrl = `https://${siteUrl}`;\n }\n\n const crawlSpinner = jsonOutput ? null : ora(`Crawling ${siteUrl} for gap analysis...`).start();\n const crawlResult = await crawlSite(siteUrl, {\n maxPages: parseInt(opts.maxPages, 10),\n delay: 200,\n });\n\n if (!jsonOutput) {\n crawlSpinner!.succeed(`Crawled ${crawlResult.totalPages} pages`);\n }\n\n const allKeywords = [\n ...kwResult.suggestions,\n ...kwResult.questions,\n ...kwResult.longTail,\n ];\n\n const existingPages = crawlResult.pages\n .filter((p) => !p.error)\n .map((p) => ({ url: p.url, metadata: p.metadata }));\n\n gapResult = analyzeContentGaps(allKeywords, existingPages);\n\n if (!jsonOutput) {\n console.log(\"\");\n console.log(\n chalk.bold(` Content coverage: `) +\n `${gapResult.totalCovered}/${gapResult.totalKeywords} keywords (${gapResult.coveragePercent}%)`,\n );\n console.log(\"\");\n\n if (gapResult.gaps.length > 0) {\n const highGaps = gapResult.gaps.filter((g) => g.relevance === \"high\");\n const medGaps = gapResult.gaps.filter((g) => g.relevance === \"medium\");\n\n if (highGaps.length > 0) {\n console.log(chalk.bold.red(` High priority gaps (${highGaps.length})`));\n for (const gap of highGaps.slice(0, 15)) {\n console.log(\n chalk.red(` ✗ `) +\n `\"${gap.keyword}\" → ` +\n chalk.dim(`${gap.suggestedType} at ${gap.suggestedPath}`),\n );\n }\n console.log(\"\");\n }\n\n if (medGaps.length > 0) {\n console.log(chalk.bold.yellow(` Medium priority gaps (${medGaps.length})`));\n for (const gap of medGaps.slice(0, 10)) {\n console.log(\n chalk.yellow(` ⚠ `) +\n `\"${gap.keyword}\" → ` +\n chalk.dim(`${gap.suggestedType} at ${gap.suggestedPath}`),\n );\n }\n console.log(\"\");\n }\n }\n\n if (gapResult.gaps.length === 0) {\n console.log(chalk.green(` ✓ All keyword opportunities are covered`));\n console.log(\"\");\n }\n }\n }\n\n // JSON output\n if (jsonOutput) {\n console.log(\n JSON.stringify(\n { keywords: kwResult, contentGaps: gapResult },\n null,\n 2,\n ),\n );\n }\n });\n"],"mappings":"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","names":["Command","join","join","Command","chalk","ora","readFile","join","chalk","existsSync","readFile","writeFile","join","Command","ora","chalk","Command","chalk","ora","Command","chalk","ora","crawlSite","Command"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "indxel-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for SEO validation in Next.js projects. Init, check, diff, CI/CD mode.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"indxel": "./dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"templates",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"dev": "tsup --watch",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"seo",
|
|
27
|
+
"cli",
|
|
28
|
+
"next.js",
|
|
29
|
+
"nextjs",
|
|
30
|
+
"metadata",
|
|
31
|
+
"validation",
|
|
32
|
+
"ci-cd",
|
|
33
|
+
"typescript",
|
|
34
|
+
"developer-tools",
|
|
35
|
+
"linter"
|
|
36
|
+
],
|
|
37
|
+
"author": "Indxel",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/indxel/indxel",
|
|
42
|
+
"directory": "packages/cli"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://indxel.com",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/indxel/indxel/issues"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"indxel": "^0.1.0",
|
|
53
|
+
"commander": "^13.0.0",
|
|
54
|
+
"chalk": "^5.4.0",
|
|
55
|
+
"ora": "^8.0.0",
|
|
56
|
+
"glob": "^11.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"tsup": "^8.0.0",
|
|
60
|
+
"typescript": "^5.7.0",
|
|
61
|
+
"vitest": "^3.0.0",
|
|
62
|
+
"@types/node": "^22.0.0"
|
|
63
|
+
}
|
|
64
|
+
}
|