@entro314labs/starlight-document-converter
Version:
A comprehensive document converter for Astro Starlight that transforms various document formats into Starlight-compatible Markdown with proper frontmatter
749 lines (740 loc) • 28.6 kB
JavaScript
import {
boxes,
createBrandHeader,
formatHelpSection
} from "./chunk-RI3FHBT3.js";
import {
DocumentConverter,
detectStarlightConfig,
isStarlightProject
} from "./chunk-HMTAMXXQ.js";
// src/cli.ts
import { existsSync as existsSync2, lstatSync, readdirSync } from "fs";
import { basename, dirname, relative, resolve as resolve2 } from "path";
import {
cancel,
confirm,
intro,
isCancel,
multiselect,
note,
outro,
select,
spinner,
text
} from "@clack/prompts";
import { Command } from "commander";
import pc from "picocolors";
// src/utils/cli-helpers.ts
import { existsSync } from "fs";
import { resolve } from "path";
function getSmartDefaults(cwd = process.cwd()) {
try {
const starlightConfig = detectStarlightConfig(cwd);
const isStarlight = isStarlightProject(cwd);
return {
outputDir: starlightConfig.docsDir,
isStarlightProject: isStarlight,
title: starlightConfig.title,
description: starlightConfig.description,
recommendations: getRecommendations(cwd, starlightConfig, isStarlight)
};
} catch {
return {
outputDir: "docs-output",
isStarlightProject: false,
title: "Documentation",
description: "Documentation site",
recommendations: [
"Using CLI-only mode. Install @astrojs/starlight for full integration features."
]
};
}
}
function getRecommendations(cwd, config, isStarlight) {
const recommendations = [];
if (!isStarlight) {
recommendations.push(
"This doesn't appear to be a Starlight project. Consider installing @astrojs/starlight first."
);
}
if (!existsSync(resolve(cwd, config.docsDir))) {
recommendations.push(
`Content directory ${config.docsDir} doesn't exist yet. It will be created automatically.`
);
}
const importDirs = ["docs-import", "documents", "content-import"];
const existingImportDirs = importDirs.filter((dir) => existsSync(resolve(cwd, dir)));
if (existingImportDirs.length === 0) {
recommendations.push(
'Consider creating a "docs-import" directory to drop documents for conversion.'
);
} else {
recommendations.push(`Found existing import directories: ${existingImportDirs.join(", ")}`);
}
return recommendations;
}
function getOutputDirectory(userSpecified, cwd = process.cwd()) {
if (userSpecified) {
return userSpecified;
}
try {
const starlightConfig = detectStarlightConfig(cwd);
return starlightConfig.docsDir;
} catch {
return "docs-output";
}
}
function detectInputSources(cwd = process.cwd()) {
const sources = [];
try {
const starlightConfig = detectStarlightConfig(cwd);
if (starlightConfig.docsDir && existsSync(resolve(cwd, starlightConfig.docsDir))) {
sources.push(starlightConfig.docsDir);
}
} catch {
}
const commonDirs = ["docs-import", "documents", "content-import", "drafts", "imports", "_import"];
for (const dir of commonDirs) {
if (existsSync(resolve(cwd, dir))) {
if (!sources.includes(dir)) {
sources.push(dir);
}
}
}
return sources;
}
// src/cli.ts
var program = new Command();
var getFormattedStats = (results) => {
const successful = results.filter((r) => r.success).length;
const skipped = results.filter((r) => r.skipped).length;
const failed = results.filter((r) => !(r.success || r.skipped)).length;
return { successful, skipped, failed, total: results.length };
};
var detectInputType = (inputPath) => {
if (!existsSync2(inputPath)) {
return "not-found";
}
return lstatSync(inputPath).isDirectory() ? "directory" : "file";
};
var getSampleFiles = (dir, maxSamples = 5) => {
try {
const files = readdirSync(dir, { recursive: true }).filter((file) => typeof file === "string").filter((file) => {
const ext = file.split(".").pop()?.toLowerCase();
return ["md", "mdx", "txt", "html", "htm", "docx", "doc", "rtf"].includes(ext || "");
}).slice(0, maxSamples);
return files;
} catch {
return [];
}
};
function showProjectInfo(smartDefaults) {
if (smartDefaults.isStarlightProject) {
note(
`\u2705 Detected Starlight project: ${pc.cyan(smartDefaults.title || "Documentation")}`,
"Project Info"
);
} else {
note("\u26A0\uFE0F Starlight not detected - using fallback configuration", "Project Info");
}
if (smartDefaults.recommendations.length > 0) {
note(smartDefaults.recommendations.join("\n"), "Recommendations");
}
}
async function getInputPath(detectedSources, outputDir) {
if (detectedSources.length > 0) {
const isStarlightDir = detectedSources[0] === outputDir || detectedSources[0].includes("src/content/docs");
const message = isStarlightDir ? `Found Starlight content directory and ${detectedSources.length > 1 ? "other directories" : "import directories"}: ${detectedSources.map((d) => pc.cyan(d)).join(", ")}` : `Found document directories: ${detectedSources.map((d) => pc.cyan(d)).join(", ")}`;
note(message, "Available Sources");
const sourceChoice = await select({
message: "Choose input source:",
options: [
...detectedSources.map((source, index) => {
const isMainContentDir = index === 0 && isStarlightDir;
return {
value: source,
label: `\u{1F4C1} ${source}`,
hint: isMainContentDir ? "Your Starlight content directory" : "Document directory"
};
}),
{
value: "custom",
label: "\u270F\uFE0F Custom path",
hint: "Specify a different path"
}
]
});
if (isCancel(sourceChoice)) {
cancel("Operation cancelled");
process.exit(0);
}
if (sourceChoice === "custom") {
return await getCustomPath("Enter path to convert:");
}
return sourceChoice;
}
return await getCustomPath("What would you like to convert?");
}
async function getCustomPath(message) {
const customPath = await text({
message,
placeholder: "./docs or ./document.md",
validate: (value) => {
if (!value) return "Please provide an input path";
const resolved = resolve2(value);
const type = detectInputType(resolved);
if (type === "not-found") return "Path does not exist";
return;
}
});
if (isCancel(customPath)) {
cancel("Operation cancelled");
process.exit(0);
}
return customPath;
}
function showConversionPreview(resolvedInput, inputType) {
if (inputType === "directory") {
const sampleFiles = getSampleFiles(resolvedInput);
if (sampleFiles.length > 0) {
note(
`Found ${sampleFiles.length} convertible files:
${sampleFiles.map((f) => ` \u2022 ${f}`).join("\n")}${sampleFiles.length === 5 ? "\n ... and potentially more" : ""}`,
"Preview"
);
}
} else {
note(`Converting single file: ${pc.cyan(basename(resolvedInput))}`, "Preview");
}
}
async function getAdvancedOptions() {
const advancedOptions = await confirm({
message: "Configure advanced options?",
initialValue: false
});
const defaultOptions = {
preserveStructure: true,
generateTitles: true,
generateDescriptions: true,
addTimestamps: false,
verbose: false,
dryRun: false
};
if (!advancedOptions || isCancel(advancedOptions)) {
return defaultOptions;
}
const preserveStructure = await confirm({
message: "Preserve directory structure?",
initialValue: true
});
if (isCancel(preserveStructure)) {
cancel("Operation cancelled");
process.exit(0);
}
const contentOptions = await multiselect({
message: "What should be auto-generated?",
options: [
{
value: "titles",
label: "Titles from content",
hint: "Extract titles from headings or filenames"
},
{
value: "descriptions",
label: "Descriptions from content",
hint: "Generate descriptions from first paragraph"
},
{
value: "timestamps",
label: "Last updated timestamps",
hint: "Add conversion date to frontmatter"
}
],
initialValues: ["titles", "descriptions"]
});
if (isCancel(contentOptions)) {
cancel("Operation cancelled");
process.exit(0);
}
const outputOptions = await multiselect({
message: "Output preferences:",
options: [
{ value: "verbose", label: "Verbose output", hint: "Show detailed conversion logs" },
{ value: "dryRun", label: "Dry run", hint: "Preview changes without writing files" }
],
initialValues: []
});
if (isCancel(outputOptions)) {
cancel("Operation cancelled");
process.exit(0);
}
return {
preserveStructure,
generateTitles: contentOptions.includes("titles"),
generateDescriptions: contentOptions.includes("descriptions"),
addTimestamps: contentOptions.includes("timestamps"),
verbose: outputOptions.includes("verbose"),
dryRun: outputOptions.includes("dryRun")
};
}
function showResults(results, converterOptions) {
const stats = getFormattedStats(results);
if (stats.total > 0) {
note(
`${pc.green("\u2705 Successful:")} ${stats.successful} files
` + (stats.skipped > 0 ? `${pc.yellow("\u23ED\uFE0F Skipped:")} ${stats.skipped} files
` : "") + (stats.failed > 0 ? `${pc.red("\u274C Failed:")} ${stats.failed} files
` : "") + (converterOptions.dryRun ? pc.yellow("\u{1F9EA} Dry run - no files were modified") : ""),
"Results"
);
}
const successfulResults = results.filter((r) => r.success).slice(0, 3);
if (successfulResults.length > 0 && !converterOptions.dryRun) {
note(
`${successfulResults.map((r) => `\u2022 ${pc.cyan(relative(process.cwd(), r.inputPath))} \u2192 ${pc.green(relative(process.cwd(), r.outputPath))}`).join("\n")}`,
"Sample conversions"
);
}
}
async function interactiveConvert() {
intro(pc.bgMagenta(pc.black(" Starlight Document Converter ")));
const smartDefaults = getSmartDefaults();
const detectedSources = detectInputSources();
showProjectInfo(smartDefaults);
const inputPath = await getInputPath(detectedSources, smartDefaults.outputDir);
const resolvedInput = resolve2(inputPath);
const inputType = detectInputType(resolvedInput);
showConversionPreview(resolvedInput, inputType);
const outputDir = await text({
message: "Where should the converted files be saved?",
placeholder: smartDefaults.outputDir,
initialValue: smartDefaults.outputDir
});
if (isCancel(outputDir)) {
cancel("Operation cancelled");
process.exit(0);
}
const advancedOptions = await getAdvancedOptions();
const converterOptions = {
outputDir,
...advancedOptions
};
const confirmConversion = await confirm({
message: `${converterOptions.dryRun ? "Preview" : "Convert"} ${inputType === "directory" ? "directory" : "file"}?`
});
if (!confirmConversion || isCancel(confirmConversion)) {
cancel("Operation cancelled");
process.exit(0);
}
const s = spinner();
s.start(`${converterOptions.dryRun ? "Previewing" : "Converting"} documents...`);
try {
const converter = new DocumentConverter(converterOptions);
const results = inputType === "directory" ? await converter.convertDirectory(resolvedInput) : [await converter.convertFile(resolvedInput)];
s.stop(`Conversion ${converterOptions.dryRun ? "preview" : "completed"}!`);
showResults(results, converterOptions);
converter.printStats();
outro(
`${pc.green("\u{1F389} All done!")} Your documents have been ${converterOptions.dryRun ? "previewed" : "converted successfully"}.`
);
} catch (error) {
s.stop("Conversion failed");
note(`${pc.red("\u274C Error:")} ${error}`, "Conversion failed");
process.exit(1);
}
}
async function configurationWizard() {
intro(pc.bgBlue(pc.black(" Starlight Integration Setup ")));
const projectType = await select({
message: "What type of project are you setting up?",
options: [
{ value: "new", label: "New Starlight project", hint: "Complete setup with Astro config" },
{
value: "existing",
label: "Existing Starlight project",
hint: "Add converter to existing setup"
},
{
value: "standalone",
label: "Standalone CLI usage",
hint: "Just use the command line tool"
}
]
});
if (isCancel(projectType)) {
cancel("Setup cancelled");
return process.exit(0);
}
if (projectType === "standalone") {
note(
`You can now use the converter with:
${pc.cyan("npx starlight-convert <input> [options]")}
For interactive mode:
${pc.cyan("npx starlight-convert")}`,
"CLI Usage"
);
outro("\u{1F389} Setup complete!");
return;
}
const inputDirs = await text({
message: "Which directories should be monitored for documents?",
placeholder: "docs-import,documents,content-drafts",
initialValue: "docs-import"
});
if (isCancel(inputDirs)) {
cancel("Setup cancelled");
return process.exit(0);
}
const inputDirsList = inputDirs.split(",").map((d) => d.trim());
const enableWatch = await confirm({
message: "Enable automatic file watching?",
initialValue: true
});
if (isCancel(enableWatch)) {
cancel("Setup cancelled");
return process.exit(0);
}
const config = `import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import starlightDocumentConverter from 'starlight-document-converter';
export default defineConfig({
integrations: [
starlight({
title: 'My Documentation',
description: 'Documentation powered by Starlight',
social: {
github: 'https://github.com/your-username/your-repo',
},
sidebar: [
{
label: 'Guides',
items: [
{ label: 'Getting Started', link: '/guides/getting-started/' },
],
},
{
label: 'Reference',
items: [
{ label: 'API Reference', link: '/reference/api/' },
],
},
],
}),
starlightDocumentConverter({
watch: ${enableWatch},
inputDirs: ${JSON.stringify(inputDirsList)},
converter: {
outputDir: 'src/content/docs',
preserveStructure: true,
generateTitles: true,
generateDescriptions: true,
verbose: true
}
})
],
});`;
note(`Add this to your ${pc.cyan("astro.config.mjs")}:
${pc.dim(config)}`, "Configuration");
const setupDirectories = await confirm({
message: "Create input directories now?",
initialValue: true
});
if (setupDirectories && !isCancel(setupDirectories)) {
const s = spinner();
s.start("Creating directories...");
try {
const { mkdir } = await import("fs/promises");
for (const dir of inputDirsList) {
await mkdir(dir, { recursive: true });
}
s.stop("Directories created!");
note(
`Created directories:
${inputDirsList.map((d) => `\u2022 ${pc.green(d)}`).join("\n")}
Drop your documents into these folders and they'll be automatically converted!`,
"Next Steps"
);
} catch (error) {
s.stop("Failed to create directories");
note(`${pc.red("\u274C Error:")} Could not create directories: ${error}`, "Error");
}
}
outro(`${pc.green("\u{1F389} Setup complete!")} Your Starlight Document Converter is ready to use.`);
}
program.name("starlight-convert").description("\u{1F31F} Beautiful document converter for Starlight").version("1.7.0").action(async () => {
await interactiveConvert();
});
program.command("convert").description("Convert documents interactively").action(async () => {
await interactiveConvert();
});
program.command("batch").description("Convert documents in batch mode").argument("<input>", "Input file or directory to convert").option("-o, --output <dir>", "Output directory (auto-detected if not specified)").option("--no-preserve", "Don't preserve directory structure", false).option("--no-titles", "Don't auto-generate titles", false).option("--no-descriptions", "Don't auto-generate descriptions", false).option("--timestamps", "Add lastUpdated timestamps", false).option("--category <category>", "Default category for documents", "documentation").option("--fix-links", "Fix internal links during conversion", false).option("--process-images", "Process and copy images during conversion", false).option("--generate-toc", "Generate table of contents", false).option("--validate", "Validate content after conversion", false).option("-v, --verbose", "Show detailed output", false).option("--dry-run", "Preview changes without writing files", false).action(async (input, options) => {
intro(pc.bgCyan(pc.black(" Batch Convert ")));
const inputPath = resolve2(input);
const inputType = detectInputType(inputPath);
const outputDir = getOutputDirectory(options.output);
if (inputType === "not-found") {
note(`${pc.red("\u274C Error:")} Input path "${input}" does not exist`, "Error");
process.exit(1);
}
const smartDefaults = getSmartDefaults();
if (smartDefaults.isStarlightProject) {
note(`\u2705 Detected Starlight project, using: ${pc.cyan(outputDir)}`, "Smart Detection");
} else {
note(`\u26A0\uFE0F Using fallback output directory: ${pc.cyan(outputDir)}`, "Fallback Mode");
}
const s = spinner();
s.start(`${options.dryRun ? "Previewing" : "Converting"} documents...`);
try {
const converter = new DocumentConverter({
outputDir,
preserveStructure: options.preserve,
generateTitles: options.titles,
generateDescriptions: options.descriptions,
addTimestamps: options.timestamps,
defaultCategory: options.category,
fixLinks: options.fixLinks,
processImages: options.processImages,
generateToc: options.generateToc,
validateContent: options.validate,
verbose: options.verbose,
dryRun: options.dryRun
});
const results = inputType === "directory" ? await converter.convertDirectory(inputPath) : [await converter.convertFile(inputPath)];
s.stop(`${options.dryRun ? "Preview" : "Conversion"} completed!`);
const stats = getFormattedStats(results);
note(
`${pc.green("\u2705 Successful:")} ${stats.successful} files
` + (stats.skipped > 0 ? `${pc.yellow("\u23ED\uFE0F Skipped:")} ${stats.skipped} files
` : "") + (stats.failed > 0 ? `${pc.red("\u274C Failed:")} ${stats.failed} files
` : "") + (options.dryRun ? pc.yellow("\u{1F9EA} Dry run - no files were modified") : ""),
"Results"
);
converter.printStats();
outro("\u{1F389} Batch conversion completed!");
} catch (error) {
s.stop("Conversion failed");
note(`${pc.red("\u274C Error:")} ${error}`, "Conversion failed");
process.exit(1);
}
});
program.command("setup").description("Interactive project setup wizard").action(async () => {
await configurationWizard();
});
program.command("watch").description("Watch directory for changes").argument("<input>", "Directory to watch").option("-o, --output <dir>", "Output directory", "src/content/docs").option("-v, --verbose", "Show detailed output").action(async (input, options) => {
intro(pc.bgGreen(pc.black(" File Watcher ")));
const inputPath = resolve2(input);
if (detectInputType(inputPath) !== "directory") {
note(`${pc.red("\u274C Error:")} Watch requires a directory path`, "Error");
process.exit(1);
}
note(`Watching ${pc.cyan(relative(process.cwd(), inputPath))} for changes...`, "Monitoring");
const { watch } = await import("fs");
const converter = new DocumentConverter({
outputDir: options.output,
verbose: options.verbose
});
const watcher = watch(inputPath, { recursive: true }, async (eventType, filename) => {
if (!filename || eventType !== "change") return;
const ext = filename.split(".").pop()?.toLowerCase();
if (["docx", "doc", "txt", "html", "htm", "md", "rtf"].includes(ext || "")) {
const s = spinner();
s.start(`Converting ${filename}...`);
try {
await converter.convertFile(resolve2(inputPath, filename));
s.stop(`${pc.green("\u2705")} Converted: ${filename}`);
} catch (error) {
s.stop(`${pc.red("\u274C")} Failed: ${filename}`);
console.log(` ${pc.red("Error:")} ${error}`);
}
}
});
process.on("SIGINT", () => {
watcher.close();
outro("\u{1F44B} Stopped watching");
process.exit(0);
});
});
program.command("repair").description("Repair frontmatter and content issues in existing Starlight files").argument("<input>", "Input file or directory to repair").option("-o, --output <dir>", "Output directory (defaults to input location)").option("--fix-links", "Fix internal links and references", false).option("--process-images", "Process and copy images to assets directory", false).option("--generate-toc", "Generate table of contents", false).option("--dry-run", "Preview repairs without making changes", false).option("-v, --verbose", "Show detailed output", false).action(async (input, options) => {
intro(pc.bgYellow(pc.black(" Content Repair ")));
const inputPath = resolve2(input);
const inputType = detectInputType(inputPath);
if (inputType === "not-found") {
note(`${pc.red("\u274C Error:")} Input path "${input}" does not exist`, "Error");
process.exit(1);
}
try {
const { repairSingleFile, repairDirectory, showRepairResults, createSpinner } = await import("./cli-commands-IAGYE2JW.js");
const repairOptions = {
output: options.output || (inputType === "directory" ? inputPath : dirname(inputPath)),
fixLinks: options.fixLinks,
processImages: options.processImages,
generateToc: options.generateToc,
dryRun: options.dryRun,
verbose: options.verbose
};
const s = createSpinner("content repair", options.dryRun);
if (inputType === "directory") {
const stats = await repairDirectory(inputPath, repairOptions);
s.stop(`${options.dryRun ? "Analysis" : "Repair"} completed!`);
note(showRepairResults(stats, repairOptions), "Results");
} else {
const result = await repairSingleFile(inputPath, repairOptions);
s.stop(`${options.dryRun ? "Analysis" : "Repair"} completed!`);
const stats = {
filesProcessed: 1,
totalRepaired: result.repaired ? 1 : 0,
totalIssues: result.issues.length
};
if (repairOptions.verbose && result.repaired) {
console.log(`
${pc.cyan(basename(inputPath))}:`);
result.issues.forEach((issue) => console.log(` \u2022 ${issue}`));
}
note(showRepairResults(stats, repairOptions), "Results");
}
outro(`\u{1F389} Content repair ${options.dryRun ? "analysis" : "completed"}!`);
} catch (error) {
note(`${pc.red("\u274C Error:")} ${error}`, "Repair failed");
process.exit(1);
}
});
program.command("validate").description("Validate Starlight content structure and quality").argument("<input>", "Input file or directory to validate").option("--fix-issues", "Automatically fix issues where possible", false).option("--show-details", "Show detailed validation results for all files", false).option("-v, --verbose", "Show verbose output with issue details", false).action(async (input, options) => {
intro(pc.bgBlue(pc.black(" Content Validation ")));
const inputPath = resolve2(input);
const inputType = detectInputType(inputPath);
if (inputType === "not-found") {
note(`${pc.red("\u274C Error:")} Input path "${input}" does not exist`, "Error");
process.exit(1);
}
try {
const { validateSingleFile, validateDirectory, showValidationResults, createSpinner } = await import("./cli-commands-IAGYE2JW.js");
const validateOptions = {
fixIssues: options.fixIssues,
showDetails: options.showDetails,
verbose: options.verbose
};
const s = createSpinner("content validation");
let stats;
if (inputType === "directory") {
stats = await validateDirectory(inputPath, validateOptions);
} else {
const result = await validateSingleFile(inputPath, validateOptions);
stats = {
totalFiles: 1,
validFiles: result.valid ? 1 : 0,
issueCount: result.validation.issues.filter((i) => i.type === "error").length,
allIssues: result.valid ? [] : [{ file: basename(inputPath), validation: result.validation }]
};
console.log(
`
${pc.cyan(basename(inputPath))}: ${result.valid ? pc.green("\u2705 Valid") : pc.red("\u274C Issues")}`
);
if (result.validation.score) {
const scoreColor = result.validation.score.overall === "good" ? pc.green : result.validation.score.overall === "fair" ? pc.yellow : pc.red;
console.log(`Quality: ${scoreColor(result.validation.score.overall.toUpperCase())}`);
}
if (!result.valid) {
result.validation.issues.forEach((issue) => {
const icon = issue.type === "error" ? "\u274C" : issue.type === "warning" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
console.log(` ${icon} ${issue.message}`);
});
}
}
s.stop("Validation completed!");
note(showValidationResults(stats), "Validation Summary");
if (options.fixIssues && stats.allIssues.length > 0) {
const shouldFix = await confirm({
message: `Fix ${stats.allIssues.length} files with issues?`,
initialValue: true
});
if (shouldFix && !isCancel(shouldFix)) {
note("Running automatic repair...", "Auto-fix");
const { repairDirectory, repairSingleFile } = await import("./cli-commands-IAGYE2JW.js");
const repairOptions = {
output: inputType === "directory" ? inputPath : dirname(inputPath),
fixLinks: false,
processImages: false,
generateToc: false,
dryRun: false,
verbose: false
};
const repairSpinner = createSpinner("auto-repair");
if (inputType === "directory") {
await repairDirectory(inputPath, repairOptions);
} else {
await repairSingleFile(inputPath, repairOptions);
}
repairSpinner.stop("Auto-repair completed!");
note(
"Issues have been automatically fixed. Re-run validation to verify.",
"Auto-fix Complete"
);
}
}
const successRate = stats.totalFiles > 0 ? Math.round(stats.validFiles / stats.totalFiles * 100) : 100;
outro(
`\u{1F389} Validation completed! ${successRate >= 90 ? "Excellent quality!" : successRate >= 70 ? "Good quality." : "Consider improvements."}`
);
} catch (error) {
note(`${pc.red("\u274C Error:")} ${error}`, "Validation failed");
process.exit(1);
}
});
program.addHelpText("before", createBrandHeader("Starlight Document Converter", "1.7.0"));
program.addHelpText(
"after",
formatHelpSection("Basic Commands", [
{
name: "starlight-convert",
description: "Interactive mode with smart detection and guided setup"
},
{
name: "starlight-convert setup",
description: "Project setup wizard for new Astro Starlight projects"
},
{
name: "starlight-convert batch <input>",
description: "Convert multiple files or entire directories"
},
{
name: "starlight-convert watch <input>",
description: "Watch directory for changes and auto-convert"
}
]) + formatHelpSection("Content Management", [
{
name: "starlight-convert repair <input>",
description: "Fix frontmatter, links, images, and content issues"
},
{
name: "starlight-convert validate <input>",
description: "Validate content structure and quality scoring"
}
]) + formatHelpSection("Common Options", [
{ name: "--dry-run", description: "Preview changes without modifying any files" },
{ name: "-v, --verbose", description: "Show detailed output and progress information" },
{ name: "-o, --output <dir>", description: "Specify output directory for converted files" }
]) + formatHelpSection("Examples", [
{
name: "Batch Conversion",
description: "starlight-convert batch docs/ --generate-toc --fix-links"
},
{
name: "Content Repair",
description: "starlight-convert repair content/ --process-images --dry-run"
},
{
name: "Quality Check",
description: "starlight-convert validate docs/ --show-details --verbose"
}
]) + `
${boxes.info("For complete documentation and advanced usage examples, visit:\nhttps://github.com/entro314-labs/starlight-document-converter", "Documentation")}
`
);
if (process.argv.length === 2) {
interactiveConvert();
} else {
program.parse();
}
//# sourceMappingURL=cli.js.map