Skip to content

Commit 4ca5638

Browse files
Merge v4.x into Next
Merge pull request #299 from coollabsio/v4.x
2 parents fed25b0 + e212c7b commit 4ca5638

File tree

4 files changed

+196
-10
lines changed

4 files changed

+196
-10
lines changed

bun.lockb

0 Bytes
Binary file not shown.

docs/.vitepress/config.mts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fileURLToPath, URL } from 'node:url'
22
import yaml from 'vite-plugin-yaml'
33
import llmstxt from 'vitepress-plugin-llms'
4+
import coolbotPlugin from './plugins/vitepress-plugin-coolbot';
45
import { defineConfig } from 'vitepress'
56
import { useSidebar } from 'vitepress-openapi'
67
import spec from './theme/openapi.json' with { type: 'json' }
@@ -20,8 +21,6 @@ bundledLanguages['ssh'] = {
2021
path: join(dirname(fileURLToPath(import.meta.url)), '../../node_modules/shiki/languages/ssh-config.tmLanguage.json')
2122
}
2223

23-
console.log(env)
24-
2524
// https://vitepress.dev/reference/site-config
2625
export default defineConfig({
2726
lang: 'en-US',
@@ -707,6 +706,16 @@ export default defineConfig({
707706
'**/api-reference/api/**/*'
708707
],
709708
}),
709+
coolbotPlugin({
710+
docsDir: 'docs',
711+
writeRawOutput: false,
712+
ignoreFolders: [
713+
'vitepress',
714+
'api-reference',
715+
'node_modules',
716+
'dist'
717+
],
718+
}),
710719
groupIconVitePlugin({
711720
customIcon: {
712721
bruno: 'vscode-icons:file-type-bruno',
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import { resolve, join, dirname } from 'path';
2+
import { readFileSync, readdirSync, statSync, mkdirSync, existsSync, writeFileSync } from 'fs';
3+
import type { Plugin } from 'vite';
4+
5+
export interface coolbotPluginOptions {
6+
/**
7+
* Write the raw txt output to the converted directory
8+
* @default false
9+
*/
10+
writeRawOutput?: boolean;
11+
/**
12+
* Directory containing markdown files to convert
13+
* @default 'docs'
14+
*/
15+
docsDir?: string;
16+
/**
17+
* Webhook URL to send the file map to
18+
* @default '' || process.env.COOLBOT_WEBHOOK_URL
19+
*/
20+
webhookUrl?: string;
21+
/**
22+
* Ignore files in the docs directory
23+
* @default []
24+
*/
25+
ignoreFolders?: string[];
26+
}
27+
28+
interface FileMap {
29+
[key: string]: string; // path: content mapping
30+
}
31+
32+
/**
33+
* Plugin to convert markdown files to text files, RAG chain.
34+
*/
35+
export default function coolbotPlugin(options: coolbotPluginOptions = {}): Plugin {
36+
const docsDir = options.docsDir || 'docs';
37+
const webhookUrl = process.env.COOLBOT_WEBHOOK_URL || '';
38+
39+
const ensureDirectoryExists = (filePath: string) => {
40+
const dir = dirname(filePath);
41+
if (!existsSync(dir)) {
42+
mkdirSync(dir, { recursive: true });
43+
}
44+
};
45+
46+
return {
47+
name: 'vitepress-plugin-CoolBot',
48+
49+
async closeBundle() {
50+
try {
51+
const docsPath = resolve(process.cwd(), docsDir);
52+
const markdownFiles = getAllMarkdownFiles(docsPath);
53+
const convertedDir = resolve(docsPath, '.vitepress/dist/');
54+
const fileMap: FileMap = {};
55+
56+
// Ensure converted directory exists
57+
if (!existsSync(convertedDir)) {
58+
mkdirSync(convertedDir, { recursive: true });
59+
}
60+
61+
for (const file of markdownFiles) {
62+
try {
63+
const relativePath = file.replace(docsPath, '');
64+
65+
if (!relativePath.startsWith('\\') && !relativePath.startsWith('/')) {
66+
console.warn(`CoolBot: Skipping file with invalid path: ${file}`);
67+
continue;
68+
}
69+
70+
const outputPath = resolve(convertedDir, relativePath.slice(1).replace('.md', '.txt'));
71+
const content = readFileSync(file, 'utf-8');
72+
const convertedContent = convertMarkdownToText(content);
73+
74+
// Store in map using normalized path without .txt extension
75+
const normalizedPath = relativePath.slice(1).replace('.md', '').replace(/\\/g, '/');
76+
fileMap[normalizedPath] = convertedContent;
77+
78+
if(options.writeRawOutput) {
79+
// Write the converted file
80+
ensureDirectoryExists(outputPath);
81+
writeFileSync(outputPath, convertedContent, 'utf-8');
82+
console.log(`CoolBot: ${relativePath} -> .vitepress/dist/${relativePath.replace('.md', '.txt')}`);
83+
}
84+
85+
} catch (fileError) {
86+
console.error(`CoolBot: Error processing file ${file}:`, fileError);
87+
}
88+
}
89+
90+
91+
// Write the file map
92+
const mapPath = resolve(convertedDir, 'kvmap.json');
93+
writeFileSync(mapPath, JSON.stringify(fileMap, null, 2), 'utf-8');
94+
95+
if(webhookUrl) {
96+
// Send POST request to webhook
97+
try {
98+
const response = await fetch(webhookUrl, {
99+
method: 'POST',
100+
headers: {
101+
'Content-Type': 'application/json',
102+
},
103+
body: JSON.stringify(fileMap),
104+
});
105+
106+
if (!response.ok) {
107+
throw new Error(`HTTP error! status: ${response.status}`);
108+
}
109+
110+
console.log('\nCoolBot: Successfully sent file map to webhook');
111+
} catch (webhookError) {
112+
console.error('CoolBot: Error sending file map to webhook:', webhookError);
113+
}
114+
}
115+
116+
console.log('\nCoolBot: Generated file map at .vitepress/dist/public/kvmap.json');
117+
console.log('\nCoolBot: Conversion complete');
118+
} catch (error) {
119+
console.error('CoolBot: Error during conversion:', error);
120+
}
121+
}
122+
};
123+
}
124+
125+
/**
126+
* Recursively find all markdown files in a directory
127+
* @param {string} dir - Directory to search
128+
* @returns {string[]} Array of absolute file paths
129+
*/
130+
function getAllMarkdownFiles(dir: string): string[] {
131+
let results: string[] = [];
132+
try {
133+
const files = readdirSync(dir);
134+
const defaultIgnored = ['node_modules', '.vitepress', 'dist', 'api-reference'];
135+
136+
for (const file of files) {
137+
const filePath = join(dir, file);
138+
const stat = statSync(filePath);
139+
140+
if (defaultIgnored.includes(file)) {
141+
continue;
142+
}
143+
144+
if (stat.isDirectory()) {
145+
results = results.concat(getAllMarkdownFiles(filePath));
146+
} else if (file.endsWith('.md')) {
147+
results.push(filePath);
148+
}
149+
}
150+
} catch (error) {
151+
console.error('CoolBot: Error reading directory:', error);
152+
}
153+
154+
return results;
155+
}
156+
157+
/**
158+
* Convert markdown content to plain text
159+
* @param {string} markdown - Markdown content
160+
* @returns {string} Plain text content
161+
*/
162+
function convertMarkdownToText(markdown: string): string {
163+
return markdown
164+
// 1. Remove metadata and containers
165+
.replace(/^---[\s\S]*?---/, '\n') // Remove YAML frontmatter
166+
.replace(/<[^>]+>/g, '') // Remove HTML tags but preserve content
167+
.replace(/:::\s*\w+\s*/g, '\n') // Remove VitePress container starts
168+
.replace(/:::/g, '\n') // Remove VitePress container ends
169+
170+
// 2. Add spacing around structural elements
171+
.replace(/\n(#\s[^\n]*)/g, '\n\n\n\n$1\n') // Add extra space around h1
172+
.replace(/\n(##\s[^\n]*)/g, '\n\n\n$1\n') // Add extra space around h2
173+
.replace(/\n(###\s[^\n]*)/g, '\n\n$1\n') // Add extra space around h3
174+
.replace(/\n(####.*)/g, '\n\n$1\n') // Add space around h4+
175+
.replace(/\n(```[^\n]*)/g, '\n\n$1') // Add double space before code blocks
176+
.replace(/(```)\s*\n/g, '$1\n\n\n') // Add triple space after code blocks
177+
178+
// 3. Preserve and normalize line breaks
179+
.split('\n') // Split into lines
180+
.map(line => line.trim()) // Trim each line
181+
.join('\n') // Rejoin with line breaks
182+
.replace(/\n{5,}/g, '\n\n\n\n') // Max 4 consecutive line breaks
183+
.replace(/\s{2,}/g, ' ') // Collapse multiple spaces to single
184+
.trim();
185+
}

docs/introduction.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)