import { readdirSync, readFileSync, existsSync } from "node:fs"; import { join } from "node:path"; import { PACKAGE_ROOT } from "../../../util"; import { type CommandResult, success, silentFailure } from "../../lib/command-result"; import { MODULE_PATHS } from "../../lib/paths"; const MODULES_DIR = join(PACKAGE_ROOT, "src", "modules"); const DOC_TYPE_MAP: Record = { command: MODULE_PATHS.docs.command, query: MODULE_PATHS.docs.query, model: MODULE_PATHS.docs.model, feature: MODULE_PATHS.docs.feature, }; function listDocNames(dir: string): string[] { if (!existsSync(dir)) return []; return readdirSync(dir) .filter((f) => f.endsWith(".md")) .map((f) => f.replace(/\.md$/, "")) .sort(); } function formatDocList(type: string, names: string[]): string { if (names.length === 0) return ""; return `${type}: ${names.join(", ")}`; } export function runDocModule( moduleName: string, docType?: string, docName?: string, format = "text", ): CommandResult { if (!existsSync(MODULES_DIR)) { console.error(`Module not found: ${moduleName}`); return silentFailure(); } const modDir = join(MODULES_DIR, moduleName); if (!existsSync(modDir)) { console.error(`Module not found: ${moduleName}`); const available = readdirSync(MODULES_DIR, { withFileTypes: true }) .filter((d) => d.isDirectory()) .map((d) => d.name) .sort(); console.error(`Available modules: ${available.join(", ")}`); return silentFailure(); } // Level 3: specific doc if (docType && docName) { const docSubdir = DOC_TYPE_MAP[docType]; if (!docSubdir) { console.error(`Unknown doc type: ${docType}`); console.error(`Available types: ${Object.keys(DOC_TYPE_MAP).join(", ")}`); return silentFailure(); } const docPath = join(modDir, docSubdir, `${docName}.md`); if (!existsSync(docPath)) { console.error(`Doc not found: ${moduleName}/${docType}/${docName}`); const available = listDocNames(join(modDir, docSubdir)); if (available.length > 0) { console.error(`Available ${docType}s: ${available.join(", ")}`); } else { console.error(`No ${docType} docs found for ${moduleName}`); } return silentFailure(); } const content = readFileSync(docPath, "utf-8"); if (format === "json") { console.log( JSON.stringify({ module: moduleName, type: docType, name: docName, content }, null, 2), ); } else { console.log(content); } return success(); } // Level 2: full module detail const readmePath = join(modDir, "README.md"); const readme = existsSync(readmePath) ? readFileSync(readmePath, "utf-8") : ""; const docs: Record = {}; for (const [type, subdir] of Object.entries(DOC_TYPE_MAP)) { const names = listDocNames(join(modDir, subdir)); if (names.length > 0) docs[type] = names; } if (format === "json") { console.log(JSON.stringify({ module: moduleName, readme, docs }, null, 2)); } else { if (readme) { console.log(readme); } else { console.log(`# ${moduleName}\n\nNo README found.\n`); } const sections: string[] = []; for (const [type, names] of Object.entries(docs)) { sections.push(formatDocList(type, names)); } if (sections.length > 0) { console.log("\n## Available Documentation\n"); console.log(sections.join("\n")); } } return success(); }