botdocs 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/src/builder/site-generator.d.ts +2 -0
- package/dist/src/builder/site-generator.js +24 -0
- package/man/botdocs.1 +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,8 @@ Convert markdown documentation into beautiful static sites with AI-powered seman
|
|
|
15
15
|
- **No Backend** - Everything runs in the browser
|
|
16
16
|
- **Fast** - Syntax highlighting with Shiki
|
|
17
17
|
- **Live Preview** - `--watch` rebuilds on save and serves the site locally
|
|
18
|
-
- **SEO** - Optional Open Graph/Twitter tags
|
|
18
|
+
- **SEO** - Optional Open Graph/Twitter tags, `sitemap.xml` and `robots.txt` via `baseUrl`
|
|
19
|
+
- **Agent Friendly** - Raw `.md` source published next to every page, plus an `llms.txt` index
|
|
19
20
|
|
|
20
21
|
## Installation
|
|
21
22
|
|
|
@@ -105,7 +106,7 @@ Create `botdocs.config.json` in your docs directory:
|
|
|
105
106
|
| `theme` | string | `"classic"` | Theme to use (classic, material, minimal, slate, modern) |
|
|
106
107
|
| `customCss` | string | none | Path to a CSS file, resolved relative to the config file's directory. Appended after theme CSS in `bundle.css`, so same-specificity selectors override the theme without `!important` |
|
|
107
108
|
| `attribution` | boolean | `true` | Show "Built with Botdocs" footer link |
|
|
108
|
-
| `baseUrl` | string | none | Canonical URL where the site is hosted. When set, pages get `rel=canonical` and Open Graph/Twitter card tags,
|
|
109
|
+
| `baseUrl` | string | none | Canonical URL where the site is hosted. When set, pages get `rel=canonical` and Open Graph/Twitter card tags, a `sitemap.xml` and `robots.txt` are generated, and `llms.txt` links become absolute |
|
|
109
110
|
| `chat.enabled` | boolean | `true` | Enable AI chatbot |
|
|
110
111
|
| `chat.welcomeMessage` | string | `"Ask me anything about the docs!"` | Chatbot welcome message |
|
|
111
112
|
| `build.chunkSize` | number | `500` | Text chunk size for embeddings |
|
|
@@ -10,6 +10,8 @@ export declare class SiteGenerator {
|
|
|
10
10
|
* Generate the complete site
|
|
11
11
|
*/
|
|
12
12
|
generate(inputDir: string, outputDir: string, config: BotdocsConfig): Promise<ProcessedDocument[]>;
|
|
13
|
+
private writeLlmsTxt;
|
|
14
|
+
private writeRobotsTxt;
|
|
13
15
|
private writeSitemap;
|
|
14
16
|
/**
|
|
15
17
|
* Build navigation structure from documents, grouping by top-level
|
|
@@ -109,6 +109,7 @@ export class SiteGenerator {
|
|
|
109
109
|
const outputPath = join(outputDir, doc.relativePath.replace(/\.md$/, '.html'));
|
|
110
110
|
mkdirSync(dirname(outputPath), { recursive: true });
|
|
111
111
|
writeFileSync(outputPath, html, 'utf-8');
|
|
112
|
+
cpSync(doc.filePath, join(outputDir, doc.relativePath));
|
|
112
113
|
}
|
|
113
114
|
// Copy index.html if README.md exists
|
|
114
115
|
const readmeDoc = this.documents.find((d) => d.relativePath === 'README.md' || d.relativePath === 'index.md');
|
|
@@ -120,11 +121,34 @@ export class SiteGenerator {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
console.log(`Generated ${this.documents.length} HTML pages`);
|
|
124
|
+
this.writeLlmsTxt(outputDir, config);
|
|
123
125
|
if (config.baseUrl) {
|
|
124
126
|
this.writeSitemap(outputDir, config.baseUrl);
|
|
127
|
+
this.writeRobotsTxt(outputDir, config.baseUrl);
|
|
125
128
|
}
|
|
126
129
|
return this.documents;
|
|
127
130
|
}
|
|
131
|
+
writeLlmsTxt(outputDir, config) {
|
|
132
|
+
const oneLine = (value) => stripHtml(value).replace(/\s+/g, ' ').trim();
|
|
133
|
+
const isRootIndex = (doc) => doc.relativePath === 'README.md' || doc.relativePath === 'index.md';
|
|
134
|
+
const pages = [...this.documents.filter(isRootIndex), ...this.documents.filter((doc) => !isRootIndex(doc))]
|
|
135
|
+
.map((doc) => {
|
|
136
|
+
const title = oneLine(doc.metadata.title || basename(doc.relativePath, '.md'));
|
|
137
|
+
const url = config.baseUrl ? absoluteUrl(config.baseUrl, doc.relativePath) : doc.relativePath;
|
|
138
|
+
const description = oneLine(doc.metadata.description || '');
|
|
139
|
+
return `- [${title}](${url})${description ? `: ${description}` : ''}`;
|
|
140
|
+
})
|
|
141
|
+
.join('\n');
|
|
142
|
+
const summary = oneLine(config.description || '');
|
|
143
|
+
const llms = `# ${oneLine(config.title || 'Documentation')}\n\n${summary ? `> ${summary}\n\n` : ''}## Docs\n\n${pages}\n`;
|
|
144
|
+
writeFileSync(join(outputDir, 'llms.txt'), llms, 'utf-8');
|
|
145
|
+
console.log('Generated llms.txt');
|
|
146
|
+
}
|
|
147
|
+
writeRobotsTxt(outputDir, baseUrl) {
|
|
148
|
+
const robots = `User-agent: *\nAllow: /\n\nSitemap: ${absoluteUrl(baseUrl, 'sitemap.xml')}\n`;
|
|
149
|
+
writeFileSync(join(outputDir, 'robots.txt'), robots, 'utf-8');
|
|
150
|
+
console.log('Generated robots.txt');
|
|
151
|
+
}
|
|
128
152
|
writeSitemap(outputDir, baseUrl) {
|
|
129
153
|
const urls = this.documents
|
|
130
154
|
.map((doc) => {
|
package/man/botdocs.1
CHANGED
|
@@ -106,8 +106,18 @@ When set, each page emits
|
|
|
106
106
|
.B rel=canonical
|
|
107
107
|
and Open Graph/Twitter card metadata, and a
|
|
108
108
|
.B sitemap.xml
|
|
109
|
-
listing every generated page
|
|
110
|
-
|
|
109
|
+
listing every generated page and a
|
|
110
|
+
.B robots.txt
|
|
111
|
+
pointing at it are written to the output directory, and
|
|
112
|
+
.B llms.txt
|
|
113
|
+
links become absolute.
|
|
114
|
+
When unset, these tags are omitted and no sitemap or robots.txt is generated.
|
|
115
|
+
.PP
|
|
116
|
+
Every build copies each page's markdown source next to its HTML and writes an
|
|
117
|
+
.B llms.txt
|
|
118
|
+
index linking to those
|
|
119
|
+
.B .md
|
|
120
|
+
files, so agents can read the docs without parsing HTML.
|
|
111
121
|
.PP
|
|
112
122
|
.B build.minChunkSize
|
|
113
123
|
folds chunks smaller than this many estimated tokens into a neighboring
|
package/package.json
CHANGED