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/commands/scan.ts","../src/scanner/crawler.ts","../src/utils/url.ts","../src/scanner/sitemap-parser.ts","../src/scanner/page-classifier.ts","../src/llm/classifier.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { writeFileSync, 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 { log, spinner } from '../utils/logger.js';\nimport { getLlmConfig } from '../llm/client.js';\nimport { llmClassifyPage } from '../llm/classifier.js';\nimport { llmSummarize } from '../llm/summarizer.js';\nimport { loadPlugins, runHook, runAfterScan } from '../plugins/loader.js';\nimport type { ScannedPage, ScanResult } from '../types/page.js';\n\nexport async function runScan(configOverride?: ReturnType<typeof loadConfig>): Promise<ScanResult> {\n const config = configOverride ?? loadConfig();\n const outDir = config.output.dir;\n mkdirSync(`${outDir}/cache/pages`, { recursive: true });\n mkdirSync(`${outDir}/data`, { recursive: true });\n\n // Load plugins\n const plugins = await loadPlugins(config.plugins ?? []);\n await runHook(plugins, 'beforeScan', config);\n\n // Check LLM availability\n const llmConfig = getLlmConfig(config);\n if (llmConfig) {\n log.info('LLM enabled — using AI-assisted classification & summarization');\n }\n\n // 1. Try sitemap\n const sp = spinner('Fetching sitemap...');\n const sitemapUrls = await parseSitemap(config.site.url);\n if (sitemapUrls.length > 0) {\n sp.succeed(`Found ${sitemapUrls.length} URLs in sitemap`);\n } else {\n sp.info('No sitemap found, will discover pages by crawling');\n }\n\n // 2. Crawl\n const crawlSp = spinner('Crawling site...');\n const crawled = await crawlSite(config, sitemapUrls, (url, i) => {\n crawlSp.text = `Crawling (${i}/${config.scan.maxPages})... ${url}`;\n });\n crawlSp.succeed(`Crawled ${crawled.length} pages`);\n\n // 3. Extract & classify\n const extractSp = spinner('Extracting content...');\n let pages: ScannedPage[] = [];\n\n for (let idx = 0; idx < crawled.length; idx++) {\n const { url, html } = crawled[idx];\n const content = extractContent(html, url);\n\n extractSp.text = `Processing (${idx + 1}/${crawled.length})... ${url}`;\n\n // Classification: LLM or rule-based\n let pageType;\n if (llmConfig) {\n try {\n pageType = await llmClassifyPage(llmConfig, url, content.title, content.bodyText);\n } catch {\n pageType = classifyPage({\n url, title: content.title, metaOgType: content.metaOgType,\n headings: content.headings, bodyText: content.bodyText,\n });\n }\n } else {\n pageType = classifyPage({\n url, title: content.title, metaOgType: content.metaOgType,\n headings: content.headings, bodyText: content.bodyText,\n });\n }\n\n // Summary: LLM or fallback\n let summary = content.summary;\n if (llmConfig) {\n try {\n summary = await llmSummarize(llmConfig, content.title, content.bodyText);\n } catch { /* keep rule-based summary */ }\n }\n\n pages.push({\n url,\n title: content.title,\n type: pageType,\n contentHash: sha256(content.bodyText),\n 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 extractSp.succeed(`Extracted content from ${pages.length} pages`);\n\n // Run afterScan plugin hooks\n pages = await runAfterScan(plugins, pages);\n\n // 4. Write scan result\n const result: ScanResult = {\n siteUrl: config.site.url,\n scannedAt: new Date().toISOString(),\n totalPages: pages.length,\n pages,\n };\n\n writeFileSync(`${outDir}/scan-result.json`, JSON.stringify(result, null, 2), 'utf-8');\n log.success(`Scan result saved to ${outDir}/scan-result.json`);\n\n // Stats\n const typeCounts = new Map<string, number>();\n for (const p of pages) {\n typeCounts.set(p.type, (typeCounts.get(p.type) ?? 0) + 1);\n }\n log.info('Page types:');\n for (const [type, count] of typeCounts) {\n console.log(` ${type}: ${count}`);\n }\n\n return result;\n}\n\nexport function registerScanCommand(program: Command) {\n program\n .command('scan')\n .description('Scan your website and classify pages')\n .option('--no-llm', 'Disable LLM-assisted classification and summarization')\n .action(async (opts) => {\n if (!opts.llm) {\n // Override LLM config to disable it\n const config = loadConfig();\n (config as Record<string, unknown>).llm = undefined;\n await runScan(config);\n } else {\n await runScan();\n }\n });\n}\n","import axios from 'axios';\nimport * as cheerio from 'cheerio';\nimport { writeFileSync, mkdirSync } from 'node:fs';\nimport pLimit from 'p-limit';\nimport { isSameOrigin } from '../utils/url.js';\nimport { sha256 } from '../utils/hash.js';\nimport type { ValidatedConfig } from '../config/schema.js';\n\nexport interface CrawlResult {\n url: string;\n html: string;\n status: number;\n}\n\nexport async function crawlSite(\n config: ValidatedConfig,\n seedUrls: string[],\n onPage?: (url: string, index: number) => void,\n): Promise<CrawlResult[]> {\n const { maxPages, concurrency, delayMs } = config.scan;\n const baseUrl = config.site.url;\n const visited = new Set<string>();\n const queue: string[] = [...seedUrls, baseUrl];\n const results: CrawlResult[] = [];\n const limit = pLimit(concurrency);\n const cacheDir = `${config.output.dir}/cache/pages`;\n mkdirSync(cacheDir, { recursive: true });\n\n const delay = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\n while (queue.length > 0 && visited.size < maxPages) {\n const batch = queue.splice(0, concurrency).filter((u) => !visited.has(u));\n if (batch.length === 0) continue;\n\n const tasks = batch.map((url) =>\n limit(async () => {\n if (visited.has(url) || visited.size >= maxPages) return null;\n visited.add(url);\n\n try {\n const res = await axios.get(url, {\n timeout: 15000,\n headers: { 'User-Agent': 'AgentSite-Kit/0.1' },\n maxRedirects: 3,\n });\n\n const html = res.data as string;\n onPage?.(url, visited.size);\n\n // Cache HTML\n const filename = sha256(url);\n writeFileSync(`${cacheDir}/${filename}.html`, html, 'utf-8');\n\n // Extract links\n const $ = cheerio.load(html);\n $('a[href]').each((_, el) => {\n try {\n const href = $(el).attr('href');\n if (!href) return;\n const resolved = new URL(href, url).href.split('#')[0].split('?')[0];\n if (isSameOrigin(baseUrl, resolved) && !visited.has(resolved)) {\n queue.push(resolved);\n }\n } catch { /* ignore invalid URLs */ }\n });\n\n if (delayMs > 0) await delay(delayMs);\n\n return { url, html, status: res.status } as CrawlResult;\n } catch {\n return null;\n }\n }),\n );\n\n const settled = await Promise.all(tasks);\n for (const r of settled) {\n if (r) results.push(r);\n }\n }\n\n return results;\n}\n","export function normalizeUrl(raw: string): string {\n let url = raw.trim();\n if (!/^https?:\\/\\//i.test(url)) url = 'https://' + url;\n return url.replace(/\\/+$/, '');\n}\n\nexport function isSameOrigin(base: string, target: string): boolean {\n try {\n return new URL(base).origin === new URL(target).origin;\n } catch {\n return false;\n }\n}\n\nexport function urlToId(url: string): string {\n return Buffer.from(url).toString('base64url');\n}\n","import axios from 'axios';\nimport { XMLParser } from 'fast-xml-parser';\n\nexport async function parseSitemap(siteUrl: string): Promise<string[]> {\n const urls: string[] = [];\n const sitemapUrl = `${siteUrl}/sitemap.xml`;\n\n try {\n const res = await axios.get(sitemapUrl, {\n timeout: 10000,\n headers: { 'User-Agent': 'AgentSite-Kit/0.1' },\n });\n\n const parser = new XMLParser();\n const parsed = parser.parse(res.data);\n\n // Handle sitemap index\n if (parsed.sitemapindex?.sitemap) {\n const sitemaps = Array.isArray(parsed.sitemapindex.sitemap)\n ? parsed.sitemapindex.sitemap\n : [parsed.sitemapindex.sitemap];\n\n for (const sm of sitemaps) {\n if (sm.loc) {\n const childUrls = await parseSitemapFromUrl(sm.loc);\n urls.push(...childUrls);\n }\n }\n }\n\n // Handle urlset\n if (parsed.urlset?.url) {\n const entries = Array.isArray(parsed.urlset.url)\n ? parsed.urlset.url\n : [parsed.urlset.url];\n for (const entry of entries) {\n if (entry.loc) urls.push(entry.loc);\n }\n }\n } catch {\n // No sitemap available, that's fine\n }\n\n return urls;\n}\n\nasync function parseSitemapFromUrl(url: string): Promise<string[]> {\n try {\n const res = await axios.get(url, {\n timeout: 10000,\n headers: { 'User-Agent': 'AgentSite-Kit/0.1' },\n });\n const parser = new XMLParser();\n const parsed = parser.parse(res.data);\n\n if (parsed.urlset?.url) {\n const entries = Array.isArray(parsed.urlset.url)\n ? parsed.urlset.url\n : [parsed.urlset.url];\n return entries.map((e: { loc: string }) => e.loc).filter(Boolean);\n }\n } catch { /* ignore */ }\n return [];\n}\n","import type { PageType } from '../types/page.js';\n\ninterface ClassifyInput {\n url: string;\n title: string;\n metaOgType?: string;\n headings: string[];\n bodyText: string;\n}\n\nconst URL_PATTERNS: [RegExp, PageType, number][] = [\n [/\\/(docs?|documentation|guide|manual|reference|api-docs)(\\/|$)/i, 'docs', 3],\n [/\\/(faq|frequently-asked|help\\/faq)(\\/|$)/i, 'faq', 3],\n [/\\/(blog|posts?|articles?|news)(\\/|$)/i, 'blog', 3],\n [/\\/(products?|features?|solutions?)(\\/|$)/i, 'product', 2],\n [/\\/(pricing|plans?|packages?)(\\/|$)/i, 'pricing', 3],\n [/\\/(about|about-us|team|company)(\\/|$)/i, 'about', 3],\n [/\\/(contact|contact-us|support)(\\/|$)/i, 'contact', 3],\n [/\\/(changelog|changes|release-notes|releases|updates|whats-new)(\\/|$)/i, 'changelog', 3],\n];\n\nconst TITLE_KEYWORDS: [RegExp, PageType, number][] = [\n [/\\b(documentation|docs|guide|reference|api)\\b/i, 'docs', 2],\n [/\\b(faq|frequently asked|common questions)\\b/i, 'faq', 2],\n [/\\b(blog|article|post)\\b/i, 'blog', 2],\n [/\\b(pricing|plans|packages)\\b/i, 'pricing', 2],\n [/\\b(product|feature|solution)\\b/i, 'product', 1],\n [/\\b(about|team|company|who we are)\\b/i, 'about', 2],\n [/\\b(contact|get in touch|support)\\b/i, 'contact', 2],\n [/\\b(changelog|release notes|what's new|updates|releases)\\b/i, 'changelog', 2],\n];\n\nexport function classifyPage(input: ClassifyInput): PageType {\n const { url, title, bodyText } = input;\n const scores = new Map<PageType, number>();\n\n const add = (type: PageType, weight: number) => {\n scores.set(type, (scores.get(type) ?? 0) + weight);\n };\n\n // Check if homepage\n try {\n const parsed = new URL(url);\n if (parsed.pathname === '/' || parsed.pathname === '') {\n return 'homepage';\n }\n } catch { /* ignore */ }\n\n // URL patterns\n for (const [pattern, type, weight] of URL_PATTERNS) {\n if (pattern.test(url)) add(type, weight);\n }\n\n // Title keywords\n for (const [pattern, type, weight] of TITLE_KEYWORDS) {\n if (pattern.test(title)) add(type, weight);\n }\n\n // Content features\n const qaPairs = (bodyText.match(/\\?[\\s\\n]/g) || []).length;\n if (qaPairs >= 3) add('faq', 2);\n\n if (/\\$\\d+|\\d+\\/mo|per month|free tier/i.test(bodyText)) add('pricing', 2);\n\n // Pick highest score\n let best: PageType = 'unknown';\n let bestScore = 1; // threshold\n for (const [type, score] of scores) {\n if (score > bestScore) {\n best = type;\n bestScore = score;\n }\n }\n\n return best;\n}\n","import { chatCompletion, type LlmConfig } from './client.js';\nimport type { PageType } from '../types/page.js';\n\nconst VALID_TYPES: PageType[] = ['homepage', 'docs', 'faq', 'blog', 'product', 'pricing', 'about', 'contact', 'unknown'];\n\nexport async function llmClassifyPage(\n config: LlmConfig,\n url: string,\n title: string,\n bodyText: string,\n): Promise<PageType> {\n const truncated = bodyText.slice(0, 2000);\n const response = await chatCompletion(config, [\n {\n role: 'system',\n content: `You are a web page classifier. Classify the page into exactly one of these types: ${VALID_TYPES.join(', ')}. Reply with only the type name, nothing else.`,\n },\n {\n role: 'user',\n content: `URL: ${url}\\nTitle: ${title}\\n\\nContent:\\n${truncated}`,\n },\n ], { temperature: 0.1, maxTokens: 32 });\n\n const cleaned = response.toLowerCase().trim() as PageType;\n if (VALID_TYPES.includes(cleaned)) return cleaned;\n return 'unknown';\n}\n"],"mappings":"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","names":["writeFileSync","mkdirSync","axios","mkdirSync","writeFileSync"]}
@@ -0,0 +1,360 @@
1
+ // src/utils/logger.ts
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ var log = {
5
+ info: (msg) => console.log(chalk.blue("\u2139"), msg),
6
+ success: (msg) => console.log(chalk.green("\u2714"), msg),
7
+ warn: (msg) => console.log(chalk.yellow("\u26A0"), msg),
8
+ error: (msg) => console.log(chalk.red("\u2716"), msg)
9
+ };
10
+ function spinner(text) {
11
+ return ora({ text, color: "cyan" }).start();
12
+ }
13
+
14
+ // src/config/loader.ts
15
+ import { readFileSync, existsSync } from "fs";
16
+ import yaml from "js-yaml";
17
+
18
+ // src/config/schema.ts
19
+ import { z } from "zod";
20
+ var siteInfoSchema = z.object({
21
+ url: z.string().url(),
22
+ name: z.string().min(1),
23
+ description: z.string().default("")
24
+ });
25
+ var scanSchema = z.object({
26
+ maxPages: z.number().int().positive().default(100),
27
+ concurrency: z.number().int().positive().default(3),
28
+ delayMs: z.number().int().nonnegative().default(200),
29
+ include: z.array(z.string()).default(["**"]),
30
+ exclude: z.array(z.string()).default([]),
31
+ respectRobotsTxt: z.boolean().default(true)
32
+ }).default({});
33
+ var outputSchema = z.object({
34
+ dir: z.string().default(".agentsite"),
35
+ formats: z.array(z.enum(["llms-txt", "agent-sitemap", "agent-index", "structured"])).default(["llms-txt", "agent-sitemap", "agent-index", "structured"])
36
+ }).default({});
37
+ var accessSchema = z.object({
38
+ allowedPages: z.array(z.string()).default(["**"]),
39
+ blockedPages: z.array(z.string()).default([]),
40
+ allowedTypes: z.array(z.string()).default(["docs", "faq", "blog", "product", "pricing", "about", "contact", "changelog"]),
41
+ summaryOnly: z.boolean().default(false),
42
+ allowSearch: z.boolean().default(true)
43
+ }).default({});
44
+ var siteEntrySchema = z.object({
45
+ site: siteInfoSchema,
46
+ scan: scanSchema,
47
+ output: outputSchema,
48
+ access: accessSchema
49
+ });
50
+ var configSchema = z.object({
51
+ site: siteInfoSchema,
52
+ scan: scanSchema,
53
+ output: outputSchema,
54
+ server: z.object({
55
+ port: z.number().int().positive().default(3141),
56
+ rateLimit: z.object({
57
+ max: z.number().int().positive().default(60),
58
+ timeWindow: z.string().default("1 minute")
59
+ }).default({}),
60
+ accessLog: z.boolean().default(true)
61
+ }).default({}),
62
+ llm: z.object({
63
+ apiUrl: z.string().default("https://integrate.api.nvidia.com/v1"),
64
+ apiKey: z.string().default("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"),
65
+ model: z.string().default("minimaxai/minimax-m2.5")
66
+ }).optional(),
67
+ access: accessSchema,
68
+ plugins: z.array(z.string()).default([]),
69
+ sites: z.array(siteEntrySchema).optional()
70
+ });
71
+
72
+ // src/config/loader.ts
73
+ var CONFIG_FILES = ["agentsite.config.yaml", "agentsite.config.yml", "agentsite.config.json"];
74
+ function loadConfig(cwd = process.cwd()) {
75
+ for (const file of CONFIG_FILES) {
76
+ const filepath = `${cwd}/${file}`;
77
+ if (!existsSync(filepath)) continue;
78
+ const raw = readFileSync(filepath, "utf-8");
79
+ const parsed = file.endsWith(".json") ? JSON.parse(raw) : yaml.load(raw);
80
+ const config = configSchema.parse(parsed);
81
+ return normalizeConfig(config);
82
+ }
83
+ throw new Error("Config file not found. Run `agentsite init` first.");
84
+ }
85
+ function normalizeConfig(config) {
86
+ const resolvedSites = config.sites && config.sites.length > 0 ? config.sites : [{
87
+ site: config.site,
88
+ scan: config.scan,
89
+ output: config.output,
90
+ access: config.access
91
+ }];
92
+ return { ...config, resolvedSites };
93
+ }
94
+ function toSlug(name) {
95
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
96
+ }
97
+
98
+ // src/utils/hash.ts
99
+ import { createHash } from "crypto";
100
+ function sha256(content) {
101
+ return createHash("sha256").update(content).digest("hex");
102
+ }
103
+
104
+ // src/scanner/content-extractor.ts
105
+ import * as cheerio from "cheerio";
106
+ var REMOVE_SELECTORS = "nav, footer, header, aside, .sidebar, .nav, .footer, .header, script, style, noscript, iframe, svg";
107
+ function extractContent(html, url) {
108
+ const $ = cheerio.load(html);
109
+ const title = $('meta[property="og:title"]').attr("content") || $("title").text().trim() || $("h1").first().text().trim() || "";
110
+ const metaOgType = $('meta[property="og:type"]').attr("content");
111
+ const lastModified = $('meta[property="article:modified_time"]').attr("content") || $('meta[name="last-modified"]').attr("content") || void 0;
112
+ const author = $('meta[name="author"]').attr("content") || $('meta[property="article:author"]').attr("content") || $(".author").first().text().trim() || void 0;
113
+ const publishedAt = $('meta[property="article:published_time"]').attr("content") || $('meta[name="date"]').attr("content") || $("time[datetime]").first().attr("datetime") || void 0;
114
+ const tags = [];
115
+ $('meta[property="article:tag"]').each((_, el) => {
116
+ const tag = $(el).attr("content")?.trim();
117
+ if (tag) tags.push(tag);
118
+ });
119
+ $('meta[name="keywords"]').attr("content")?.split(",").forEach((k) => {
120
+ const tag = k.trim();
121
+ if (tag) tags.push(tag);
122
+ });
123
+ $(REMOVE_SELECTORS).remove();
124
+ const headings = [];
125
+ $("h1, h2, h3").each((_, el) => {
126
+ const text = $(el).text().trim();
127
+ if (text) headings.push(text);
128
+ });
129
+ const bodyText = $("body").text().replace(/\s+/g, " ").trim();
130
+ const wordCount = bodyText.split(/\s+/).filter(Boolean).length;
131
+ const version = $('meta[name="version"]').attr("content") || bodyText.match(/v?\d+\.\d+\.\d+/)?.[0] || void 0;
132
+ const faqItems = [];
133
+ $("details").each((_, el) => {
134
+ const q = $(el).find("summary").text().trim();
135
+ const a = $(el).clone().find("summary").remove().end().text().trim();
136
+ if (q && a) faqItems.push({ question: q, answer: a });
137
+ });
138
+ $("dt").each((_, el) => {
139
+ const q = $(el).text().trim();
140
+ const a = $(el).next("dd").text().trim();
141
+ if (q && a) faqItems.push({ question: q, answer: a });
142
+ });
143
+ const features = [];
144
+ $("ul li, ol li").each((_, el) => {
145
+ const text = $(el).text().trim();
146
+ if (text.length > 10 && text.length < 200) features.push(text);
147
+ });
148
+ const summary = $('meta[name="description"]').attr("content")?.trim() || $('meta[property="og:description"]').attr("content")?.trim() || bodyText.slice(0, 200);
149
+ return {
150
+ title,
151
+ summary,
152
+ headings,
153
+ bodyText,
154
+ metaOgType,
155
+ faqItems,
156
+ features: features.slice(0, 20),
157
+ lastModified,
158
+ wordCount,
159
+ tags: tags.length > 0 ? tags : void 0,
160
+ version,
161
+ author,
162
+ publishedAt
163
+ };
164
+ }
165
+
166
+ // src/llm/client.ts
167
+ import axios from "axios";
168
+ function getLlmConfig(config) {
169
+ const apiUrl = process.env.AGENTSITE_LLM_API_URL || config?.llm?.apiUrl;
170
+ const apiKey = process.env.AGENTSITE_LLM_API_KEY || config?.llm?.apiKey;
171
+ const model = process.env.AGENTSITE_LLM_MODEL || config?.llm?.model;
172
+ if (!apiUrl || !apiKey || !model) return null;
173
+ return { apiUrl, apiKey, model };
174
+ }
175
+ async function chatCompletion(config, messages, options) {
176
+ const res = await axios.post(
177
+ `${config.apiUrl}/chat/completions`,
178
+ {
179
+ model: config.model,
180
+ messages,
181
+ temperature: options?.temperature ?? 0.3,
182
+ top_p: 0.95,
183
+ max_tokens: options?.maxTokens ?? 1024,
184
+ stream: false
185
+ },
186
+ {
187
+ headers: {
188
+ "Content-Type": "application/json",
189
+ Authorization: `Bearer ${config.apiKey}`
190
+ },
191
+ timeout: 3e4
192
+ }
193
+ );
194
+ return res.data.choices[0]?.message?.content?.trim() ?? "";
195
+ }
196
+
197
+ // src/llm/summarizer.ts
198
+ async function llmSummarize(config, title, bodyText) {
199
+ const truncated = bodyText.slice(0, 3e3);
200
+ const response = await chatCompletion(config, [
201
+ {
202
+ role: "system",
203
+ content: "You are a concise content summarizer. Summarize the following web page content in 1-2 sentences. Focus on what this page is about and its key information. Reply in the same language as the content."
204
+ },
205
+ {
206
+ role: "user",
207
+ content: `Title: ${title}
208
+
209
+ Content:
210
+ ${truncated}`
211
+ }
212
+ ], { maxTokens: 256 });
213
+ return response;
214
+ }
215
+ async function llmExtractTags(config, title, bodyText) {
216
+ const truncated = bodyText.slice(0, 2e3);
217
+ const response = await chatCompletion(config, [
218
+ {
219
+ role: "system",
220
+ content: 'Extract 3-5 relevant tags/keywords from the following web page. Return only a JSON array of strings, nothing else. Example: ["tag1", "tag2", "tag3"]'
221
+ },
222
+ {
223
+ role: "user",
224
+ content: `Title: ${title}
225
+
226
+ Content:
227
+ ${truncated}`
228
+ }
229
+ ], { maxTokens: 128 });
230
+ try {
231
+ const parsed = JSON.parse(response);
232
+ if (Array.isArray(parsed)) return parsed.map(String);
233
+ } catch {
234
+ }
235
+ return [];
236
+ }
237
+
238
+ // src/plugins/builtin/wordpress.ts
239
+ var plugin = {
240
+ name: "wordpress",
241
+ version: "1.0.0",
242
+ hooks: {
243
+ async afterScan(pages) {
244
+ return pages.map((page) => {
245
+ const url = page.url.toLowerCase();
246
+ if (url.includes("/wp-content/") || url.includes("/wp-json/")) {
247
+ return page;
248
+ }
249
+ if (url.includes("/category/")) {
250
+ return { ...page, tags: [...page.tags ?? [], "wordpress-category"] };
251
+ }
252
+ if (url.includes("/tag/")) {
253
+ return { ...page, tags: [...page.tags ?? [], "wordpress-tag"] };
254
+ }
255
+ if (url.includes("/author/")) {
256
+ return { ...page, tags: [...page.tags ?? [], "wordpress-author"] };
257
+ }
258
+ return page;
259
+ });
260
+ }
261
+ }
262
+ };
263
+ var wordpress_default = plugin;
264
+
265
+ // src/plugins/builtin/static-site.ts
266
+ var STATIC_SITE_PATTERNS = {
267
+ hugo: ["/tags/", "/categories/", "/posts/", "/page/"],
268
+ jekyll: ["/jekyll/", "/_site/", "/collections/"],
269
+ docusaurus: ["/docs/", "/blog/", "/community/"],
270
+ gatsby: ["/gatsby/", "/blog/", "/tags/"],
271
+ vitepress: ["/guide/", "/api/", "/config/"],
272
+ nextjs: ["/_next/", "/api/"]
273
+ };
274
+ var plugin2 = {
275
+ name: "static-site",
276
+ version: "1.0.0",
277
+ hooks: {
278
+ async afterScan(pages) {
279
+ const urlSample = pages.slice(0, 50).map((p) => p.url.toLowerCase());
280
+ let detectedGenerator = null;
281
+ for (const [generator, patterns] of Object.entries(STATIC_SITE_PATTERNS)) {
282
+ const matchCount = patterns.filter(
283
+ (pat) => urlSample.some((url) => url.includes(pat))
284
+ ).length;
285
+ if (matchCount >= 2) {
286
+ detectedGenerator = generator;
287
+ break;
288
+ }
289
+ }
290
+ if (!detectedGenerator) return pages;
291
+ return pages.map((page) => ({
292
+ ...page,
293
+ tags: [...page.tags ?? [], `ssg-${detectedGenerator}`]
294
+ }));
295
+ }
296
+ }
297
+ };
298
+ var static_site_default = plugin2;
299
+
300
+ // src/plugins/loader.ts
301
+ var BUILTIN_PLUGINS = {
302
+ "wordpress": wordpress_default,
303
+ "static-site": static_site_default
304
+ };
305
+ async function loadPlugins(pluginNames) {
306
+ const plugins = [];
307
+ for (const name of pluginNames) {
308
+ try {
309
+ let plugin3;
310
+ if (name in BUILTIN_PLUGINS) {
311
+ plugin3 = BUILTIN_PLUGINS[name];
312
+ } else if (name.startsWith("./") || name.startsWith("../") || name.startsWith("/")) {
313
+ const mod = await import(name);
314
+ plugin3 = mod.default ?? mod;
315
+ } else {
316
+ const mod = await import(`agentsite-plugin-${name}`);
317
+ plugin3 = mod.default ?? mod;
318
+ }
319
+ plugins.push(plugin3);
320
+ log.info(`Loaded plugin: ${plugin3.name} v${plugin3.version}`);
321
+ } catch (err) {
322
+ log.warn(`Failed to load plugin "${name}": ${err.message}`);
323
+ }
324
+ }
325
+ return plugins;
326
+ }
327
+ async function runHook(plugins, hook, ...args) {
328
+ for (const plugin3 of plugins) {
329
+ const fn = plugin3.hooks?.[hook];
330
+ if (fn) {
331
+ await fn(...args);
332
+ }
333
+ }
334
+ }
335
+ async function runAfterScan(plugins, pages) {
336
+ let result = pages;
337
+ for (const plugin3 of plugins) {
338
+ if (plugin3.hooks?.afterScan) {
339
+ result = await plugin3.hooks.afterScan(result);
340
+ }
341
+ }
342
+ return result;
343
+ }
344
+
345
+ export {
346
+ log,
347
+ spinner,
348
+ loadConfig,
349
+ toSlug,
350
+ sha256,
351
+ extractContent,
352
+ getLlmConfig,
353
+ chatCompletion,
354
+ llmSummarize,
355
+ llmExtractTags,
356
+ loadPlugins,
357
+ runHook,
358
+ runAfterScan
359
+ };
360
+ //# sourceMappingURL=chunk-YWUDTSOR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/logger.ts","../src/config/loader.ts","../src/config/schema.ts","../src/utils/hash.ts","../src/scanner/content-extractor.ts","../src/llm/client.ts","../src/llm/summarizer.ts","../src/plugins/builtin/wordpress.ts","../src/plugins/builtin/static-site.ts","../src/plugins/loader.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nexport const log = {\n info: (msg: string) => console.log(chalk.blue('ℹ'), msg),\n success: (msg: string) => console.log(chalk.green('✔'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.log(chalk.red('✖'), msg),\n};\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' }).start();\n}\n","import { readFileSync, existsSync } from 'node:fs';\nimport yaml from 'js-yaml';\nimport { configSchema, type ValidatedConfig, type SiteEntry } from './schema.js';\n\nconst CONFIG_FILES = ['agentsite.config.yaml', 'agentsite.config.yml', 'agentsite.config.json'];\n\nexport interface NormalizedConfig extends ValidatedConfig {\n /** Always populated: either from `sites` array or auto-wrapped from single-site fields */\n resolvedSites: SiteEntry[];\n}\n\nexport function loadConfig(cwd: string = process.cwd()): NormalizedConfig {\n for (const file of CONFIG_FILES) {\n const filepath = `${cwd}/${file}`;\n if (!existsSync(filepath)) continue;\n\n const raw = readFileSync(filepath, 'utf-8');\n const parsed = file.endsWith('.json') ? JSON.parse(raw) : yaml.load(raw);\n const config = configSchema.parse(parsed);\n\n return normalizeConfig(config);\n }\n\n throw new Error('Config file not found. Run `agentsite init` first.');\n}\n\nfunction normalizeConfig(config: ValidatedConfig): NormalizedConfig {\n const resolvedSites: SiteEntry[] = config.sites && config.sites.length > 0\n ? config.sites\n : [{\n site: config.site,\n scan: config.scan,\n output: config.output,\n access: config.access,\n }];\n\n return { ...config, resolvedSites };\n}\n\n/** Convert a site name to a URL-safe slug */\nexport function toSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n}\n","import { z } from 'zod';\n\nconst siteInfoSchema = z.object({\n url: z.string().url(),\n name: z.string().min(1),\n description: z.string().default(''),\n});\n\nconst scanSchema = z.object({\n maxPages: z.number().int().positive().default(100),\n concurrency: z.number().int().positive().default(3),\n delayMs: z.number().int().nonnegative().default(200),\n include: z.array(z.string()).default(['**']),\n exclude: z.array(z.string()).default([]),\n respectRobotsTxt: z.boolean().default(true),\n}).default({});\n\nconst outputSchema = z.object({\n dir: z.string().default('.agentsite'),\n formats: z.array(z.enum(['llms-txt', 'agent-sitemap', 'agent-index', 'structured'])).default(['llms-txt', 'agent-sitemap', 'agent-index', 'structured']),\n}).default({});\n\nconst accessSchema = z.object({\n allowedPages: z.array(z.string()).default(['**']),\n blockedPages: z.array(z.string()).default([]),\n allowedTypes: z.array(z.string()).default(['docs', 'faq', 'blog', 'product', 'pricing', 'about', 'contact', 'changelog']),\n summaryOnly: z.boolean().default(false),\n allowSearch: z.boolean().default(true),\n}).default({});\n\nconst siteEntrySchema = z.object({\n site: siteInfoSchema,\n scan: scanSchema,\n output: outputSchema,\n access: accessSchema,\n});\n\nexport const configSchema = z.object({\n site: siteInfoSchema,\n scan: scanSchema,\n output: outputSchema,\n server: z.object({\n port: z.number().int().positive().default(3141),\n rateLimit: z.object({\n max: z.number().int().positive().default(60),\n timeWindow: z.string().default('1 minute'),\n }).default({}),\n accessLog: z.boolean().default(true),\n }).default({}),\n llm: z.object({\n apiUrl: z.string().default('https://integrate.api.nvidia.com/v1'),\n apiKey: z.string().default('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'),\n model: z.string().default('minimaxai/minimax-m2.5'),\n }).optional(),\n access: accessSchema,\n plugins: z.array(z.string()).default([]),\n sites: z.array(siteEntrySchema).optional(),\n});\n\nexport type ValidatedConfig = z.infer<typeof configSchema>;\nexport type SiteEntry = z.infer<typeof siteEntrySchema>;\n","import { createHash } from 'node:crypto';\n\nexport function sha256(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n","import * as cheerio from 'cheerio';\n\nexport interface ExtractedContent {\n title: string;\n summary: string;\n headings: string[];\n bodyText: string;\n metaOgType?: string;\n faqItems: { question: string; answer: string }[];\n features: string[];\n lastModified?: string;\n wordCount: number;\n tags?: string[];\n version?: string;\n author?: string;\n publishedAt?: string;\n}\n\nconst REMOVE_SELECTORS = 'nav, footer, header, aside, .sidebar, .nav, .footer, .header, script, style, noscript, iframe, svg';\n\nexport function extractContent(html: string, url: string): ExtractedContent {\n const $ = cheerio.load(html);\n\n const title =\n $('meta[property=\"og:title\"]').attr('content') ||\n $('title').text().trim() ||\n $('h1').first().text().trim() ||\n '';\n\n const metaOgType = $('meta[property=\"og:type\"]').attr('content');\n\n const lastModified =\n $('meta[property=\"article:modified_time\"]').attr('content') ||\n $('meta[name=\"last-modified\"]').attr('content') ||\n undefined;\n\n const author =\n $('meta[name=\"author\"]').attr('content') ||\n $('meta[property=\"article:author\"]').attr('content') ||\n $('.author').first().text().trim() ||\n undefined;\n\n const publishedAt =\n $('meta[property=\"article:published_time\"]').attr('content') ||\n $('meta[name=\"date\"]').attr('content') ||\n $('time[datetime]').first().attr('datetime') ||\n undefined;\n\n const tags: string[] = [];\n $('meta[property=\"article:tag\"]').each((_, el) => {\n const tag = $(el).attr('content')?.trim();\n if (tag) tags.push(tag);\n });\n $('meta[name=\"keywords\"]').attr('content')?.split(',').forEach(k => {\n const tag = k.trim();\n if (tag) tags.push(tag);\n });\n\n // Remove non-content elements\n $(REMOVE_SELECTORS).remove();\n\n // Extract headings\n const headings: string[] = [];\n $('h1, h2, h3').each((_, el) => {\n const text = $(el).text().trim();\n if (text) headings.push(text);\n });\n\n // Extract body text\n const bodyText = $('body').text().replace(/\\s+/g, ' ').trim();\n const wordCount = bodyText.split(/\\s+/).filter(Boolean).length;\n\n const version =\n $('meta[name=\"version\"]').attr('content') ||\n bodyText.match(/v?\\d+\\.\\d+\\.\\d+/)?.[0] ||\n undefined;\n\n // Extract FAQ items\n const faqItems: { question: string; answer: string }[] = [];\n\n // Pattern 1: details/summary\n $('details').each((_, el) => {\n const q = $(el).find('summary').text().trim();\n const a = $(el).clone().find('summary').remove().end().text().trim();\n if (q && a) faqItems.push({ question: q, answer: a });\n });\n\n // Pattern 2: dt/dd\n $('dt').each((_, el) => {\n const q = $(el).text().trim();\n const a = $(el).next('dd').text().trim();\n if (q && a) faqItems.push({ question: q, answer: a });\n });\n\n // Extract features (list items in product-like pages)\n const features: string[] = [];\n $('ul li, ol li').each((_, el) => {\n const text = $(el).text().trim();\n if (text.length > 10 && text.length < 200) features.push(text);\n });\n\n // Summary: meta description or first 200 chars\n const summary =\n $('meta[name=\"description\"]').attr('content')?.trim() ||\n $('meta[property=\"og:description\"]').attr('content')?.trim() ||\n bodyText.slice(0, 200);\n\n return {\n title,\n summary,\n headings,\n bodyText,\n metaOgType,\n faqItems,\n features: features.slice(0, 20),\n lastModified,\n wordCount,\n tags: tags.length > 0 ? tags : undefined,\n version,\n author,\n publishedAt,\n };\n}\n","import axios from 'axios';\nimport type { AgentSiteConfig } from '../types/config.js';\n\nexport interface LlmConfig {\n apiUrl: string;\n apiKey: string;\n model: string;\n}\n\nexport interface ChatMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\nexport function getLlmConfig(config?: AgentSiteConfig): LlmConfig | null {\n // Priority: env vars > config file\n const apiUrl = process.env.AGENTSITE_LLM_API_URL || config?.llm?.apiUrl;\n const apiKey = process.env.AGENTSITE_LLM_API_KEY || config?.llm?.apiKey;\n const model = process.env.AGENTSITE_LLM_MODEL || config?.llm?.model;\n\n if (!apiUrl || !apiKey || !model) return null;\n return { apiUrl, apiKey, model };\n}\n\nexport async function chatCompletion(\n config: LlmConfig,\n messages: ChatMessage[],\n options?: { temperature?: number; maxTokens?: number },\n): Promise<string> {\n const res = await axios.post(\n `${config.apiUrl}/chat/completions`,\n {\n model: config.model,\n messages,\n temperature: options?.temperature ?? 0.3,\n top_p: 0.95,\n max_tokens: options?.maxTokens ?? 1024,\n stream: false,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`,\n },\n timeout: 30000,\n },\n );\n\n return res.data.choices[0]?.message?.content?.trim() ?? '';\n}\n","import { chatCompletion, type LlmConfig } from './client.js';\n\nexport async function llmSummarize(config: LlmConfig, title: string, bodyText: string): Promise<string> {\n const truncated = bodyText.slice(0, 3000);\n const response = await chatCompletion(config, [\n {\n role: 'system',\n content: 'You are a concise content summarizer. Summarize the following web page content in 1-2 sentences. Focus on what this page is about and its key information. Reply in the same language as the content.',\n },\n {\n role: 'user',\n content: `Title: ${title}\\n\\nContent:\\n${truncated}`,\n },\n ], { maxTokens: 256 });\n\n return response;\n}\n\nexport async function llmExtractTags(config: LlmConfig, title: string, bodyText: string): Promise<string[]> {\n const truncated = bodyText.slice(0, 2000);\n const response = await chatCompletion(config, [\n {\n role: 'system',\n content: 'Extract 3-5 relevant tags/keywords from the following web page. Return only a JSON array of strings, nothing else. Example: [\"tag1\", \"tag2\", \"tag3\"]',\n },\n {\n role: 'user',\n content: `Title: ${title}\\n\\nContent:\\n${truncated}`,\n },\n ], { maxTokens: 128 });\n\n try {\n const parsed = JSON.parse(response);\n if (Array.isArray(parsed)) return parsed.map(String);\n } catch { /* ignore parse error */ }\n return [];\n}\n","import type { AgentSitePlugin } from '../types.js';\n\nconst plugin: AgentSitePlugin = {\n name: 'wordpress',\n version: '1.0.0',\n hooks: {\n async afterScan(pages) {\n return pages.map((page) => {\n const url = page.url.toLowerCase();\n\n // Detect WordPress patterns and enhance classification\n if (url.includes('/wp-content/') || url.includes('/wp-json/')) {\n // Already classified, skip\n return page;\n }\n\n // WordPress category/tag archives\n if (url.includes('/category/')) {\n return { ...page, tags: [...(page.tags ?? []), 'wordpress-category'] };\n }\n if (url.includes('/tag/')) {\n return { ...page, tags: [...(page.tags ?? []), 'wordpress-tag'] };\n }\n\n // WordPress author pages\n if (url.includes('/author/')) {\n return { ...page, tags: [...(page.tags ?? []), 'wordpress-author'] };\n }\n\n return page;\n });\n },\n },\n};\n\nexport default plugin;\n","import type { AgentSitePlugin } from '../types.js';\n\nconst STATIC_SITE_PATTERNS: Record<string, string[]> = {\n hugo: ['/tags/', '/categories/', '/posts/', '/page/'],\n jekyll: ['/jekyll/', '/_site/', '/collections/'],\n docusaurus: ['/docs/', '/blog/', '/community/'],\n gatsby: ['/gatsby/', '/blog/', '/tags/'],\n vitepress: ['/guide/', '/api/', '/config/'],\n nextjs: ['/_next/', '/api/'],\n};\n\nconst plugin: AgentSitePlugin = {\n name: 'static-site',\n version: '1.0.0',\n hooks: {\n async afterScan(pages) {\n // Detect which static site generator is likely in use\n const urlSample = pages.slice(0, 50).map((p) => p.url.toLowerCase());\n let detectedGenerator: string | null = null;\n\n for (const [generator, patterns] of Object.entries(STATIC_SITE_PATTERNS)) {\n const matchCount = patterns.filter((pat) =>\n urlSample.some((url) => url.includes(pat))\n ).length;\n if (matchCount >= 2) {\n detectedGenerator = generator;\n break;\n }\n }\n\n if (!detectedGenerator) return pages;\n\n return pages.map((page) => ({\n ...page,\n tags: [...(page.tags ?? []), `ssg-${detectedGenerator}`],\n }));\n },\n },\n};\n\nexport default plugin;\n","import type { AgentSitePlugin } from './types.js';\nimport { log } from '../utils/logger.js';\nimport wordpressPlugin from './builtin/wordpress.js';\nimport staticSitePlugin from './builtin/static-site.js';\n\nconst BUILTIN_PLUGINS: Record<string, AgentSitePlugin> = {\n 'wordpress': wordpressPlugin,\n 'static-site': staticSitePlugin,\n};\n\nexport async function loadPlugins(pluginNames: string[]): Promise<AgentSitePlugin[]> {\n const plugins: AgentSitePlugin[] = [];\n\n for (const name of pluginNames) {\n try {\n let plugin: AgentSitePlugin;\n\n if (name in BUILTIN_PLUGINS) {\n plugin = BUILTIN_PLUGINS[name];\n } else if (name.startsWith('./') || name.startsWith('../') || name.startsWith('/')) {\n const mod = await import(name);\n plugin = mod.default ?? mod;\n } else {\n const mod = await import(`agentsite-plugin-${name}`);\n plugin = mod.default ?? mod;\n }\n\n plugins.push(plugin);\n log.info(`Loaded plugin: ${plugin.name} v${plugin.version}`);\n } catch (err) {\n log.warn(`Failed to load plugin \"${name}\": ${(err as Error).message}`);\n }\n }\n\n return plugins;\n}\n\nexport async function runHook<K extends keyof NonNullable<AgentSitePlugin['hooks']>>(\n plugins: AgentSitePlugin[],\n hook: K,\n ...args: Parameters<NonNullable<NonNullable<AgentSitePlugin['hooks']>[K]>>\n): Promise<void> {\n for (const plugin of plugins) {\n const fn = plugin.hooks?.[hook];\n if (fn) {\n await (fn as (...a: unknown[]) => Promise<unknown>)(...args);\n }\n }\n}\n\nexport async function runAfterScan(plugins: AgentSitePlugin[], pages: import('../types/page.js').ScannedPage[]): Promise<import('../types/page.js').ScannedPage[]> {\n let result = pages;\n for (const plugin of plugins) {\n if (plugin.hooks?.afterScan) {\n result = await plugin.hooks.afterScan(result);\n }\n }\n return result;\n}\n"],"mappings":";AAAA,OAAO,WAAW;AAClB,OAAO,SAAuB;AAEvB,IAAM,MAAM;AAAA,EACjB,MAAM,CAAC,QAAgB,QAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,GAAG;AAAA,EACvD,SAAS,CAAC,QAAgB,QAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,GAAG;AAAA,EAC3D,MAAM,CAAC,QAAgB,QAAQ,IAAI,MAAM,OAAO,QAAG,GAAG,GAAG;AAAA,EACzD,OAAO,CAAC,QAAgB,QAAQ,IAAI,MAAM,IAAI,QAAG,GAAG,GAAG;AACzD;AAEO,SAAS,QAAQ,MAAmB;AACzC,SAAO,IAAI,EAAE,MAAM,OAAO,OAAO,CAAC,EAAE,MAAM;AAC5C;;;ACZA,SAAS,cAAc,kBAAkB;AACzC,OAAO,UAAU;;;ACDjB,SAAS,SAAS;AAElB,IAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,KAAK,EAAE,OAAO,EAAE,IAAI;AAAA,EACpB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE;AACpC,CAAC;AAED,IAAM,aAAa,EAAE,OAAO;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAG;AAAA,EACjD,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EAClD,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,GAAG;AAAA,EACnD,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC;AAAA,EAC3C,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACvC,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAC5C,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,KAAK,EAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,EACpC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,YAAY,iBAAiB,eAAe,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,YAAY,iBAAiB,eAAe,YAAY,CAAC;AACzJ,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC;AAAA,EAChD,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC5C,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,QAAQ,OAAO,QAAQ,WAAW,WAAW,SAAS,WAAW,WAAW,CAAC;AAAA,EACxH,aAAa,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACtC,aAAa,EAAE,QAAQ,EAAE,QAAQ,IAAI;AACvC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AACV,CAAC;AAEM,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ,EAAE,OAAO;AAAA,IACf,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,IAAI;AAAA,IAC9C,WAAW,EAAE,OAAO;AAAA,MAClB,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE;AAAA,MAC3C,YAAY,EAAE,OAAO,EAAE,QAAQ,UAAU;AAAA,IAC3C,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IACb,WAAW,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACrC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACb,KAAK,EAAE,OAAO;AAAA,IACZ,QAAQ,EAAE,OAAO,EAAE,QAAQ,qCAAqC;AAAA,IAChE,QAAQ,EAAE,OAAO,EAAE,QAAQ,wEAAwE;AAAA,IACnG,OAAO,EAAE,OAAO,EAAE,QAAQ,wBAAwB;AAAA,EACpD,CAAC,EAAE,SAAS;AAAA,EACZ,QAAQ;AAAA,EACR,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACvC,OAAO,EAAE,MAAM,eAAe,EAAE,SAAS;AAC3C,CAAC;;;ADrDD,IAAM,eAAe,CAAC,yBAAyB,wBAAwB,uBAAuB;AAOvF,SAAS,WAAW,MAAc,QAAQ,IAAI,GAAqB;AACxE,aAAW,QAAQ,cAAc;AAC/B,UAAM,WAAW,GAAG,GAAG,IAAI,IAAI;AAC/B,QAAI,CAAC,WAAW,QAAQ,EAAG;AAE3B,UAAM,MAAM,aAAa,UAAU,OAAO;AAC1C,UAAM,SAAS,KAAK,SAAS,OAAO,IAAI,KAAK,MAAM,GAAG,IAAI,KAAK,KAAK,GAAG;AACvE,UAAM,SAAS,aAAa,MAAM,MAAM;AAExC,WAAO,gBAAgB,MAAM;AAAA,EAC/B;AAEA,QAAM,IAAI,MAAM,oDAAoD;AACtE;AAEA,SAAS,gBAAgB,QAA2C;AAClE,QAAM,gBAA6B,OAAO,SAAS,OAAO,MAAM,SAAS,IACrE,OAAO,QACP,CAAC;AAAA,IACC,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,EACjB,CAAC;AAEL,SAAO,EAAE,GAAG,QAAQ,cAAc;AACpC;AAGO,SAAS,OAAO,MAAsB;AAC3C,SAAO,KACJ,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,UAAU,EAAE;AACzB;;;AE7CA,SAAS,kBAAkB;AAEpB,SAAS,OAAO,SAAyB;AAC9C,SAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAC1D;;;ACJA,YAAY,aAAa;AAkBzB,IAAM,mBAAmB;AAElB,SAAS,eAAe,MAAc,KAA+B;AAC1E,QAAM,IAAY,aAAK,IAAI;AAE3B,QAAM,QACJ,EAAE,2BAA2B,EAAE,KAAK,SAAS,KAC7C,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,KACvB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAC5B;AAEF,QAAM,aAAa,EAAE,0BAA0B,EAAE,KAAK,SAAS;AAE/D,QAAM,eACJ,EAAE,wCAAwC,EAAE,KAAK,SAAS,KAC1D,EAAE,4BAA4B,EAAE,KAAK,SAAS,KAC9C;AAEF,QAAM,SACJ,EAAE,qBAAqB,EAAE,KAAK,SAAS,KACvC,EAAE,iCAAiC,EAAE,KAAK,SAAS,KACnD,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KACjC;AAEF,QAAM,cACJ,EAAE,yCAAyC,EAAE,KAAK,SAAS,KAC3D,EAAE,mBAAmB,EAAE,KAAK,SAAS,KACrC,EAAE,gBAAgB,EAAE,MAAM,EAAE,KAAK,UAAU,KAC3C;AAEF,QAAM,OAAiB,CAAC;AACxB,IAAE,8BAA8B,EAAE,KAAK,CAAC,GAAG,OAAO;AAChD,UAAM,MAAM,EAAE,EAAE,EAAE,KAAK,SAAS,GAAG,KAAK;AACxC,QAAI,IAAK,MAAK,KAAK,GAAG;AAAA,EACxB,CAAC;AACD,IAAE,uBAAuB,EAAE,KAAK,SAAS,GAAG,MAAM,GAAG,EAAE,QAAQ,OAAK;AAClE,UAAM,MAAM,EAAE,KAAK;AACnB,QAAI,IAAK,MAAK,KAAK,GAAG;AAAA,EACxB,CAAC;AAGD,IAAE,gBAAgB,EAAE,OAAO;AAG3B,QAAM,WAAqB,CAAC;AAC5B,IAAE,YAAY,EAAE,KAAK,CAAC,GAAG,OAAO;AAC9B,UAAM,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK;AAC/B,QAAI,KAAM,UAAS,KAAK,IAAI;AAAA,EAC9B,CAAC;AAGD,QAAM,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC5D,QAAM,YAAY,SAAS,MAAM,KAAK,EAAE,OAAO,OAAO,EAAE;AAExD,QAAM,UACJ,EAAE,sBAAsB,EAAE,KAAK,SAAS,KACxC,SAAS,MAAM,iBAAiB,IAAI,CAAC,KACrC;AAGF,QAAM,WAAmD,CAAC;AAG1D,IAAE,SAAS,EAAE,KAAK,CAAC,GAAG,OAAO;AAC3B,UAAM,IAAI,EAAE,EAAE,EAAE,KAAK,SAAS,EAAE,KAAK,EAAE,KAAK;AAC5C,UAAM,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK;AACnE,QAAI,KAAK,EAAG,UAAS,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAE,CAAC;AAAA,EACtD,CAAC;AAGD,IAAE,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO;AACtB,UAAM,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK;AAC5B,UAAM,IAAI,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE,KAAK,EAAE,KAAK;AACvC,QAAI,KAAK,EAAG,UAAS,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAE,CAAC;AAAA,EACtD,CAAC;AAGD,QAAM,WAAqB,CAAC;AAC5B,IAAE,cAAc,EAAE,KAAK,CAAC,GAAG,OAAO;AAChC,UAAM,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK;AAC/B,QAAI,KAAK,SAAS,MAAM,KAAK,SAAS,IAAK,UAAS,KAAK,IAAI;AAAA,EAC/D,CAAC;AAGD,QAAM,UACJ,EAAE,0BAA0B,EAAE,KAAK,SAAS,GAAG,KAAK,KACpD,EAAE,iCAAiC,EAAE,KAAK,SAAS,GAAG,KAAK,KAC3D,SAAS,MAAM,GAAG,GAAG;AAEvB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,SAAS,MAAM,GAAG,EAAE;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,MAAM,KAAK,SAAS,IAAI,OAAO;AAAA,IAC/B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC1HA,OAAO,WAAW;AAcX,SAAS,aAAa,QAA4C;AAEvE,QAAM,SAAS,QAAQ,IAAI,yBAAyB,QAAQ,KAAK;AACjE,QAAM,SAAS,QAAQ,IAAI,yBAAyB,QAAQ,KAAK;AACjE,QAAM,QAAQ,QAAQ,IAAI,uBAAuB,QAAQ,KAAK;AAE9D,MAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAO,QAAO;AACzC,SAAO,EAAE,QAAQ,QAAQ,MAAM;AACjC;AAEA,eAAsB,eACpB,QACA,UACA,SACiB;AACjB,QAAM,MAAM,MAAM,MAAM;AAAA,IACtB,GAAG,OAAO,MAAM;AAAA,IAChB;AAAA,MACE,OAAO,OAAO;AAAA,MACd;AAAA,MACA,aAAa,SAAS,eAAe;AAAA,MACrC,OAAO;AAAA,MACP,YAAY,SAAS,aAAa;AAAA,MAClC,QAAQ;AAAA,IACV;AAAA,IACA;AAAA,MACE,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,OAAO,MAAM;AAAA,MACxC;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAO,IAAI,KAAK,QAAQ,CAAC,GAAG,SAAS,SAAS,KAAK,KAAK;AAC1D;;;AC/CA,eAAsB,aAAa,QAAmB,OAAe,UAAmC;AACtG,QAAM,YAAY,SAAS,MAAM,GAAG,GAAI;AACxC,QAAM,WAAW,MAAM,eAAe,QAAQ;AAAA,IAC5C;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,UAAU,KAAK;AAAA;AAAA;AAAA,EAAiB,SAAS;AAAA,IACpD;AAAA,EACF,GAAG,EAAE,WAAW,IAAI,CAAC;AAErB,SAAO;AACT;AAEA,eAAsB,eAAe,QAAmB,OAAe,UAAqC;AAC1G,QAAM,YAAY,SAAS,MAAM,GAAG,GAAI;AACxC,QAAM,WAAW,MAAM,eAAe,QAAQ;AAAA,IAC5C;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,UAAU,KAAK;AAAA;AAAA;AAAA,EAAiB,SAAS;AAAA,IACpD;AAAA,EACF,GAAG,EAAE,WAAW,IAAI,CAAC;AAErB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,QAAI,MAAM,QAAQ,MAAM,EAAG,QAAO,OAAO,IAAI,MAAM;AAAA,EACrD,QAAQ;AAAA,EAA2B;AACnC,SAAO,CAAC;AACV;;;AClCA,IAAM,SAA0B;AAAA,EAC9B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,IACL,MAAM,UAAU,OAAO;AACrB,aAAO,MAAM,IAAI,CAAC,SAAS;AACzB,cAAM,MAAM,KAAK,IAAI,YAAY;AAGjC,YAAI,IAAI,SAAS,cAAc,KAAK,IAAI,SAAS,WAAW,GAAG;AAE7D,iBAAO;AAAA,QACT;AAGA,YAAI,IAAI,SAAS,YAAY,GAAG;AAC9B,iBAAO,EAAE,GAAG,MAAM,MAAM,CAAC,GAAI,KAAK,QAAQ,CAAC,GAAI,oBAAoB,EAAE;AAAA,QACvE;AACA,YAAI,IAAI,SAAS,OAAO,GAAG;AACzB,iBAAO,EAAE,GAAG,MAAM,MAAM,CAAC,GAAI,KAAK,QAAQ,CAAC,GAAI,eAAe,EAAE;AAAA,QAClE;AAGA,YAAI,IAAI,SAAS,UAAU,GAAG;AAC5B,iBAAO,EAAE,GAAG,MAAM,MAAM,CAAC,GAAI,KAAK,QAAQ,CAAC,GAAI,kBAAkB,EAAE;AAAA,QACrE;AAEA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,IAAO,oBAAQ;;;ACjCf,IAAM,uBAAiD;AAAA,EACrD,MAAM,CAAC,UAAU,gBAAgB,WAAW,QAAQ;AAAA,EACpD,QAAQ,CAAC,YAAY,WAAW,eAAe;AAAA,EAC/C,YAAY,CAAC,UAAU,UAAU,aAAa;AAAA,EAC9C,QAAQ,CAAC,YAAY,UAAU,QAAQ;AAAA,EACvC,WAAW,CAAC,WAAW,SAAS,UAAU;AAAA,EAC1C,QAAQ,CAAC,WAAW,OAAO;AAC7B;AAEA,IAAMA,UAA0B;AAAA,EAC9B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,IACL,MAAM,UAAU,OAAO;AAErB,YAAM,YAAY,MAAM,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,YAAY,CAAC;AACnE,UAAI,oBAAmC;AAEvC,iBAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,oBAAoB,GAAG;AACxE,cAAM,aAAa,SAAS;AAAA,UAAO,CAAC,QAClC,UAAU,KAAK,CAAC,QAAQ,IAAI,SAAS,GAAG,CAAC;AAAA,QAC3C,EAAE;AACF,YAAI,cAAc,GAAG;AACnB,8BAAoB;AACpB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,kBAAmB,QAAO;AAE/B,aAAO,MAAM,IAAI,CAAC,UAAU;AAAA,QAC1B,GAAG;AAAA,QACH,MAAM,CAAC,GAAI,KAAK,QAAQ,CAAC,GAAI,OAAO,iBAAiB,EAAE;AAAA,MACzD,EAAE;AAAA,IACJ;AAAA,EACF;AACF;AAEA,IAAO,sBAAQA;;;ACnCf,IAAM,kBAAmD;AAAA,EACvD,aAAa;AAAA,EACb,eAAe;AACjB;AAEA,eAAsB,YAAY,aAAmD;AACnF,QAAM,UAA6B,CAAC;AAEpC,aAAW,QAAQ,aAAa;AAC9B,QAAI;AACF,UAAIC;AAEJ,UAAI,QAAQ,iBAAiB;AAC3B,QAAAA,UAAS,gBAAgB,IAAI;AAAA,MAC/B,WAAW,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,GAAG,GAAG;AAClF,cAAM,MAAM,MAAM,OAAO;AACzB,QAAAA,UAAS,IAAI,WAAW;AAAA,MAC1B,OAAO;AACL,cAAM,MAAM,MAAM,OAAO,oBAAoB,IAAI;AACjD,QAAAA,UAAS,IAAI,WAAW;AAAA,MAC1B;AAEA,cAAQ,KAAKA,OAAM;AACnB,UAAI,KAAK,kBAAkBA,QAAO,IAAI,KAAKA,QAAO,OAAO,EAAE;AAAA,IAC7D,SAAS,KAAK;AACZ,UAAI,KAAK,0BAA0B,IAAI,MAAO,IAAc,OAAO,EAAE;AAAA,IACvE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,QACpB,SACA,SACG,MACY;AACf,aAAWA,WAAU,SAAS;AAC5B,UAAM,KAAKA,QAAO,QAAQ,IAAI;AAC9B,QAAI,IAAI;AACN,YAAO,GAA6C,GAAG,IAAI;AAAA,IAC7D;AAAA,EACF;AACF;AAEA,eAAsB,aAAa,SAA4B,OAAoG;AACjK,MAAI,SAAS;AACb,aAAWA,WAAU,SAAS;AAC5B,QAAIA,QAAO,OAAO,WAAW;AAC3B,eAAS,MAAMA,QAAO,MAAM,UAAU,MAAM;AAAA,IAC9C;AAAA,EACF;AACA,SAAO;AACT;","names":["plugin","plugin"]}
@@ -0,0 +1,10 @@
1
+ import {
2
+ registerGenerateCommand,
3
+ runGenerate
4
+ } from "./chunk-AYLZUDQP.js";
5
+ import "./chunk-YWUDTSOR.js";
6
+ export {
7
+ registerGenerateCommand,
8
+ runGenerate
9
+ };
10
+ //# sourceMappingURL=generate-V5JMMT4J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }