agentsite-kit 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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/templates/registry.ts","../src/commands/serve.ts","../src/server/app.ts","../src/utils/access-control.ts","../src/web/dashboard.ts","../src/server/access-log.ts","../src/server/routes/search.ts","../src/server/routes/pages.ts","../src/server/routes/faq.ts","../src/server/routes/products.ts","../src/server/routes/docs.ts","../src/server/routes/articles.ts","../src/server/routes/pricing.ts","../src/server/routes/changelog.ts","../src/commands/update.ts","../src/change-detection/store.ts","../src/commands/mcp.ts","../src/mcp/server.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerInitCommand } from './commands/init.js';\nimport { registerScanCommand } from './commands/scan.js';\nimport { registerGenerateCommand } from './commands/generate.js';\nimport { registerServeCommand } from './commands/serve.js';\nimport { registerUpdateCommand } from './commands/update.js';\nimport { registerMcpCommand } from './commands/mcp.js';\n\nconst program = new Command();\n\nprogram\n .name('agentsite')\n .description('Make any website Agent-friendly')\n .version('1.0.0');\n\nregisterInitCommand(program);\nregisterScanCommand(program);\nregisterGenerateCommand(program);\nregisterServeCommand(program);\nregisterUpdateCommand(program);\nregisterMcpCommand(program);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport yaml from 'js-yaml';\nimport { log } from '../utils/logger.js';\nimport { normalizeUrl } from '../utils/url.js';\nimport { listTemplates, loadTemplate, applyTemplate } from '../templates/registry.js';\n\nfunction ask(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport function registerInitCommand(program: Command) {\n program\n .command('init')\n .description('Initialize AgentSite config for your website')\n .option('-t, --template <name>', 'Use an industry template (docs-site, blog, saas, knowledge-base, ecommerce, portfolio, api-docs, community)')\n .option('--list-templates', 'List available templates')\n .action(async (opts) => {\n // List templates\n if (opts.listTemplates) {\n const templates = listTemplates();\n if (templates.length === 0) {\n log.warn('No templates found.');\n return;\n }\n log.info('Available templates:');\n for (const t of templates) {\n console.log(` ${t.id.padEnd(20)} ${t.description}`);\n }\n return;\n }\n\n if (existsSync('agentsite.config.yaml')) {\n log.warn('agentsite.config.yaml already exists. Overwrite? (y/N)');\n const confirm = await ask('');\n if (confirm.toLowerCase() !== 'y') {\n log.info('Aborted.');\n return;\n }\n }\n\n const url = normalizeUrl(await ask('Site URL: '));\n const name = await ask('Site name: ');\n const description = await ask('Site description: ');\n\n // Build base config\n let config: Record<string, unknown> = {\n site: { url, name, description },\n scan: {\n maxPages: 100,\n concurrency: 3,\n delayMs: 200,\n include: ['**'],\n exclude: [],\n respectRobotsTxt: true,\n },\n output: {\n dir: '.agentsite',\n formats: ['llms-txt', 'agent-sitemap', 'agent-index', 'structured'],\n },\n server: {\n port: 3141,\n rateLimit: { max: 60, timeWindow: '1 minute' },\n accessLog: true,\n },\n access: {\n allowedPages: ['**'],\n blockedPages: [],\n allowedTypes: ['docs', 'faq', 'blog', 'product', 'pricing', 'about', 'contact', 'changelog'],\n summaryOnly: false,\n allowSearch: true,\n },\n };\n\n // Apply template if specified\n if (opts.template) {\n const template = loadTemplate(opts.template);\n if (!template) {\n log.error(`Template \"${opts.template}\" not found. Use --list-templates to see available templates.`);\n process.exit(1);\n }\n config = applyTemplate(config, template);\n log.info(`Applied template: ${template.name}`);\n }\n\n const yamlContent = yaml.dump(config, { lineWidth: -1, noRefs: true });\n writeFileSync('agentsite.config.yaml', yamlContent, 'utf-8');\n mkdirSync('.agentsite/cache/pages', { recursive: true });\n mkdirSync('.agentsite/data', { recursive: true });\n\n log.success('Created agentsite.config.yaml');\n log.success('Created .agentsite/ directory');\n log.info('Next: run `agentsite scan` to scan your site.');\n });\n}\n","import { readFileSync, existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, resolve } from 'node:path';\nimport yaml from 'js-yaml';\n\nexport interface TemplatePreset {\n id: string;\n name: string;\n description: string;\n config: Record<string, unknown>;\n}\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n// Works both in dev (src/templates/) and bundled (dist/) contexts\nconst PRESETS_DIR = existsSync(resolve(__dirname, '../../templates/presets'))\n ? resolve(__dirname, '../../templates/presets')\n : resolve(__dirname, '../templates/presets');\n\nconst BUILTIN_TEMPLATES = ['docs-site', 'blog', 'saas', 'knowledge-base', 'ecommerce', 'portfolio', 'api-docs', 'community'];\n\nexport function listTemplates(): TemplatePreset[] {\n const templates: TemplatePreset[] = [];\n for (const id of BUILTIN_TEMPLATES) {\n const preset = loadTemplate(id);\n if (preset) templates.push(preset);\n }\n return templates;\n}\n\nexport function loadTemplate(id: string): TemplatePreset | null {\n const filePath = resolve(PRESETS_DIR, `${id}.yaml`);\n if (!existsSync(filePath)) return null;\n\n const raw = readFileSync(filePath, 'utf-8');\n const parsed = yaml.load(raw) as Record<string, unknown>;\n\n return {\n id,\n name: (parsed.name as string) ?? id,\n description: (parsed.description as string) ?? '',\n config: (parsed.config as Record<string, unknown>) ?? {},\n };\n}\n\nexport function applyTemplate(baseConfig: Record<string, unknown>, template: TemplatePreset): Record<string, unknown> {\n return deepMerge(baseConfig, template.config);\n}\n\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {\n const result = { ...target };\n for (const key of Object.keys(source)) {\n const sv = source[key];\n const tv = target[key];\n if (sv && typeof sv === 'object' && !Array.isArray(sv) && tv && typeof tv === 'object' && !Array.isArray(tv)) {\n result[key] = deepMerge(tv as Record<string, unknown>, sv as Record<string, unknown>);\n } else {\n result[key] = sv;\n }\n }\n return result;\n}\n","import { Command } from 'commander';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { loadConfig, toSlug } from '../config/loader.js';\nimport { createApp, type ServerData } from '../server/app.js';\nimport { log } from '../utils/logger.js';\nimport type { ScanResult } from '../types/page.js';\n\nfunction loadJson(path: string): unknown[] {\n if (!existsSync(path)) return [];\n return JSON.parse(readFileSync(path, 'utf-8'));\n}\n\nfunction loadSiteData(outDir: string): { scanResult: ScanResult; data: ServerData } | null {\n const scanPath = `${outDir}/scan-result.json`;\n if (!existsSync(scanPath)) return null;\n\n const scanResult: ScanResult = JSON.parse(readFileSync(scanPath, 'utf-8'));\n const data: ServerData = {\n pages: scanResult.pages,\n docs: loadJson(`${outDir}/data/docs.json`) as ServerData['docs'],\n faq: loadJson(`${outDir}/data/faq.json`) as ServerData['faq'],\n products: loadJson(`${outDir}/data/products.json`) as ServerData['products'],\n articles: loadJson(`${outDir}/data/articles.json`) as ServerData['articles'],\n pricing: loadJson(`${outDir}/data/pricing.json`) as ServerData['pricing'],\n changelog: loadJson(`${outDir}/data/changelog.json`) as ServerData['changelog'],\n };\n\n return { scanResult, data };\n}\n\nexport function registerServeCommand(program: Command) {\n program\n .command('serve')\n .description('Start the Agent-friendly API server')\n .option('-p, --port <port>', 'Port number')\n .action(async (opts) => {\n const config = loadConfig();\n const outDir = config.output.dir;\n\n // Load primary site data (allow empty data so server can still boot)\n const primary = loadSiteData(outDir);\n const data: ServerData = primary?.data ?? {\n pages: [], docs: [], faq: [], products: [],\n articles: [], pricing: [], changelog: [],\n };\n if (!primary) {\n log.warn('No scan data found. Server starting with empty data.');\n log.warn('Use the Dashboard Operations panel or run `agentsite scan && agentsite generate` to populate.');\n }\n\n const port = parseInt(opts.port, 10) || config.server.port;\n const app = await createApp(config, data);\n\n // Multi-site: register additional site routes\n if (config.resolvedSites.length > 1) {\n for (const siteEntry of config.resolvedSites) {\n const slug = toSlug(siteEntry.site.name);\n const siteOutDir = siteEntry.output.dir;\n const siteData = loadSiteData(siteOutDir);\n if (siteData) {\n // Register site-prefixed API endpoints\n app.get(`/api/${slug}/pages-data`, async () => ({\n siteUrl: siteData.scanResult.siteUrl,\n scannedAt: siteData.scanResult.scannedAt,\n totalPages: siteData.scanResult.totalPages,\n pages: siteData.data.pages,\n }));\n app.get(`/api/${slug}/search`, async (req) => {\n const query = req.query as Record<string, string>;\n return { site: slug, query: query.q, results: [] };\n });\n app.get(`/api/${slug}/docs`, async () => siteData.data.docs);\n app.get(`/api/${slug}/faq`, async () => siteData.data.faq);\n app.get(`/api/${slug}/products`, async () => siteData.data.products);\n app.get(`/api/${slug}/articles`, async () => siteData.data.articles);\n app.get(`/api/${slug}/pricing`, async () => siteData.data.pricing);\n app.get(`/api/${slug}/changelog`, async () => siteData.data.changelog);\n }\n }\n }\n\n // Sites list endpoint\n app.get('/api/sites', async () => {\n return {\n sites: config.resolvedSites.map((s) => ({\n name: s.site.name,\n slug: toSlug(s.site.name),\n url: s.site.url,\n description: s.site.description,\n outDir: s.output.dir,\n })),\n };\n });\n\n await app.listen({ port, host: '0.0.0.0' });\n log.success(`API server running at http://localhost:${port}`);\n log.info('Endpoints:');\n console.log(' GET /api/health');\n console.log(' GET /api/search?q=keyword');\n console.log(' GET /api/pages/:id');\n console.log(' GET /api/faq');\n console.log(' GET /api/products');\n console.log(' GET /api/docs');\n console.log(' GET /api/articles');\n console.log(' GET /api/pricing');\n console.log(' GET /api/changelog');\n console.log(' GET /api/stats');\n console.log(' GET /api/config');\n console.log(' GET /api/files');\n console.log(' GET /api/access-log');\n console.log(' GET /api/sites');\n if (config.resolvedSites.length > 1) {\n for (const s of config.resolvedSites) {\n console.log(` GET /api/${toSlug(s.site.name)}/* (multi-site)`);\n }\n }\n });\n}\n","import Fastify from 'fastify';\nimport cors from '@fastify/cors';\nimport rateLimit from '@fastify/rate-limit';\nimport type { ValidatedConfig } from '../config/schema.js';\nimport type { ScannedPage } from '../types/page.js';\nimport { isPageAllowed } from '../utils/access-control.js';\nimport { dashboardHtml } from '../web/dashboard.js';\nimport { AccessLogger } from './access-log.js';\nimport { registerSearchRoute } from './routes/search.js';\nimport { registerPagesRoute } from './routes/pages.js';\nimport { registerFaqRoute } from './routes/faq.js';\nimport { registerProductsRoute } from './routes/products.js';\nimport { registerDocsRoute } from './routes/docs.js';\nimport { registerArticlesRoute } from './routes/articles.js';\nimport { registerPricingRoute } from './routes/pricing.js';\nimport { registerChangelogRoute } from './routes/changelog.js';\n\nexport interface ServerData {\n docs: unknown[];\n faq: unknown[];\n products: unknown[];\n articles: unknown[];\n pricing: unknown[];\n changelog: unknown[];\n pages: ScannedPage[];\n}\n\nexport async function createApp(config: ValidatedConfig, data: ServerData) {\n const app = Fastify({ logger: false });\n\n await app.register(cors, { origin: true });\n await app.register(rateLimit, {\n max: config.server.rateLimit.max,\n timeWindow: config.server.rateLimit.timeWindow,\n });\n\n // Access logging\n let accessLogger: AccessLogger | undefined;\n if (config.server.accessLog) {\n accessLogger = new AccessLogger(config.output.dir);\n accessLogger.register(app);\n }\n\n // Filter pages based on access control rules\n const filteredPages = data.pages.filter(page => isPageAllowed(page, config));\n const filteredData = { ...data, pages: filteredPages };\n\n // Build simple inverted index for search\n const searchIndex = buildSearchIndex(filteredData);\n\n app.get('/api/health', async () => ({ ok: true }));\n\n // Access log endpoint\n app.get('/api/access-log', async (req) => {\n if (!accessLogger) return { entries: [], message: 'Access logging is disabled' };\n const query = req.query as Record<string, string>;\n const limit = parseInt(query.limit, 10) || 100;\n return { entries: accessLogger.getRecent(limit) };\n });\n\n // Stats endpoint\n app.get('/api/stats', async () => {\n const typeCounts: Record<string, number> = {};\n let totalWords = 0;\n for (const p of filteredData.pages) {\n typeCounts[p.type] = (typeCounts[p.type] ?? 0) + 1;\n totalWords += p.wordCount;\n }\n return {\n totalPages: filteredData.pages.length,\n totalWords,\n pageTypes: typeCounts,\n dataFiles: {\n docs: filteredData.docs.length,\n faq: filteredData.faq.length,\n products: filteredData.products.length,\n articles: filteredData.articles.length,\n pricing: filteredData.pricing.length,\n changelog: filteredData.changelog.length,\n },\n };\n });\n\n // Config endpoint (sanitized)\n app.get('/api/config', async () => {\n const sanitized = {\n site: config.site,\n scan: config.scan,\n output: config.output,\n server: { port: config.server.port, rateLimit: config.server.rateLimit, accessLog: config.server.accessLog },\n access: config.access,\n llm: config.llm ? { apiUrl: config.llm.apiUrl, model: config.llm.model, apiKey: '***' } : undefined,\n };\n return sanitized;\n });\n\n // Files endpoint\n app.get('/api/files', async () => {\n const { readFileSync, existsSync } = await import('node:fs');\n const outDir = config.output.dir;\n const files: { name: string; size: number; content?: string }[] = [];\n\n const textFiles = ['llms.txt'];\n const jsonFiles = ['agent-sitemap.json', 'agent-index.json', 'data/docs.json', 'data/faq.json', 'data/products.json', 'data/articles.json', 'data/pricing.json', 'data/changelog.json'];\n\n for (const f of textFiles) {\n const p = `${outDir}/${f}`;\n if (existsSync(p)) {\n const content = readFileSync(p, 'utf-8');\n files.push({ name: f, size: content.length, content });\n }\n }\n for (const f of jsonFiles) {\n const p = `${outDir}/${f}`;\n if (existsSync(p)) {\n const content = readFileSync(p, 'utf-8');\n files.push({ name: f, size: content.length, content });\n }\n }\n\n return { files };\n });\n\n // Web dashboard\n app.get('/', async (req, reply) => {\n reply.type('text/html').send(dashboardHtml);\n });\n\n app.get('/api/pages-data', async () => {\n return {\n siteUrl: filteredData.pages[0]?.url.split('/').slice(0, 3).join('/') || '',\n scannedAt: filteredData.pages[0]?.scannedAt || new Date().toISOString(),\n totalPages: filteredData.pages.length,\n pages: filteredData.pages,\n };\n });\n\n if (config.access.allowSearch) {\n registerSearchRoute(app, filteredData, searchIndex);\n }\n registerPagesRoute(app, filteredData, config);\n registerFaqRoute(app, filteredData);\n registerProductsRoute(app, filteredData);\n registerDocsRoute(app, filteredData);\n registerArticlesRoute(app, filteredData);\n registerPricingRoute(app, filteredData);\n registerChangelogRoute(app, filteredData);\n\n // Operation endpoints (rescan / regenerate)\n app.post('/api/rescan', async () => {\n try {\n const { runScan } = await import('../commands/scan.js');\n const result = await runScan();\n return { ok: true, message: `Rescan complete. ${result.totalPages} pages scanned.` };\n } catch (err) {\n return { ok: false, message: (err as Error).message };\n }\n });\n\n app.post('/api/regenerate', async () => {\n try {\n const { runGenerate } = await import('../commands/generate.js');\n await runGenerate();\n return { ok: true, message: 'Regeneration complete.' };\n } catch (err) {\n return { ok: false, message: (err as Error).message };\n }\n });\n\n return app;\n}\n\nexport type SearchIndex = Map<string, Set<number>>;\n\nfunction buildSearchIndex(data: ServerData): SearchIndex {\n const index = new Map<string, Set<number>>();\n\n data.pages.forEach((page, i) => {\n const text = `${page.title} ${page.summary} ${page.type}`.toLowerCase();\n const words = text.split(/\\W+/).filter((w) => w.length > 2);\n for (const word of words) {\n if (!index.has(word)) index.set(word, new Set());\n index.get(word)!.add(i);\n }\n });\n\n return index;\n}\n","import { minimatch } from 'minimatch';\nimport type { ValidatedConfig } from '../config/schema.js';\nimport type { ScannedPage } from '../types/page.js';\n\nexport function isPageAllowed(page: ScannedPage, config: ValidatedConfig): boolean {\n const { allowedPages, blockedPages, allowedTypes } = config.access;\n\n // Check blocked patterns first\n for (const pattern of blockedPages) {\n if (minimatch(page.url, pattern)) return false;\n }\n\n // Check allowed patterns\n let matchesAllowed = false;\n for (const pattern of allowedPages) {\n if (minimatch(page.url, pattern)) {\n matchesAllowed = true;\n break;\n }\n }\n if (!matchesAllowed) return false;\n\n // Check page type\n return allowedTypes.includes(page.type);\n}\n\nexport function filterPageContent(page: ScannedPage, config: ValidatedConfig): Partial<ScannedPage> {\n if (config.access.summaryOnly) {\n return {\n url: page.url,\n title: page.title,\n type: page.type,\n summary: page.summary,\n updatedAt: page.updatedAt,\n };\n }\n return page;\n}\n","export const dashboardHtml = `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>AgentSite Kit Dashboard</title>\n<style>\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,sans-serif;background:#f5f5f5;display:flex;min-height:100vh}\n.sidebar{width:220px;background:#1a1a2e;color:#fff;padding:20px 0;position:fixed;height:100vh;overflow-y:auto}\n.sidebar h1{font-size:16px;padding:0 20px 20px;border-bottom:1px solid #333}\n.sidebar nav{padding:10px 0}\n.sidebar a{display:block;padding:10px 20px;color:#aaa;text-decoration:none;font-size:14px;transition:all .2s}\n.sidebar a:hover,.sidebar a.active{background:#16213e;color:#fff}\n.sidebar a .icon{margin-right:8px}\n.main{margin-left:220px;flex:1;padding:20px;min-height:100vh}\n.header{background:#fff;padding:20px;border-radius:8px;margin-bottom:20px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}\nh2{font-size:20px;margin-bottom:5px}\n.subtitle{color:#666;font-size:14px}\n.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:20px}\n.card{background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}\n.card h3{font-size:14px;margin-bottom:8px;color:#666}\n.stat{font-size:28px;font-weight:bold;color:#0066cc}\n.table-wrap{background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 2px 4px rgba(0,0,0,0.1);margin-bottom:20px}\ntable{width:100%;border-collapse:collapse}\nth,td{padding:10px 12px;text-align:left;border-bottom:1px solid #eee;font-size:13px}\nth{background:#f9f9f9;font-weight:600}\n.badge{display:inline-block;padding:3px 8px;border-radius:4px;font-size:11px;font-weight:500}\n.badge-docs{background:#e3f2fd;color:#1976d2}\n.badge-faq{background:#f3e5f5;color:#7b1fa2}\n.badge-blog{background:#e8f5e9;color:#388e3c}\n.badge-product{background:#fff3e0;color:#f57c00}\n.badge-pricing{background:#fce4ec;color:#c2185b}\n.badge-changelog{background:#e0f2f1;color:#00796b}\n.badge-homepage{background:#f5f5f5;color:#616161}\n.badge-about{background:#ede7f6;color:#512da8}\n.badge-contact{background:#e8eaf6;color:#283593}\n.badge-unknown{background:#eceff1;color:#546e7a}\n.toolbar{display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap}\n.toolbar input,.toolbar select{padding:8px 12px;border:1px solid #ddd;border-radius:6px;font-size:13px}\n.toolbar input{flex:1;min-width:200px}\n.pre-wrap{background:#f8f8f8;border:1px solid #eee;border-radius:6px;padding:16px;font-family:monospace;font-size:12px;white-space:pre-wrap;word-break:break-all;max-height:500px;overflow-y:auto;margin-bottom:16px}\n.file-card{background:#fff;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1);margin-bottom:16px;overflow:hidden}\n.file-card .file-header{padding:12px 16px;background:#f9f9f9;font-weight:600;font-size:13px;display:flex;justify-content:space-between;cursor:pointer}\n.file-card .file-body{padding:16px;display:none}\n.file-card.open .file-body{display:block}\n.log-entry{display:grid;grid-template-columns:180px 60px 1fr 60px 80px;gap:8px;padding:8px 12px;border-bottom:1px solid #f0f0f0;font-size:12px;align-items:center}\n.log-entry:hover{background:#f9f9f9}\n.status-2xx{color:#388e3c}.status-4xx{color:#f57c00}.status-5xx{color:#c62828}\n.page-view{display:none}\n.page-view.active{display:block}\n.tab-bar{display:flex;gap:4px;margin-bottom:16px;border-bottom:2px solid #eee;padding-bottom:-2px}\n.tab{padding:8px 16px;cursor:pointer;font-size:13px;color:#666;border-bottom:2px solid transparent;margin-bottom:-2px}\n.tab.active{color:#0066cc;border-bottom-color:#0066cc}\n.site-switcher{padding:10px 20px;margin-top:10px}\n.site-switcher select{width:100%;padding:6px 8px;border-radius:4px;border:1px solid #444;background:#16213e;color:#fff;font-size:12px}\n</style>\n</head>\n<body>\n<div class=\"sidebar\">\n<h1>AgentSite Kit</h1>\n<div class=\"site-switcher\" id=\"siteSwitcher\" style=\"display:none\">\n<select id=\"siteSelect\"></select>\n</div>\n<nav>\n<a href=\"#/\" class=\"active\"><span class=\"icon\">&#9632;</span> Overview</a>\n<a href=\"#/pages\"><span class=\"icon\">&#9776;</span> Pages</a>\n<a href=\"#/files\"><span class=\"icon\">&#128196;</span> Files</a>\n<a href=\"#/config\"><span class=\"icon\">&#9881;</span> Config</a>\n<a href=\"#/logs\"><span class=\"icon\">&#128203;</span> Access Logs</a>\n<a href=\"#/sites\"><span class=\"icon\">&#127760;</span> Sites</a>\n<a href=\"#/export\"><span class=\"icon\">&#9654;</span> Operations</a>\n</nav>\n</div>\n<div class=\"main\">\n\n<!-- Overview Page -->\n<div class=\"page-view active\" id=\"page-overview\">\n<div class=\"header\"><h2>Overview</h2><p class=\"subtitle\">Site health at a glance</p></div>\n<div class=\"grid\" id=\"statsGrid\"></div>\n<div class=\"table-wrap\">\n<table><thead><tr><th>Title</th><th>Type</th><th>URL</th><th>Words</th></tr></thead>\n<tbody id=\"overviewTable\"></tbody></table>\n</div>\n</div>\n\n<!-- Pages Page -->\n<div class=\"page-view\" id=\"page-pages\">\n<div class=\"header\"><h2>Pages</h2><p class=\"subtitle\">All scanned pages</p></div>\n<div class=\"toolbar\">\n<input type=\"text\" id=\"pageSearch\" placeholder=\"Search pages...\">\n<select id=\"typeFilter\"><option value=\"\">All types</option></select>\n</div>\n<div class=\"table-wrap\">\n<table><thead><tr><th>Title</th><th>Type</th><th>URL</th><th>Words</th><th>Tags</th></tr></thead>\n<tbody id=\"pagesTable\"></tbody></table>\n</div>\n</div>\n\n<!-- Files Page -->\n<div class=\"page-view\" id=\"page-files\">\n<div class=\"header\"><h2>Generated Files</h2><p class=\"subtitle\">Preview output files</p></div>\n<div id=\"filesList\"></div>\n</div>\n\n<!-- Config Page -->\n<div class=\"page-view\" id=\"page-config\">\n<div class=\"header\"><h2>Configuration</h2><p class=\"subtitle\">Current AgentSite config (API keys hidden)</p></div>\n<div class=\"pre-wrap\" id=\"configContent\">Loading...</div>\n</div>\n\n<!-- Logs Page -->\n<div class=\"page-view\" id=\"page-logs\">\n<div class=\"header\"><h2>Access Logs</h2><p class=\"subtitle\">Recent API requests</p></div>\n<div class=\"grid\" id=\"logStats\"></div>\n<div class=\"table-wrap\" style=\"margin-top:16px\">\n<div class=\"log-entry\" style=\"font-weight:600;background:#f9f9f9\">\n<span>Timestamp</span><span>Method</span><span>Path</span><span>Status</span><span>Time</span>\n</div>\n<div id=\"logEntries\"></div>\n</div>\n</div>\n\n<!-- Sites Page -->\n<div class=\"page-view\" id=\"page-sites\">\n<div class=\"header\"><h2>Sites</h2><p class=\"subtitle\">Multi-site management</p></div>\n<div id=\"sitesContent\">\n<div class=\"card\"><p>Configure multiple sites in your <code>agentsite.config.yaml</code> using the <code>sites</code> array.</p></div>\n</div>\n</div>\n\n<!-- Export/Operations Page -->\n<div class=\"page-view\" id=\"page-export\">\n<div class=\"header\"><h2>Operations</h2><p class=\"subtitle\">Trigger scan and generation tasks</p></div>\n<div class=\"grid\">\n<div class=\"card\">\n<h3>Re-scan Site</h3>\n<p style=\"font-size:13px;color:#666;margin-bottom:12px\">Crawl the site again and update scan results.</p>\n<button id=\"btnRescan\" style=\"padding:8px 20px;background:#0066cc;color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:13px\">Start Rescan</button>\n<div id=\"rescanStatus\" style=\"margin-top:8px;font-size:12px;color:#666\"></div>\n</div>\n<div class=\"card\">\n<h3>Regenerate Files</h3>\n<p style=\"font-size:13px;color:#666;margin-bottom:12px\">Regenerate all output files from scan results.</p>\n<button id=\"btnRegenerate\" style=\"padding:8px 20px;background:#388e3c;color:#fff;border:none;border-radius:6px;cursor:pointer;font-size:13px\">Regenerate</button>\n<div id=\"regenStatus\" style=\"margin-top:8px;font-size:12px;color:#666\"></div>\n</div>\n</div>\n</div>\n\n</div>\n<script>\n// Router\nvar allPages=[];\nfunction navigate(){\n var hash=location.hash||'#/';\n var route=hash.replace('#','');\n document.querySelectorAll('.page-view').forEach(function(el){el.classList.remove('active')});\n document.querySelectorAll('.sidebar a').forEach(function(el){el.classList.remove('active')});\n var pageMap={'/':\"page-overview\",'/pages':\"page-pages\",'/files':\"page-files\",'/config':\"page-config\",'/logs':\"page-logs\",'/sites':\"page-sites\",'/export':\"page-export\"};\n var pageId=pageMap[route]||'page-overview';\n var el=document.getElementById(pageId);\n if(el)el.classList.add('active');\n var link=document.querySelector('.sidebar a[href=\"'+hash+'\"]');\n if(link)link.classList.add('active');\n if(route==='/logs')loadLogs();\n if(route==='/files')loadFiles();\n if(route==='/config')loadConfig();\n}\nwindow.addEventListener('hashchange',navigate);\n\n// Load overview + stats\nfunction loadOverview(){\n fetch('/api/stats').then(function(r){return r.json()}).then(function(s){\n var g=document.getElementById('statsGrid');\n g.innerHTML='<div class=\"card\"><h3>Total Pages</h3><div class=\"stat\">'+s.totalPages+'</div></div>'\n +'<div class=\"card\"><h3>Total Words</h3><div class=\"stat\">'+s.totalWords.toLocaleString()+'</div></div>'\n +'<div class=\"card\"><h3>Docs</h3><div class=\"stat\">'+(s.pageTypes.docs||0)+'</div></div>'\n +'<div class=\"card\"><h3>FAQ</h3><div class=\"stat\">'+(s.pageTypes.faq||0)+'</div></div>'\n +'<div class=\"card\"><h3>Blog</h3><div class=\"stat\">'+(s.pageTypes.blog||0)+'</div></div>'\n +'<div class=\"card\"><h3>Products</h3><div class=\"stat\">'+(s.pageTypes.product||0)+'</div></div>';\n });\n fetch('/api/pages-data').then(function(r){return r.json()}).then(function(d){\n allPages=d.pages||[];\n renderOverviewTable(allPages.slice(0,20));\n renderPagesTable(allPages);\n populateTypeFilter(allPages);\n });\n}\n\nfunction renderOverviewTable(pages){\n var tb=document.getElementById('overviewTable');\n tb.innerHTML=pages.map(function(p){\n return '<tr><td>'+esc(p.title)+'</td><td><span class=\"badge badge-'+p.type+'\">'+p.type+'</span></td><td style=\"font-size:12px;color:#666\">'+esc(p.url)+'</td><td>'+p.wordCount+'</td></tr>';\n }).join('');\n}\n\n// Pages\nfunction renderPagesTable(pages){\n var tb=document.getElementById('pagesTable');\n tb.innerHTML=pages.map(function(p){\n var tags=(p.tags||[]).join(', ');\n return '<tr><td>'+esc(p.title)+'</td><td><span class=\"badge badge-'+p.type+'\">'+p.type+'</span></td><td style=\"font-size:12px;color:#666\">'+esc(p.url)+'</td><td>'+p.wordCount+'</td><td style=\"font-size:11px;color:#888\">'+esc(tags)+'</td></tr>';\n }).join('');\n}\n\nfunction populateTypeFilter(pages){\n var types={};pages.forEach(function(p){types[p.type]=1});\n var sel=document.getElementById('typeFilter');\n Object.keys(types).sort().forEach(function(t){\n var o=document.createElement('option');o.value=t;o.textContent=t;sel.appendChild(o);\n });\n}\n\ndocument.getElementById('pageSearch').addEventListener('input',filterPages);\ndocument.getElementById('typeFilter').addEventListener('change',filterPages);\nfunction filterPages(){\n var q=document.getElementById('pageSearch').value.toLowerCase();\n var t=document.getElementById('typeFilter').value;\n var filtered=allPages.filter(function(p){\n if(t&&p.type!==t)return false;\n if(q&&p.title.toLowerCase().indexOf(q)===-1&&p.url.toLowerCase().indexOf(q)===-1)return false;\n return true;\n });\n renderPagesTable(filtered);\n}\n\n// Files\nfunction loadFiles(){\n fetch('/api/files').then(function(r){return r.json()}).then(function(d){\n var container=document.getElementById('filesList');\n container.innerHTML=d.files.map(function(f){\n var preview=f.content?f.content.substring(0,2000):'';\n return '<div class=\"file-card\"><div class=\"file-header\" onclick=\"this.parentElement.classList.toggle(\\\\'open\\\\')\"><span>'+esc(f.name)+'</span><span style=\"color:#888\">'+formatSize(f.size)+'</span></div><div class=\"file-body\"><pre class=\"pre-wrap\">'+esc(preview)+(f.size>2000?'\\\\n...truncated':'')+'</pre></div></div>';\n }).join('');\n });\n}\n\n// Config\nfunction loadConfig(){\n fetch('/api/config').then(function(r){return r.json()}).then(function(c){\n document.getElementById('configContent').textContent=JSON.stringify(c,null,2);\n });\n}\n\n// Logs\nfunction loadLogs(){\n fetch('/api/access-log?limit=200').then(function(r){return r.json()}).then(function(d){\n var entries=d.entries||[];\n // Stats\n var total=entries.length;\n var ok=entries.filter(function(e){return e.statusCode<400}).length;\n var avgTime=total?Math.round(entries.reduce(function(s,e){return s+e.responseTimeMs},0)/total):0;\n document.getElementById('logStats').innerHTML=\n '<div class=\"card\"><h3>Recent Requests</h3><div class=\"stat\">'+total+'</div></div>'\n +'<div class=\"card\"><h3>Success Rate</h3><div class=\"stat\">'+(total?Math.round(ok/total*100):0)+'%</div></div>'\n +'<div class=\"card\"><h3>Avg Response</h3><div class=\"stat\">'+avgTime+'ms</div></div>';\n // Entries\n var container=document.getElementById('logEntries');\n container.innerHTML=entries.slice(0,100).map(function(e){\n var cls=e.statusCode<400?'status-2xx':e.statusCode<500?'status-4xx':'status-5xx';\n return '<div class=\"log-entry\"><span>'+new Date(e.timestamp).toLocaleString()+'</span><span><b>'+e.method+'</b></span><span style=\"color:#666\">'+esc(e.path+(e.query?'?'+e.query:''))+'</span><span class=\"'+cls+'\">'+e.statusCode+'</span><span>'+e.responseTimeMs+'ms</span></div>';\n }).join('');\n });\n}\n\n// Operations\ndocument.getElementById('btnRescan').addEventListener('click',function(){\n var btn=this;btn.disabled=true;btn.textContent='Scanning...';\n document.getElementById('rescanStatus').textContent='Running...';\n fetch('/api/rescan',{method:'POST'}).then(function(r){return r.json()}).then(function(d){\n document.getElementById('rescanStatus').textContent=d.message||'Done';\n btn.disabled=false;btn.textContent='Start Rescan';\n loadOverview();\n }).catch(function(e){\n document.getElementById('rescanStatus').textContent='Error: '+e.message;\n btn.disabled=false;btn.textContent='Start Rescan';\n });\n});\ndocument.getElementById('btnRegenerate').addEventListener('click',function(){\n var btn=this;btn.disabled=true;btn.textContent='Generating...';\n document.getElementById('regenStatus').textContent='Running...';\n fetch('/api/regenerate',{method:'POST'}).then(function(r){return r.json()}).then(function(d){\n document.getElementById('regenStatus').textContent=d.message||'Done';\n btn.disabled=false;btn.textContent='Regenerate';\n }).catch(function(e){\n document.getElementById('regenStatus').textContent='Error: '+e.message;\n btn.disabled=false;btn.textContent='Regenerate';\n });\n});\n\n// Utils\nfunction esc(s){if(!s)return '';return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;')}\nfunction formatSize(b){if(b<1024)return b+'B';if(b<1048576)return (b/1024).toFixed(1)+'KB';return (b/1048576).toFixed(1)+'MB'}\n\n// Init\nloadOverview();\nnavigate();\n</script>\n</body>\n</html>`;\n","import { appendFileSync, readFileSync, existsSync } from 'node:fs';\nimport type { FastifyInstance } from 'fastify';\n\nexport interface AccessLogEntry {\n timestamp: string;\n method: string;\n path: string;\n query: string;\n ip: string;\n userAgent: string;\n statusCode: number;\n responseTimeMs: number;\n}\n\nexport class AccessLogger {\n private logPath: string;\n\n constructor(outDir: string) {\n this.logPath = `${outDir}/access-log.jsonl`;\n }\n\n log(entry: AccessLogEntry): void {\n appendFileSync(this.logPath, JSON.stringify(entry) + '\\n', 'utf-8');\n }\n\n getRecent(limit: number = 100): AccessLogEntry[] {\n if (!existsSync(this.logPath)) return [];\n const lines = readFileSync(this.logPath, 'utf-8')\n .split('\\n')\n .filter((l) => l.trim().length > 0);\n return lines\n .slice(-limit)\n .reverse()\n .map((l) => JSON.parse(l) as AccessLogEntry);\n }\n\n register(app: FastifyInstance): void {\n app.addHook('onResponse', async (request, reply) => {\n const entry: AccessLogEntry = {\n timestamp: new Date().toISOString(),\n method: request.method,\n path: request.url.split('?')[0],\n query: request.url.includes('?') ? request.url.split('?')[1] : '',\n ip: request.ip,\n userAgent: (request.headers['user-agent'] as string) ?? '',\n statusCode: reply.statusCode,\n responseTimeMs: Math.round(reply.elapsedTime),\n };\n this.log(entry);\n });\n }\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData, SearchIndex } from '../app.js';\n\nexport function registerSearchRoute(app: FastifyInstance, data: ServerData, searchIndex: SearchIndex) {\n app.get<{ Querystring: { q?: string; page?: string; limit?: string } }>(\n '/api/search',\n async (req) => {\n const q = (req.query.q ?? '').toLowerCase().trim();\n const page = Math.max(1, parseInt(req.query.page ?? '1', 10));\n const limit = Math.min(50, Math.max(1, parseInt(req.query.limit ?? '10', 10)));\n\n if (!q) return { ok: true, data: [], total: 0, page };\n\n const words = q.split(/\\W+/).filter((w) => w.length > 2);\n const scoreMap = new Map<number, number>();\n\n for (const word of words) {\n const matches = searchIndex.get(word);\n if (matches) {\n for (const idx of matches) {\n scoreMap.set(idx, (scoreMap.get(idx) ?? 0) + 1);\n }\n }\n }\n\n const sorted = [...scoreMap.entries()]\n .sort((a, b) => b[1] - a[1]);\n\n const total = sorted.length;\n const start = (page - 1) * limit;\n const results = sorted.slice(start, start + limit).map(([idx]) => data.pages[idx]);\n\n return { ok: true, data: results, total, page };\n },\n );\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\nimport type { ValidatedConfig } from '../../config/schema.js';\nimport { urlToId } from '../../utils/url.js';\nimport { filterPageContent } from '../../utils/access-control.js';\n\nexport function registerPagesRoute(app: FastifyInstance, data: ServerData, config: ValidatedConfig) {\n app.get<{ Params: { id: string } }>('/api/pages/:id', async (req, reply) => {\n const page = data.pages.find((p) => urlToId(p.url) === req.params.id);\n if (!page) {\n reply.code(404);\n return { ok: false, error: 'Page not found' };\n }\n return { ok: true, data: filterPageContent(page, config) };\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\n\nexport function registerFaqRoute(app: FastifyInstance, data: ServerData) {\n app.get<{ Querystring: { category?: string } }>('/api/faq', async (req) => {\n let items = data.faq as { category?: string }[];\n const category = req.query.category;\n if (category) {\n items = items.filter((f) => f.category?.toLowerCase() === category.toLowerCase());\n }\n return { ok: true, data: items, total: items.length };\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\n\nexport function registerProductsRoute(app: FastifyInstance, data: ServerData) {\n app.get('/api/products', async () => {\n return { ok: true, data: data.products, total: data.products.length };\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\n\nexport function registerDocsRoute(app: FastifyInstance, data: ServerData) {\n app.get<{ Querystring: { section?: string } }>('/api/docs', async (req) => {\n let items = data.docs as { section?: string }[];\n const section = req.query.section;\n if (section) {\n items = items.filter((d) => d.section?.toLowerCase() === section.toLowerCase());\n }\n return { ok: true, data: items, total: items.length };\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\n\nexport function registerArticlesRoute(app: FastifyInstance, data: ServerData) {\n app.get<{ Querystring: { tag?: string; page?: string; limit?: string } }>(\n '/api/articles',\n async (req) => {\n let items = data.articles as { tags?: string[] }[];\n const tag = req.query.tag;\n if (tag) {\n items = items.filter((a) => a.tags?.some((t) => t.toLowerCase() === tag.toLowerCase()));\n }\n\n const page = Math.max(1, parseInt(req.query.page ?? '1', 10));\n const limit = Math.min(50, Math.max(1, parseInt(req.query.limit ?? '10', 10)));\n const total = items.length;\n const start = (page - 1) * limit;\n const paged = items.slice(start, start + limit);\n\n return { ok: true, data: paged, total, page };\n },\n );\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\n\nexport function registerPricingRoute(app: FastifyInstance, data: ServerData) {\n app.get('/api/pricing', async () => {\n return { ok: true, data: data.pricing };\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ServerData } from '../app.js';\n\nexport function registerChangelogRoute(app: FastifyInstance, data: ServerData) {\n app.get('/api/changelog', async () => {\n return { ok: true, data: data.changelog };\n });\n}\n","import { Command } from 'commander';\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { loadConfig } from '../config/loader.js';\nimport { crawlSite } from '../scanner/crawler.js';\nimport { parseSitemap } from '../scanner/sitemap-parser.js';\nimport { classifyPage } from '../scanner/page-classifier.js';\nimport { extractContent } from '../scanner/content-extractor.js';\nimport { sha256 } from '../utils/hash.js';\nimport { loadHashes, saveHashes, findChangedUrls } from '../change-detection/store.js';\nimport { generateLlmsTxt } from '../generator/llms-txt.js';\nimport { generateAgentSitemap } from '../generator/agent-sitemap.js';\nimport { generateAgentIndex } from '../generator/agent-index.js';\nimport { generateStructuredExports } from '../generator/structured-export.js';\nimport { log, spinner } from '../utils/logger.js';\nimport type { ScannedPage, ScanResult } from '../types/page.js';\n\nexport function registerUpdateCommand(program: Command) {\n program\n .command('update')\n .description('Incrementally update: re-scan, detect changes, regenerate')\n .action(async () => {\n const config = loadConfig();\n const outDir = config.output.dir;\n const hashPath = `${outDir}/cache/hashes.json`;\n mkdirSync(`${outDir}/cache/pages`, { recursive: true });\n mkdirSync(`${outDir}/data`, { recursive: true });\n\n const oldHashes = loadHashes(hashPath);\n\n // Re-scan\n const sp = spinner('Re-scanning site...');\n const sitemapUrls = await parseSitemap(config.site.url);\n const crawled = await crawlSite(config, sitemapUrls, (url, i) => {\n sp.text = `Scanning (${i})... ${url}`;\n });\n sp.succeed(`Scanned ${crawled.length} pages`);\n\n // Build new pages & hashes\n const newHashes: Record<string, string> = {};\n const pages: ScannedPage[] = [];\n\n for (const { url, html } of crawled) {\n const content = extractContent(html, url);\n const contentHash = sha256(content.bodyText);\n newHashes[url] = contentHash;\n\n const pageType = classifyPage({\n url,\n title: content.title,\n metaOgType: content.metaOgType,\n headings: content.headings,\n bodyText: content.bodyText,\n });\n\n pages.push({\n url,\n title: content.title,\n type: pageType,\n contentHash,\n summary: content.summary,\n headings: content.headings,\n lastModified: content.lastModified,\n scannedAt: new Date().toISOString(),\n wordCount: content.wordCount,\n tags: content.tags,\n version: content.version,\n author: content.author,\n publishedAt: content.publishedAt,\n updatedAt: content.lastModified,\n });\n }\n\n // Detect changes\n const changed = findChangedUrls(oldHashes, newHashes);\n if (changed.length === 0) {\n log.success('No changes detected. Everything is up to date.');\n return;\n }\n\n log.info(`${changed.length} page(s) changed`);\n\n // Save updated scan result\n const result: ScanResult = {\n siteUrl: config.site.url,\n scannedAt: new Date().toISOString(),\n totalPages: pages.length,\n pages,\n };\n writeFileSync(`${outDir}/scan-result.json`, JSON.stringify(result, null, 2), 'utf-8');\n\n // Regenerate outputs\n const genSp = spinner('Regenerating files...');\n\n writeFileSync(`${outDir}/llms.txt`, generateLlmsTxt(result, config.site.name, config.site.description), 'utf-8');\n writeFileSync(`${outDir}/agent-sitemap.json`, JSON.stringify(generateAgentSitemap(result), null, 2), 'utf-8');\n writeFileSync(`${outDir}/agent-index.json`, JSON.stringify(generateAgentIndex(result, config.site.name, config.site.description), null, 2), 'utf-8');\n\n const { docs, faq, products, articles, pricing, changelog } = await generateStructuredExports(result, outDir, config);\n writeFileSync(`${outDir}/data/docs.json`, JSON.stringify(docs, null, 2), 'utf-8');\n writeFileSync(`${outDir}/data/faq.json`, JSON.stringify(faq, null, 2), 'utf-8');\n writeFileSync(`${outDir}/data/products.json`, JSON.stringify(products, null, 2), 'utf-8');\n writeFileSync(`${outDir}/data/articles.json`, JSON.stringify(articles, null, 2), 'utf-8');\n writeFileSync(`${outDir}/data/pricing.json`, JSON.stringify(pricing, null, 2), 'utf-8');\n writeFileSync(`${outDir}/data/changelog.json`, JSON.stringify(changelog, null, 2), 'utf-8');\n\n // Update hashes\n saveHashes(hashPath, newHashes);\n\n genSp.succeed('All files regenerated');\n log.success(`Update complete. ${changed.length} page(s) updated.`);\n });\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\n\nexport type HashStore = Record<string, string>;\n\nexport function loadHashes(path: string): HashStore {\n if (!existsSync(path)) return {};\n return JSON.parse(readFileSync(path, 'utf-8'));\n}\n\nexport function saveHashes(path: string, hashes: HashStore): void {\n writeFileSync(path, JSON.stringify(hashes, null, 2), 'utf-8');\n}\n\nexport function findChangedUrls(oldHashes: HashStore, newHashes: HashStore): string[] {\n const changed: string[] = [];\n for (const [url, hash] of Object.entries(newHashes)) {\n if (oldHashes[url] !== hash) changed.push(url);\n }\n return changed;\n}\n","import { Command } from 'commander';\nimport { existsSync } from 'node:fs';\nimport { loadConfig } from '../config/loader.js';\nimport { startMcpServer } from '../mcp/server.js';\nimport { log } from '../utils/logger.js';\n\nexport function registerMcpCommand(program: Command) {\n program\n .command('mcp')\n .description('Start MCP (Model Context Protocol) server over stdio')\n .action(async () => {\n const config = loadConfig();\n const outDir = config.output.dir;\n\n if (!existsSync(`${outDir}/scan-result.json`)) {\n log.error('No data found. Run `agentsite scan` and `agentsite generate` first.');\n process.exit(1);\n }\n\n // MCP uses stdio, so we suppress normal logs\n await startMcpServer(outDir);\n });\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { readFileSync, existsSync } from 'node:fs';\nimport type { ScanResult, ScannedPage } from '../types/page.js';\nimport type { DocEntry, FaqEntry, ProductEntry, ArticleEntry, PricingEntry, ChangelogEntry } from '../types/content.js';\n\ninterface McpData {\n scanResult: ScanResult;\n docs: DocEntry[];\n faq: FaqEntry[];\n products: ProductEntry[];\n articles: ArticleEntry[];\n pricing: PricingEntry[];\n changelog: ChangelogEntry[];\n}\n\nfunction loadData(outDir: string): McpData {\n const loadJson = <T>(path: string): T[] => {\n if (!existsSync(path)) return [];\n return JSON.parse(readFileSync(path, 'utf-8'));\n };\n\n const scanResult: ScanResult = JSON.parse(readFileSync(`${outDir}/scan-result.json`, 'utf-8'));\n\n return {\n scanResult,\n docs: loadJson<DocEntry>(`${outDir}/data/docs.json`),\n faq: loadJson<FaqEntry>(`${outDir}/data/faq.json`),\n products: loadJson<ProductEntry>(`${outDir}/data/products.json`),\n articles: loadJson<ArticleEntry>(`${outDir}/data/articles.json`),\n pricing: loadJson<PricingEntry>(`${outDir}/data/pricing.json`),\n changelog: loadJson<ChangelogEntry>(`${outDir}/data/changelog.json`),\n };\n}\n\nfunction buildSearchIndex(pages: ScannedPage[]): Map<string, Set<number>> {\n const index = new Map<string, Set<number>>();\n pages.forEach((page, i) => {\n const text = `${page.title} ${page.summary} ${page.type}`.toLowerCase();\n const words = text.split(/\\W+/).filter((w) => w.length > 2);\n for (const word of words) {\n if (!index.has(word)) index.set(word, new Set());\n index.get(word)!.add(i);\n }\n });\n return index;\n}\n\nexport async function startMcpServer(outDir: string) {\n const data = loadData(outDir);\n const searchIndex = buildSearchIndex(data.scanResult.pages);\n\n const server = new McpServer({\n name: 'agentsite',\n version: '1.0.0',\n });\n\n // Tool: search\n server.tool(\n 'search',\n 'Search site content by keyword',\n { query: z.string().describe('Search keyword'), limit: z.number().optional().describe('Max results (default 10)') },\n async ({ query, limit }) => {\n const max = limit ?? 10;\n const words = query.toLowerCase().split(/\\W+/).filter((w) => w.length > 2);\n const scoreMap = new Map<number, number>();\n\n for (const word of words) {\n const matches = searchIndex.get(word);\n if (matches) {\n for (const idx of matches) {\n scoreMap.set(idx, (scoreMap.get(idx) ?? 0) + 1);\n }\n }\n }\n\n const sorted = [...scoreMap.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, max)\n .map(([idx]) => {\n const p = data.scanResult.pages[idx];\n return { url: p.url, title: p.title, type: p.type, summary: p.summary };\n });\n\n return { content: [{ type: 'text' as const, text: JSON.stringify(sorted, null, 2) }] };\n },\n );\n\n // Tool: get_page\n server.tool(\n 'get_page',\n 'Get detailed info about a specific page by URL',\n { url: z.string().describe('Page URL') },\n async ({ url }) => {\n const page = data.scanResult.pages.find((p) => p.url === url);\n if (!page) {\n return { content: [{ type: 'text' as const, text: 'Page not found' }] };\n }\n return { content: [{ type: 'text' as const, text: JSON.stringify(page, null, 2) }] };\n },\n );\n\n // Tool: list_pages\n server.tool(\n 'list_pages',\n 'List all pages with optional type filter',\n { type: z.string().optional().describe('Filter by page type: docs, faq, blog, product, pricing, about, contact, changelog') },\n async ({ type }) => {\n let pages = data.scanResult.pages;\n if (type) {\n pages = pages.filter((p) => p.type === type);\n }\n const summary = pages.map((p) => ({ url: p.url, title: p.title, type: p.type }));\n return { content: [{ type: 'text' as const, text: JSON.stringify(summary, null, 2) }] };\n },\n );\n\n // Tool: list_faq\n server.tool(\n 'list_faq',\n 'List FAQ entries with optional category filter',\n { category: z.string().optional().describe('Filter by category') },\n async ({ category }) => {\n let items = data.faq;\n if (category) {\n items = items.filter((f) => f.category.toLowerCase() === category.toLowerCase());\n }\n return { content: [{ type: 'text' as const, text: JSON.stringify(items, null, 2) }] };\n },\n );\n\n // Tool: list_docs\n server.tool(\n 'list_docs',\n 'List documentation entries with optional section filter',\n { section: z.string().optional().describe('Filter by section') },\n async ({ section }) => {\n let items = data.docs;\n if (section) {\n items = items.filter((d) => d.section.toLowerCase() === section.toLowerCase());\n }\n return { content: [{ type: 'text' as const, text: JSON.stringify(items, null, 2) }] };\n },\n );\n\n // Tool: list_products\n server.tool(\n 'list_products',\n 'List all product entries',\n {},\n async () => {\n return { content: [{ type: 'text' as const, text: JSON.stringify(data.products, null, 2) }] };\n },\n );\n\n // Tool: list_articles\n server.tool(\n 'list_articles',\n 'List blog/article entries with optional tag filter',\n { tag: z.string().optional().describe('Filter by tag') },\n async ({ tag }) => {\n let items = data.articles;\n if (tag) {\n items = items.filter((a) => a.tags.some((t) => t.toLowerCase() === tag.toLowerCase()));\n }\n return { content: [{ type: 'text' as const, text: JSON.stringify(items, null, 2) }] };\n },\n );\n\n // Tool: list_pricing\n server.tool(\n 'list_pricing',\n 'List pricing/plan entries',\n {},\n async () => {\n return { content: [{ type: 'text' as const, text: JSON.stringify(data.pricing, null, 2) }] };\n },\n );\n\n // Tool: list_changelog\n server.tool(\n 'list_changelog',\n 'List changelog/release entries',\n { version: z.string().optional().describe('Filter by version') },\n async ({ version }) => {\n let items = data.changelog;\n if (version) {\n items = items.filter((c) => c.version.toLowerCase().includes(version.toLowerCase()));\n }\n return { content: [{ type: 'text' as const, text: JSON.stringify(items, null, 2) }] };\n },\n );\n\n // Tool: get_config\n server.tool(\n 'get_config',\n 'Get site configuration summary (API keys hidden)',\n {},\n async () => {\n const configPath = `${outDir}/../agentsite.config.yaml`;\n let configSummary: unknown = { note: 'Config file not found at expected location' };\n if (existsSync(configPath)) {\n const yaml = await import('js-yaml');\n const raw = readFileSync(configPath, 'utf-8');\n const parsed = yaml.load(raw) as Record<string, unknown>;\n // Sanitize\n if (parsed.llm && typeof parsed.llm === 'object') {\n (parsed.llm as Record<string, unknown>).apiKey = '***';\n }\n configSummary = parsed;\n }\n return { content: [{ type: 'text' as const, text: JSON.stringify(configSummary, null, 2) }] };\n },\n );\n\n // Tool: site_overview\n server.tool(\n 'site_overview',\n 'Get a high-level overview of the site: name, description, page counts by type',\n {},\n async () => {\n const typeCounts: Record<string, number> = {};\n for (const p of data.scanResult.pages) {\n typeCounts[p.type] = (typeCounts[p.type] ?? 0) + 1;\n }\n const overview = {\n totalPages: data.scanResult.totalPages,\n scannedAt: data.scanResult.scannedAt,\n pageTypes: typeCounts,\n dataFiles: {\n docs: data.docs.length,\n faq: data.faq.length,\n products: data.products.length,\n articles: data.articles.length,\n pricing: data.pricing.length,\n changelog: data.changelog.length,\n },\n };\n return { content: [{ type: 'text' as const, text: JSON.stringify(overview, null, 2) }] };\n },\n );\n\n // Resource: llms.txt\n const llmsPath = `${outDir}/llms.txt`;\n if (existsSync(llmsPath)) {\n server.resource(\n 'llms-txt',\n 'file:///llms.txt',\n { description: 'LLM-friendly site overview in llms.txt format', mimeType: 'text/plain' },\n async () => ({\n contents: [{ uri: 'file:///llms.txt', text: readFileSync(llmsPath, 'utf-8'), mimeType: 'text/plain' }],\n }),\n );\n }\n\n // Resource: agent-index.json\n const indexPath = `${outDir}/agent-index.json`;\n if (existsSync(indexPath)) {\n server.resource(\n 'agent-index',\n 'file:///agent-index.json',\n { description: 'Agent index with site metadata and API endpoints', mimeType: 'application/json' },\n async () => ({\n contents: [{ uri: 'file:///agent-index.json', text: readFileSync(indexPath, 'utf-8'), mimeType: 'application/json' }],\n }),\n );\n }\n\n // Resource: agent-sitemap.json\n const sitemapPath = `${outDir}/agent-sitemap.json`;\n if (existsSync(sitemapPath)) {\n server.resource(\n 'agent-sitemap',\n 'file:///agent-sitemap.json',\n { description: 'Machine-readable sitemap with page metadata', mimeType: 'application/json' },\n async () => ({\n contents: [{ uri: 'file:///agent-sitemap.json', text: readFileSync(sitemapPath, 'utf-8'), mimeType: 'application/json' }],\n }),\n );\n }\n\n // Resource: data/*.json files\n const dataFiles = ['docs', 'faq', 'products', 'articles', 'pricing', 'changelog'];\n for (const name of dataFiles) {\n const dataPath = `${outDir}/data/${name}.json`;\n if (existsSync(dataPath)) {\n server.resource(\n `data-${name}`,\n `file:///data/${name}.json`,\n { description: `Structured ${name} data`, mimeType: 'application/json' },\n async () => ({\n contents: [{ uri: `file:///data/${name}.json`, text: readFileSync(dataPath, 'utf-8'), mimeType: 'application/json' }],\n }),\n );\n }\n }\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n"],"mappings":"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","names":["existsSync","yaml","resolve","program","existsSync","yaml","readFileSync","existsSync","readFileSync","existsSync","readFileSync","existsSync","existsSync","readFileSync","program","writeFileSync","mkdirSync","readFileSync","writeFileSync","existsSync","program","mkdirSync","writeFileSync","existsSync","readFileSync","existsSync","loadJson","buildSearchIndex","yaml","program","existsSync"]}
@@ -0,0 +1,10 @@
1
+ import {
2
+ registerScanCommand,
3
+ runScan
4
+ } from "./chunk-YWR5EH3F.js";
5
+ import "./chunk-YWUDTSOR.js";
6
+ export {
7
+ registerScanCommand,
8
+ runScan
9
+ };
10
+ //# sourceMappingURL=scan-QWNB65DB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "agentsite-kit",
3
+ "version": "1.0.0",
4
+ "description": "CLI toolkit to make any website Agent-friendly",
5
+ "type": "module",
6
+ "bin": {
7
+ "agentsite": "./bin/agentsite.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "bin",
12
+ "templates"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsx src/index.ts",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/lingfan36/AgentSite-Kit.git"
22
+ },
23
+ "homepage": "https://github.com/lingfan36/AgentSite-Kit",
24
+ "bugs": {
25
+ "url": "https://github.com/lingfan36/AgentSite-Kit/issues"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "keywords": [
31
+ "agent",
32
+ "llm",
33
+ "ai",
34
+ "sitemap",
35
+ "cli",
36
+ "web-scraper",
37
+ "structured-data",
38
+ "mcp",
39
+ "llms-txt",
40
+ "agent-friendly"
41
+ ],
42
+ "license": "MIT",
43
+ "dependencies": {
44
+ "@fastify/cors": "^10.0.0",
45
+ "@fastify/rate-limit": "^10.0.0",
46
+ "@modelcontextprotocol/sdk": "^1.27.1",
47
+ "axios": "^1.7.0",
48
+ "chalk": "^5.3.0",
49
+ "cheerio": "^1.0.0",
50
+ "commander": "^12.1.0",
51
+ "fast-xml-parser": "^4.4.0",
52
+ "fastify": "^5.0.0",
53
+ "js-yaml": "^4.1.0",
54
+ "minimatch": "^10.0.0",
55
+ "ora": "^8.1.0",
56
+ "p-limit": "^6.1.0",
57
+ "zod": "^3.23.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/js-yaml": "^4.0.9",
61
+ "@types/node": "^22.0.0",
62
+ "tsup": "^8.2.0",
63
+ "tsx": "^4.19.0",
64
+ "typescript": "^5.6.0"
65
+ }
66
+ }
@@ -0,0 +1,32 @@
1
+ site:
2
+ url: "{{url}}"
3
+ name: "{{name}}"
4
+ description: "{{description}}"
5
+
6
+ scan:
7
+ maxPages: 100
8
+ concurrency: 3
9
+ delayMs: 200
10
+ include:
11
+ - "**"
12
+ exclude: []
13
+ respectRobotsTxt: true
14
+
15
+ output:
16
+ dir: ".agentsite"
17
+ formats:
18
+ - llms-txt
19
+ - agent-sitemap
20
+ - agent-index
21
+ - structured
22
+
23
+ server:
24
+ port: 3141
25
+ rateLimit:
26
+ max: 60
27
+ timeWindow: "1 minute"
28
+
29
+ llm:
30
+ apiUrl: "https://integrate.api.nvidia.com/v1"
31
+ apiKey: "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"
32
+ model: "minimaxai/minimax-m2.5"
@@ -0,0 +1,29 @@
1
+ name: "API Documentation"
2
+ description: "Optimized for API documentation sites (OpenAPI/Swagger friendly)"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 300
7
+ include:
8
+ - "/api/**"
9
+ - "/docs/**"
10
+ - "/reference/**"
11
+ - "/endpoints/**"
12
+ - "/guides/**"
13
+ - "/sdk/**"
14
+ - "/changelog/**"
15
+ exclude:
16
+ - "/blog/**"
17
+ - "/admin/**"
18
+ access:
19
+ allowedTypes:
20
+ - docs
21
+ - changelog
22
+ - faq
23
+ - about
24
+ output:
25
+ formats:
26
+ - llms-txt
27
+ - agent-sitemap
28
+ - agent-index
29
+ - structured
@@ -0,0 +1,26 @@
1
+ name: "Blog"
2
+ description: "Optimized for blog sites with articles, tags, and categories"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 150
7
+ include:
8
+ - "/blog/**"
9
+ - "/posts/**"
10
+ - "/articles/**"
11
+ - "/category/**"
12
+ - "/tag/**"
13
+ exclude:
14
+ - "/admin/**"
15
+ access:
16
+ allowedTypes:
17
+ - blog
18
+ - faq
19
+ - about
20
+ - contact
21
+ output:
22
+ formats:
23
+ - llms-txt
24
+ - agent-sitemap
25
+ - agent-index
26
+ - structured
@@ -0,0 +1,31 @@
1
+ name: "Community / Forum"
2
+ description: "Optimized for community forums and discussion sites"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 150
7
+ include:
8
+ - "/forum/**"
9
+ - "/community/**"
10
+ - "/discussions/**"
11
+ - "/topics/**"
12
+ - "/faq/**"
13
+ - "/help/**"
14
+ - "/docs/**"
15
+ exclude:
16
+ - "/admin/**"
17
+ - "/settings/**"
18
+ - "/profile/**"
19
+ access:
20
+ allowedTypes:
21
+ - faq
22
+ - docs
23
+ - blog
24
+ - about
25
+ - contact
26
+ output:
27
+ formats:
28
+ - llms-txt
29
+ - agent-sitemap
30
+ - agent-index
31
+ - structured
@@ -0,0 +1,26 @@
1
+ name: "Documentation Site"
2
+ description: "Optimized for documentation sites with structured sections and guides"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 200
7
+ include:
8
+ - "/docs/**"
9
+ - "/guide/**"
10
+ - "/reference/**"
11
+ - "/api/**"
12
+ - "/tutorial/**"
13
+ exclude:
14
+ - "/blog/**"
15
+ - "/changelog/**"
16
+ access:
17
+ allowedTypes:
18
+ - docs
19
+ - faq
20
+ - about
21
+ output:
22
+ formats:
23
+ - llms-txt
24
+ - agent-sitemap
25
+ - agent-index
26
+ - structured
@@ -0,0 +1,32 @@
1
+ name: "E-commerce"
2
+ description: "Optimized for e-commerce sites with product catalogs and pricing"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 200
7
+ include:
8
+ - "/products/**"
9
+ - "/shop/**"
10
+ - "/catalog/**"
11
+ - "/collections/**"
12
+ - "/pricing/**"
13
+ - "/faq/**"
14
+ exclude:
15
+ - "/cart/**"
16
+ - "/checkout/**"
17
+ - "/account/**"
18
+ - "/admin/**"
19
+ access:
20
+ allowedTypes:
21
+ - product
22
+ - pricing
23
+ - faq
24
+ - about
25
+ - contact
26
+ - docs
27
+ output:
28
+ formats:
29
+ - llms-txt
30
+ - agent-sitemap
31
+ - agent-index
32
+ - structured
@@ -0,0 +1,28 @@
1
+ name: "Knowledge Base"
2
+ description: "Optimized for knowledge bases combining docs, FAQ, and articles"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 300
7
+ include:
8
+ - "/docs/**"
9
+ - "/help/**"
10
+ - "/faq/**"
11
+ - "/kb/**"
12
+ - "/support/**"
13
+ - "/articles/**"
14
+ - "/guides/**"
15
+ exclude:
16
+ - "/admin/**"
17
+ access:
18
+ allowedTypes:
19
+ - docs
20
+ - faq
21
+ - blog
22
+ - about
23
+ output:
24
+ formats:
25
+ - llms-txt
26
+ - agent-sitemap
27
+ - agent-index
28
+ - structured
@@ -0,0 +1,27 @@
1
+ name: "Portfolio"
2
+ description: "Optimized for portfolio and showcase sites"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 80
7
+ include:
8
+ - "/projects/**"
9
+ - "/work/**"
10
+ - "/portfolio/**"
11
+ - "/case-studies/**"
12
+ - "/about/**"
13
+ exclude:
14
+ - "/admin/**"
15
+ access:
16
+ allowedTypes:
17
+ - product
18
+ - about
19
+ - contact
20
+ - blog
21
+ - docs
22
+ output:
23
+ formats:
24
+ - llms-txt
25
+ - agent-sitemap
26
+ - agent-index
27
+ - structured
@@ -0,0 +1,30 @@
1
+ name: "SaaS Website"
2
+ description: "Optimized for SaaS product websites with features, pricing, and FAQ"
3
+
4
+ config:
5
+ scan:
6
+ maxPages: 100
7
+ include:
8
+ - "/**"
9
+ exclude:
10
+ - "/app/**"
11
+ - "/dashboard/**"
12
+ - "/admin/**"
13
+ - "/login/**"
14
+ - "/signup/**"
15
+ access:
16
+ allowedTypes:
17
+ - product
18
+ - pricing
19
+ - faq
20
+ - docs
21
+ - about
22
+ - contact
23
+ - changelog
24
+ - blog
25
+ output:
26
+ formats:
27
+ - llms-txt
28
+ - agent-sitemap
29
+ - agent-index
30
+ - structured