|
|
@ -21,13 +21,13 @@ import {
|
|
|
|
extractTitle,
|
|
|
|
extractTitle,
|
|
|
|
generateMetadata,
|
|
|
|
generateMetadata,
|
|
|
|
getHumanReadableSizeOf,
|
|
|
|
getHumanReadableSizeOf,
|
|
|
|
stripExt,
|
|
|
|
stripExt
|
|
|
|
} from './helpers/utils'
|
|
|
|
} from './helpers/utils'
|
|
|
|
import type {
|
|
|
|
import type {
|
|
|
|
CustomTemplateVariables,
|
|
|
|
CustomTemplateVariables,
|
|
|
|
LlmstxtSettings,
|
|
|
|
LlmstxtSettings,
|
|
|
|
PreparedFile,
|
|
|
|
PreparedFile,
|
|
|
|
VitePressConfig,
|
|
|
|
VitePressConfig
|
|
|
|
} from './types'
|
|
|
|
} from './types'
|
|
|
|
|
|
|
|
|
|
|
|
const PLUGIN_NAME = 'llmstxt'
|
|
|
|
const PLUGIN_NAME = 'llmstxt'
|
|
|
@ -50,7 +50,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
ignoreFiles: [],
|
|
|
|
ignoreFiles: [],
|
|
|
|
workDir: undefined as unknown as string,
|
|
|
|
workDir: undefined as unknown as string,
|
|
|
|
stripHTML: true,
|
|
|
|
stripHTML: true,
|
|
|
|
...userSettings,
|
|
|
|
...userSettings
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Store the resolved Vite config
|
|
|
|
// Store the resolved Vite config
|
|
|
@ -71,7 +71,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
if (settings.workDir) {
|
|
|
|
if (settings.workDir) {
|
|
|
|
settings.workDir = path.resolve(
|
|
|
|
settings.workDir = path.resolve(
|
|
|
|
config.vitepress.srcDir,
|
|
|
|
config.vitepress.srcDir,
|
|
|
|
settings.workDir as string,
|
|
|
|
settings.workDir as string
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
settings.workDir = config.vitepress.srcDir
|
|
|
|
settings.workDir = config.vitepress.srcDir
|
|
|
@ -79,7 +79,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
// Detect if this is the SSR build
|
|
|
|
// Detect if this is the SSR build
|
|
|
|
isSsrBuild = !!resolvedConfig.build?.ssr
|
|
|
|
isSsrBuild = !!resolvedConfig.build?.ssr
|
|
|
|
log.info(
|
|
|
|
log.info(
|
|
|
|
`${pc.bold(PLUGIN_NAME)} initialized ${isSsrBuild ? pc.dim('(SSR build)') : pc.dim('(client build)')} with workDir: ${pc.cyan(settings.workDir as string)}`,
|
|
|
|
`${pc.bold(PLUGIN_NAME)} initialized ${isSsrBuild ? pc.dim('(SSR build)') : pc.dim('(client build)')} with workDir: ${pc.cyan(settings.workDir as string)}`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
@ -92,7 +92,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
// Try to read and serve the markdown file
|
|
|
|
// Try to read and serve the markdown file
|
|
|
|
const filePath = path.resolve(
|
|
|
|
const filePath = path.resolve(
|
|
|
|
config.vitepress?.outDir ?? 'dist',
|
|
|
|
config.vitepress?.outDir ?? 'dist',
|
|
|
|
`${stripExt(req.url)}.md`,
|
|
|
|
`${stripExt(req.url)}.md`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
|
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
|
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
|
|
|
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
|
|
|
@ -143,12 +143,12 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
return await Promise.resolve(
|
|
|
|
return await Promise.resolve(
|
|
|
|
minimatch(
|
|
|
|
minimatch(
|
|
|
|
path.relative(settings.workDir as string, id),
|
|
|
|
path.relative(settings.workDir as string, id),
|
|
|
|
pattern,
|
|
|
|
pattern
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
return false
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldIgnore.some((result) => result === true)) {
|
|
|
|
if (shouldIgnore.some((result) => result === true)) {
|
|
|
@ -189,13 +189,13 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
// Skip if no files found
|
|
|
|
// Skip if no files found
|
|
|
|
if (fileCount === 0) {
|
|
|
|
if (fileCount === 0) {
|
|
|
|
log.warn(
|
|
|
|
log.warn(
|
|
|
|
`No markdown files found to process. Check your \`${pc.bold('workDir')}\` and \`${pc.bold('ignoreFiles')}\` settings.`,
|
|
|
|
`No markdown files found to process. Check your \`${pc.bold('workDir')}\` and \`${pc.bold('ignoreFiles')}\` settings.`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.info(
|
|
|
|
log.info(
|
|
|
|
`Processing ${pc.bold(fileCount.toString())} markdown files from ${pc.cyan(settings.workDir)}`,
|
|
|
|
`Processing ${pc.bold(fileCount.toString())} markdown files from ${pc.cyan(settings.workDir)}`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const preparedFiles: PreparedFile[] = await Promise.all(
|
|
|
|
const preparedFiles: PreparedFile[] = await Promise.all(
|
|
|
@ -230,7 +230,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
: file
|
|
|
|
: file
|
|
|
|
|
|
|
|
|
|
|
|
return { path: filePath, title, file: mdFile }
|
|
|
|
return { path: filePath, title, file: mdFile }
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if (settings.generateLLMFriendlyDocsForEachPage) {
|
|
|
|
if (settings.generateLLMFriendlyDocsForEachPage) {
|
|
|
@ -243,7 +243,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
|
|
|
|
|
|
|
|
// Ensure target directory exists (async version)
|
|
|
|
// Ensure target directory exists (async version)
|
|
|
|
await fs.mkdir(path.dirname(targetPath), {
|
|
|
|
await fs.mkdir(path.dirname(targetPath), {
|
|
|
|
recursive: true,
|
|
|
|
recursive: true
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Copy file to output directory (async version)
|
|
|
|
// Copy file to output directory (async version)
|
|
|
@ -253,19 +253,19 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
mdFile.content,
|
|
|
|
mdFile.content,
|
|
|
|
generateMetadata(mdFile, {
|
|
|
|
generateMetadata(mdFile, {
|
|
|
|
domain: settings.domain,
|
|
|
|
domain: settings.domain,
|
|
|
|
filePath: relativePath,
|
|
|
|
filePath: relativePath
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
log.success(`Processed ${pc.cyan(relativePath)}`)
|
|
|
|
log.success(`Processed ${pc.cyan(relativePath)}`)
|
|
|
|
} catch (error) {
|
|
|
|
} catch (error) {
|
|
|
|
log.error(
|
|
|
|
log.error(
|
|
|
|
// @ts-ignore
|
|
|
|
// @ts-ignore
|
|
|
|
`Failed to process ${pc.cyan(relativePath)}: ${error.message}`,
|
|
|
|
`Failed to process ${pc.cyan(relativePath)}: ${error.message}`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -282,7 +282,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
description: settings.description,
|
|
|
|
description: settings.description,
|
|
|
|
details: settings.details,
|
|
|
|
details: settings.details,
|
|
|
|
toc: settings.toc,
|
|
|
|
toc: settings.toc,
|
|
|
|
...settings.customTemplateVariables,
|
|
|
|
...settings.customTemplateVariables
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tasks.push(
|
|
|
|
tasks.push(
|
|
|
@ -301,7 +301,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
linksExtension: !settings.generateLLMFriendlyDocsForEachPage
|
|
|
|
linksExtension: !settings.generateLLMFriendlyDocsForEachPage
|
|
|
|
? '.html'
|
|
|
|
? '.html'
|
|
|
|
: undefined,
|
|
|
|
: undefined,
|
|
|
|
cleanUrls: config.cleanUrls,
|
|
|
|
cleanUrls: config.cleanUrls
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
await fs.writeFile(llmsTxtPath, llmsTxt, 'utf-8')
|
|
|
|
await fs.writeFile(llmsTxtPath, llmsTxt, 'utf-8')
|
|
|
@ -313,11 +313,11 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
file: pc.cyan('llms.txt'),
|
|
|
|
file: pc.cyan('llms.txt'),
|
|
|
|
tokens: pc.bold(millify(approximateTokenSize(llmsTxt))),
|
|
|
|
tokens: pc.bold(millify(approximateTokenSize(llmsTxt))),
|
|
|
|
size: pc.bold(getHumanReadableSizeOf(llmsTxt)),
|
|
|
|
size: pc.bold(getHumanReadableSizeOf(llmsTxt)),
|
|
|
|
fileCount: pc.bold(fileCount.toString()),
|
|
|
|
fileCount: pc.bold(fileCount.toString())
|
|
|
|
},
|
|
|
|
}
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
})(),
|
|
|
|
})()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -328,7 +328,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
tasks.push(
|
|
|
|
tasks.push(
|
|
|
|
(async () => {
|
|
|
|
(async () => {
|
|
|
|
log.info(
|
|
|
|
log.info(
|
|
|
|
`Generating full documentation bundle (${pc.cyan('llms-full.txt')})...`,
|
|
|
|
`Generating full documentation bundle (${pc.cyan('llms-full.txt')})...`
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const llmsFullTxt = generateLLMsFullTxt(preparedFiles, {
|
|
|
|
const llmsFullTxt = generateLLMsFullTxt(preparedFiles, {
|
|
|
@ -337,7 +337,7 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
linksExtension: !settings.generateLLMFriendlyDocsForEachPage
|
|
|
|
linksExtension: !settings.generateLLMFriendlyDocsForEachPage
|
|
|
|
? '.html'
|
|
|
|
? '.html'
|
|
|
|
: undefined,
|
|
|
|
: undefined,
|
|
|
|
cleanUrls: config.cleanUrls,
|
|
|
|
cleanUrls: config.cleanUrls
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Write content to llms-full.txt
|
|
|
|
// Write content to llms-full.txt
|
|
|
@ -349,17 +349,17 @@ export default function llmstxt(userSettings: LlmstxtSettings = {}): Plugin {
|
|
|
|
file: pc.cyan('llms-full.txt'),
|
|
|
|
file: pc.cyan('llms-full.txt'),
|
|
|
|
tokens: pc.bold(millify(approximateTokenSize(llmsFullTxt))),
|
|
|
|
tokens: pc.bold(millify(approximateTokenSize(llmsFullTxt))),
|
|
|
|
size: pc.bold(getHumanReadableSizeOf(llmsFullTxt)),
|
|
|
|
size: pc.bold(getHumanReadableSizeOf(llmsFullTxt)),
|
|
|
|
fileCount: pc.bold(fileCount.toString()),
|
|
|
|
fileCount: pc.bold(fileCount.toString())
|
|
|
|
},
|
|
|
|
}
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
})(),
|
|
|
|
)
|
|
|
|
|
|
|
|
})()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tasks.length) {
|
|
|
|
if (tasks.length) {
|
|
|
|
await Promise.all(tasks)
|
|
|
|
await Promise.all(tasks)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|