@knowcode/doc-builder 1.0.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/cli.js ADDED
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require('commander');
4
+ const chalk = require('chalk');
5
+ const prompts = require('prompts');
6
+ const ora = require('ora');
7
+ const fs = require('fs-extra');
8
+ const path = require('path');
9
+ const { build } = require('./lib/builder');
10
+ const { startDevServer } = require('./lib/dev-server');
11
+ const { deployToVercel, setupVercelProject } = require('./lib/deploy');
12
+ const { loadConfig, createDefaultConfig } = require('./lib/config');
13
+ const { execSync } = require('child_process');
14
+
15
+ // Package info
16
+ const packageJson = require('./package.json');
17
+
18
+ // Default to build command if no args provided
19
+ if (process.argv.length === 2) {
20
+ process.argv.push('build');
21
+ }
22
+
23
+ program
24
+ .name('doc-builder')
25
+ .description(packageJson.description)
26
+ .version(packageJson.version)
27
+ .addHelpText('before', `
28
+ ${chalk.cyan('🚀 @juno/doc-builder')} - Transform your markdown into beautiful documentation sites
29
+
30
+ ${chalk.yellow('What it does:')}
31
+ • Converts markdown files to static HTML with a beautiful Notion-inspired theme
32
+ • Automatically generates navigation from your folder structure
33
+ • Supports mermaid diagrams, syntax highlighting, and dark mode
34
+ • Deploys to Vercel with one command (zero configuration)
35
+ • Optional authentication to protect private documentation
36
+
37
+ ${chalk.yellow('Quick Start:')}
38
+ ${chalk.gray('$')} npx @juno/doc-builder ${chalk.gray('# Build and deploy to Vercel')}
39
+ ${chalk.gray('$')} npx @juno/doc-builder build ${chalk.gray('# Build HTML files only')}
40
+ ${chalk.gray('$')} npx @juno/doc-builder dev ${chalk.gray('# Start development server')}
41
+ `);
42
+
43
+ // Build command
44
+ program
45
+ .command('build')
46
+ .description('Build the documentation site to static HTML')
47
+ .option('-c, --config <path>', 'path to config file (default: doc-builder.config.js)')
48
+ .option('-i, --input <dir>', 'input directory containing markdown files (default: docs)')
49
+ .option('-o, --output <dir>', 'output directory for HTML files (default: html)')
50
+ .option('--preset <preset>', 'use a preset configuration (available: cybersolstice)')
51
+ .option('--legacy', 'use legacy mode for backward compatibility')
52
+ .option('--no-auth', 'disable authentication even if configured')
53
+ .option('--no-changelog', 'disable automatic changelog generation')
54
+ .addHelpText('after', `
55
+ ${chalk.yellow('Examples:')}
56
+ ${chalk.gray('$')} doc-builder build ${chalk.gray('# Build with defaults')}
57
+ ${chalk.gray('$')} doc-builder build --input docs --output dist
58
+ ${chalk.gray('$')} doc-builder build --preset cybersolstice ${chalk.gray('# Use JUNO platform preset')}
59
+ ${chalk.gray('$')} doc-builder build --config my-config.js ${chalk.gray('# Use custom config')}
60
+ `)
61
+ .action(async (options) => {
62
+ const spinner = ora('Building documentation...').start();
63
+
64
+ try {
65
+ const config = await loadConfig(options.config || 'doc-builder.config.js', options);
66
+ await build(config);
67
+ spinner.succeed('Documentation built successfully!');
68
+ } catch (error) {
69
+ spinner.fail('Build failed');
70
+ console.error(chalk.red(error.message));
71
+ if (error.stack) {
72
+ console.error(chalk.gray(error.stack));
73
+ }
74
+ process.exit(1);
75
+ }
76
+ });
77
+
78
+ // Dev server command
79
+ program
80
+ .command('dev')
81
+ .description('Start development server with live reload')
82
+ .option('-c, --config <path>', 'path to config file (default: doc-builder.config.js)')
83
+ .option('-p, --port <port>', 'port to run dev server on (default: 3000)')
84
+ .option('-h, --host <host>', 'host to bind to (default: localhost)')
85
+ .option('--no-open', 'don\'t open browser automatically')
86
+ .addHelpText('after', `
87
+ ${chalk.yellow('Examples:')}
88
+ ${chalk.gray('$')} doc-builder dev ${chalk.gray('# Start on http://localhost:3000')}
89
+ ${chalk.gray('$')} doc-builder dev --port 8080 ${chalk.gray('# Use custom port')}
90
+ ${chalk.gray('$')} doc-builder dev --host 0.0.0.0 ${chalk.gray('# Allow external connections')}
91
+ `)
92
+ .action(async (options) => {
93
+ try {
94
+ const config = await loadConfig(options.config, options);
95
+ await startDevServer(config, options.port);
96
+ } catch (error) {
97
+ console.error(chalk.red(error.message));
98
+ process.exit(1);
99
+ }
100
+ });
101
+
102
+ // Deploy command
103
+ program
104
+ .command('deploy')
105
+ .description('Deploy documentation to Vercel (requires Vercel CLI)')
106
+ .option('-c, --config <path>', 'path to config file (default: doc-builder.config.js)')
107
+ .option('--prod', 'deploy to production (default: preview deployment)')
108
+ .option('--no-build', 'skip building before deployment')
109
+ .option('--force', 'force deployment without confirmation')
110
+ .addHelpText('after', `
111
+ ${chalk.yellow('Examples:')}
112
+ ${chalk.gray('$')} doc-builder deploy ${chalk.gray('# Deploy preview to Vercel')}
113
+ ${chalk.gray('$')} doc-builder deploy --prod ${chalk.gray('# Deploy to production')}
114
+ ${chalk.gray('$')} doc-builder deploy --no-build ${chalk.gray('# Deploy existing build')}
115
+
116
+ ${chalk.yellow('First-time setup:')}
117
+ The tool will guide you through:
118
+ 1. Installing Vercel CLI (if needed)
119
+ 2. Creating a new Vercel project
120
+ 3. Configuring deployment settings
121
+
122
+ ${chalk.yellow('Important:')} After deployment, disable Vercel Authentication in project settings for public docs.
123
+ `)
124
+ .action(async (options) => {
125
+ const spinner = ora('Deploying to Vercel...').start();
126
+
127
+ try {
128
+ const config = await loadConfig(options.config, options);
129
+
130
+ // Check if this is the first deployment
131
+ const vercelConfigPath = path.join(process.cwd(), '.vercel', 'project.json');
132
+ if (!fs.existsSync(vercelConfigPath)) {
133
+ spinner.stop();
134
+ console.log(chalk.yellow('\n🚀 First time deploying to Vercel!\n'));
135
+
136
+ const setupConfirm = await prompts({
137
+ type: 'confirm',
138
+ name: 'value',
139
+ message: 'Would you like to set up a new Vercel project?',
140
+ initial: true
141
+ });
142
+
143
+ if (setupConfirm.value) {
144
+ await setupVercelProject(config);
145
+ } else {
146
+ console.log(chalk.gray('Run `vercel` manually to set up your project.'));
147
+ process.exit(0);
148
+ }
149
+ }
150
+
151
+ spinner.start('Deploying to Vercel...');
152
+ const url = await deployToVercel(config, options.prod);
153
+ spinner.succeed(`Deployed successfully! ${chalk.cyan(url)}`);
154
+
155
+ } catch (error) {
156
+ spinner.fail('Deployment failed');
157
+ console.error(chalk.red(error.message));
158
+ process.exit(1);
159
+ }
160
+ });
161
+
162
+ // Init command
163
+ program
164
+ .command('init')
165
+ .description('Initialize doc-builder in your project')
166
+ .option('--config', 'create configuration file')
167
+ .option('--example', 'create example documentation structure')
168
+ .addHelpText('after', `
169
+ ${chalk.yellow('Examples:')}
170
+ ${chalk.gray('$')} doc-builder init --config ${chalk.gray('# Create doc-builder.config.js')}
171
+ ${chalk.gray('$')} doc-builder init --example ${chalk.gray('# Create example docs folder')}
172
+ `)
173
+ .action(async (options) => {
174
+ if (options.config) {
175
+ const configPath = path.join(process.cwd(), 'doc-builder.config.js');
176
+
177
+ if (fs.existsSync(configPath)) {
178
+ const overwrite = await prompts({
179
+ type: 'confirm',
180
+ name: 'value',
181
+ message: 'Config file already exists. Overwrite?',
182
+ initial: false
183
+ });
184
+
185
+ if (!overwrite.value) {
186
+ console.log(chalk.gray('Cancelled.'));
187
+ process.exit(0);
188
+ }
189
+ }
190
+
191
+ const config = await createDefaultConfig();
192
+ fs.writeFileSync(configPath, `module.exports = ${JSON.stringify(config, null, 2)};`);
193
+ console.log(chalk.green('✅ Created doc-builder.config.js'));
194
+ }
195
+
196
+ if (options.example) {
197
+ const docsDir = path.join(process.cwd(), 'docs');
198
+
199
+ if (!fs.existsSync(docsDir)) {
200
+ fs.mkdirSync(docsDir, { recursive: true });
201
+
202
+ // Create example files
203
+ const exampleFiles = {
204
+ 'README.md': `# Welcome to Your Documentation\n\nThis is an example documentation site created with @knowcode/doc-builder.\n\n## Features\n\n- 📝 Write in Markdown\n- 🎨 Beautiful Notion-inspired design\n- 📊 Mermaid diagram support\n- 🌙 Dark mode\n- 🚀 Deploy to Vercel\n\n## Getting Started\n\n1. Edit this file and add your content\n2. Create new markdown files\n3. Run \`npx @knowcode/doc-builder\` to build and deploy\n\n## Example Diagram\n\n\`\`\`mermaid\ngraph TD\n A[Write Docs] --> B[Build]\n B --> C[Deploy]\n C --> D[Share]\n\`\`\`\n`,
205
+ 'getting-started.md': `# Getting Started\n\n**Generated**: ${new Date().toISOString().split('T')[0]}\n**Status**: Draft\n**Verified**: ❓\n\n## Overview\n\nThis guide will help you get started with your documentation.\n\n## Installation\n\nNo installation required! Just use:\n\n\`\`\`bash\nnpx @knowcode/doc-builder\n\`\`\`\n\n## Writing Documentation\n\n1. Create markdown files in the \`docs\` folder\n2. Use folders to organize your content\n3. Add front matter for metadata\n\n## Building\n\nTo build your documentation:\n\n\`\`\`bash\nnpx @knowcode/doc-builder build\n\`\`\`\n\n## Deployment\n\nDeploy to Vercel:\n\n\`\`\`bash\nnpx @knowcode/doc-builder deploy --prod\n\`\`\`\n`,
206
+ 'guides/configuration.md': `# Configuration Guide\n\n**Generated**: ${new Date().toISOString().split('T')[0]}\n**Status**: Draft\n**Verified**: ❓\n\n## Overview\n\n@knowcode/doc-builder works with zero configuration, but you can customize it.\n\n## Configuration File\n\nCreate \`doc-builder.config.js\`:\n\n\`\`\`javascript\nmodule.exports = {\n siteName: 'My Documentation',\n siteDescription: 'Documentation for my project',\n \n features: {\n authentication: false,\n changelog: true,\n mermaid: true,\n darkMode: true\n }\n};\n\`\`\`\n\n## Options\n\n### Site Information\n\n- \`siteName\`: Your documentation site name\n- \`siteDescription\`: Brief description\n\n### Directories\n\n- \`docsDir\`: Input directory (default: 'docs')\n- \`outputDir\`: Output directory (default: 'html')\n\n### Features\n\n- \`authentication\`: Enable password protection\n- \`changelog\`: Generate changelog automatically\n- \`mermaid\`: Support for diagrams\n- \`darkMode\`: Dark theme support\n`
207
+ };
208
+
209
+ // Create example files
210
+ for (const [filePath, content] of Object.entries(exampleFiles)) {
211
+ const fullPath = path.join(docsDir, filePath);
212
+ const dir = path.dirname(fullPath);
213
+
214
+ if (!fs.existsSync(dir)) {
215
+ fs.mkdirSync(dir, { recursive: true });
216
+ }
217
+
218
+ fs.writeFileSync(fullPath, content);
219
+ console.log(chalk.green(`✅ Created ${filePath}`));
220
+ }
221
+
222
+ console.log(chalk.cyan('\\n📚 Example documentation created in docs/ folder'));
223
+ console.log(chalk.gray('\\nNext steps:'));
224
+ console.log(chalk.gray('1. Edit the example files to add your content'));
225
+ console.log(chalk.gray('2. Run `npx @knowcode/doc-builder` to build and deploy'));
226
+ } else {
227
+ console.log(chalk.yellow('⚠️ docs/ directory already exists'));
228
+ }
229
+ }
230
+ });
231
+
232
+ // Add a default command handler for when doc-builder is run without arguments
233
+ program
234
+ .action(async () => {
235
+ // Default action is build + deploy
236
+ console.log(chalk.cyan('\n🚀 Building and deploying your documentation...\n'));
237
+
238
+ try {
239
+ // Build first
240
+ const config = await loadConfig('doc-builder.config.js', { legacy: true });
241
+ const buildSpinner = ora('Building documentation...').start();
242
+ await build(config);
243
+ buildSpinner.succeed('Documentation built successfully!');
244
+
245
+ // Then deploy
246
+ const deploySpinner = ora('Deploying to Vercel...').start();
247
+
248
+ // Check if this is the first deployment
249
+ const vercelConfigPath = path.join(process.cwd(), '.vercel', 'project.json');
250
+ if (!fs.existsSync(vercelConfigPath)) {
251
+ deploySpinner.stop();
252
+ console.log(chalk.yellow('\n🚀 First time deploying to Vercel!\n'));
253
+
254
+ const setupConfirm = await prompts({
255
+ type: 'confirm',
256
+ name: 'value',
257
+ message: 'Would you like to set up a new Vercel project?',
258
+ initial: true
259
+ });
260
+
261
+ if (setupConfirm.value) {
262
+ await setupVercelProject(config);
263
+ } else {
264
+ console.log(chalk.gray('\nTo deploy manually, run: vercel'));
265
+ console.log(chalk.gray('To skip deployment, run: doc-builder build\n'));
266
+ process.exit(0);
267
+ }
268
+ deploySpinner.start('Deploying to Vercel...');
269
+ }
270
+
271
+ const url = await deployToVercel(config, false);
272
+ deploySpinner.succeed(`Deployed successfully! ${chalk.cyan(url)}`);
273
+
274
+ } catch (error) {
275
+ console.error(chalk.red('\nError: ' + error.message));
276
+ console.log(chalk.gray('\nTo build without deploying, run: doc-builder build'));
277
+ process.exit(1);
278
+ }
279
+ });
280
+
281
+ // Parse arguments
282
+ program.parse(process.argv);
package/index.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @knowcode/doc-builder - Programmatic API
3
+ *
4
+ * This module exports functions for use in scripts or other tools
5
+ */
6
+
7
+ const { build } = require('./lib/builder');
8
+ const { startDevServer } = require('./lib/dev-server');
9
+ const { deployToVercel, setupVercelProject } = require('./lib/deploy');
10
+ const { loadConfig, createDefaultConfig } = require('./lib/config');
11
+
12
+ module.exports = {
13
+ // Main functions
14
+ build,
15
+ startDevServer,
16
+ deployToVercel,
17
+ setupVercelProject,
18
+
19
+ // Config utilities
20
+ loadConfig,
21
+ createDefaultConfig,
22
+
23
+ // Convenience wrapper for common operations
24
+ async buildDocs(configPath = 'doc-builder.config.js', options = {}) {
25
+ const config = await loadConfig(configPath, options);
26
+ return build(config);
27
+ },
28
+
29
+ async deploy(configPath = 'doc-builder.config.js', options = {}) {
30
+ const config = await loadConfig(configPath, options);
31
+ return deployToVercel(config, options.prod);
32
+ },
33
+
34
+ async dev(configPath = 'doc-builder.config.js', options = {}) {
35
+ const config = await loadConfig(configPath, options);
36
+ return startDevServer(config, options.port || 3000);
37
+ }
38
+ };
package/lib/builder.js ADDED
@@ -0,0 +1,79 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+
5
+ /**
6
+ * Main build function
7
+ * This wraps the existing build.js functionality
8
+ */
9
+ async function build(config) {
10
+ console.log(chalk.blue(`\n🚀 Building ${config.siteName}...\n`));
11
+
12
+ // Validate config
13
+ if (!config || typeof config !== 'object') {
14
+ throw new Error('Invalid configuration provided to build function');
15
+ }
16
+
17
+ // For now, we'll use the existing build.js file
18
+ // In a future refactor, we'll move all the logic here
19
+ const buildScriptPath = path.join(__dirname, '../../../html/build.js');
20
+
21
+ if (!fs.existsSync(buildScriptPath)) {
22
+ throw new Error('Build script not found. This package must be run from the cybersolstice project.');
23
+ }
24
+
25
+ // Set environment variables for the build script
26
+ process.env.DOC_BUILDER_CONFIG = JSON.stringify(config);
27
+
28
+ // Import and run the existing build
29
+ const buildModule = require(buildScriptPath);
30
+
31
+ // Run the build - it doesn't take parameters, config is passed via env
32
+ if (typeof buildModule.build === 'function') {
33
+ await buildModule.build();
34
+ } else {
35
+ // If it's not a function, it might be auto-executing
36
+ // Just requiring it should run it
37
+ }
38
+
39
+ // Copy assets to output directory
40
+ await copyAssets(config);
41
+
42
+ console.log(chalk.green('\n✨ Build complete!\n'));
43
+ }
44
+
45
+ /**
46
+ * Copy package assets to output directory
47
+ */
48
+ async function copyAssets(config) {
49
+ const outputDir = path.join(process.cwd(), config.outputDir);
50
+ const assetsDir = path.join(__dirname, '../assets');
51
+
52
+ // Ensure output directory exists
53
+ await fs.ensureDir(outputDir);
54
+
55
+ // Copy CSS
56
+ const cssSource = path.join(assetsDir, 'css');
57
+ const cssDest = path.join(outputDir, 'css');
58
+ if (fs.existsSync(cssSource)) {
59
+ await fs.copy(cssSource, cssDest, { overwrite: true });
60
+ }
61
+
62
+ // Copy JS
63
+ const jsSource = path.join(assetsDir, 'js');
64
+ const jsDest = path.join(outputDir, 'js');
65
+ if (fs.existsSync(jsSource)) {
66
+ await fs.copy(jsSource, jsDest, { overwrite: true });
67
+ }
68
+
69
+ // Copy auth.js to root
70
+ const authSource = path.join(assetsDir, 'js', 'auth.js');
71
+ const authDest = path.join(outputDir, 'auth.js');
72
+ if (fs.existsSync(authSource)) {
73
+ await fs.copy(authSource, authDest, { overwrite: true });
74
+ }
75
+ }
76
+
77
+ module.exports = {
78
+ build
79
+ };
package/lib/config.js ADDED
@@ -0,0 +1,255 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+
5
+ /**
6
+ * Default configuration
7
+ */
8
+ const defaultConfig = {
9
+ // Source and output directories
10
+ docsDir: 'docs',
11
+ outputDir: 'html',
12
+
13
+ // Site metadata
14
+ siteName: 'Documentation',
15
+ siteDescription: 'Documentation site built with @knowcode/doc-builder',
16
+
17
+ // Features
18
+ features: {
19
+ authentication: false,
20
+ changelog: true,
21
+ mermaid: true,
22
+ tooltips: true,
23
+ search: false,
24
+ darkMode: true
25
+ },
26
+
27
+ // Authentication (if enabled)
28
+ auth: {
29
+ username: 'admin',
30
+ password: 'password'
31
+ },
32
+
33
+ // Changelog settings
34
+ changelog: {
35
+ daysBack: 14,
36
+ enabled: true
37
+ },
38
+
39
+ // Navigation configuration
40
+ folderOrder: [],
41
+ folderDescriptions: {},
42
+ folderIcons: {},
43
+
44
+ // Deployment
45
+ deployment: {
46
+ platform: 'vercel',
47
+ outputDirectory: 'html'
48
+ }
49
+ };
50
+
51
+ /**
52
+ * Cybersolstice preset - maintains compatibility with existing project
53
+ */
54
+ const cybersolsticePreset = {
55
+ docsDir: 'docs',
56
+ outputDir: 'html',
57
+ siteName: 'JUNO Platform', // Keep original for cybersolstice project
58
+ siteDescription: 'Transforming complex sales through intelligent automation',
59
+
60
+ features: {
61
+ authentication: true,
62
+ changelog: true,
63
+ mermaid: true,
64
+ tooltips: true,
65
+ search: false,
66
+ darkMode: true
67
+ },
68
+
69
+ auth: {
70
+ username: 'juno',
71
+ password: 'docs2025'
72
+ },
73
+
74
+ changelog: {
75
+ daysBack: 14,
76
+ enabled: true
77
+ },
78
+
79
+ // Folder descriptions from existing code
80
+ folderDescriptions: {
81
+ 'product-roadmap': 'Strategic vision, timeline, and feature planning for the JUNO platform',
82
+ 'product-requirements': 'Detailed product specifications, requirements documents, and feature definitions',
83
+ 'architecture': 'System design, data flows, and technical infrastructure documentation',
84
+ 'system-analysis': 'Comprehensive system analysis, functional requirements, and cross-component documentation',
85
+ 'bubble': 'Core application platform - business logic, UI/UX, and user workflows',
86
+ 'quickbase': 'Database schema, data management, and backend operations',
87
+ 'activecampaign': 'Marketing automation integration and lead management system',
88
+ 'juno-signer': 'Document signing service for digital signatures and PDF generation',
89
+ 'juno-api-deprecated': 'Legacy API documentation (deprecated, for reference only)',
90
+ 'postman': 'API testing tools, collections, and test automation',
91
+ 'mcp': 'Model Context Protocol setup and configuration guides',
92
+ 'team': 'Team roles, responsibilities, and task assignments',
93
+ 'thought-leadership': 'Strategic thinking, industry insights, and future vision',
94
+ 'paths': 'Dynamic pathway routing system for insurance applications',
95
+ 'testing': 'Testing procedures, checklists, and quality assurance',
96
+ 'technical': 'Technical documentation and implementation details',
97
+ 'application': 'Application components, data types, and workflows'
98
+ },
99
+
100
+ folderIcons: {
101
+ 'root': 'fas fa-home',
102
+ 'product-roadmap': 'fas fa-road',
103
+ 'product-requirements': 'fas fa-clipboard-list',
104
+ 'architecture': 'fas fa-sitemap',
105
+ 'system-analysis': 'fas fa-analytics',
106
+ 'system': 'fas fa-cogs',
107
+ 'bubble': 'fas fa-bubble',
108
+ 'quickbase': 'fas fa-database',
109
+ 'activecampaign': 'fas fa-envelope',
110
+ 'juno-signer': 'fas fa-signature',
111
+ 'juno-api-deprecated': 'fas fa-archive',
112
+ 'postman': 'fas fa-flask',
113
+ 'mcp': 'fas fa-puzzle-piece',
114
+ 'team': 'fas fa-users',
115
+ 'thought-leadership': 'fas fa-lightbulb',
116
+ 'middleware': 'fas fa-layer-group',
117
+ 'paths': 'fas fa-route',
118
+ 'testing': 'fas fa-vial',
119
+ 'juno-api': 'fas fa-plug'
120
+ },
121
+
122
+ folderOrder: [
123
+ 'product-roadmap',
124
+ 'product-requirements',
125
+ 'architecture',
126
+ 'system-analysis',
127
+ 'bubble',
128
+ 'quickbase',
129
+ 'activecampaign',
130
+ 'juno-signer',
131
+ 'juno-api-deprecated',
132
+ 'postman',
133
+ 'mcp',
134
+ 'team',
135
+ 'thought-leadership'
136
+ ]
137
+ };
138
+
139
+ /**
140
+ * Load configuration
141
+ */
142
+ async function loadConfig(configPath, options = {}) {
143
+ let config = { ...defaultConfig };
144
+
145
+ // Apply preset if specified
146
+ if (options.preset === 'cybersolstice') {
147
+ config = { ...config, ...cybersolsticePreset };
148
+ }
149
+
150
+ // Load custom config file if it exists
151
+ const customConfigPath = path.join(process.cwd(), configPath);
152
+ if (fs.existsSync(customConfigPath)) {
153
+ try {
154
+ const customConfig = require(customConfigPath);
155
+ config = { ...config, ...customConfig };
156
+ console.log(chalk.gray(`Loaded config from ${configPath}`));
157
+ } catch (error) {
158
+ console.warn(chalk.yellow(`Warning: Failed to load config file: ${error.message}`));
159
+ }
160
+ } else if (!options.preset && !options.legacy) {
161
+ console.log(chalk.gray('No config file found, using defaults'));
162
+ }
163
+
164
+ // Apply CLI options (these override config file)
165
+ if (options.input) {
166
+ config.docsDir = options.input;
167
+ }
168
+ if (options.output) {
169
+ config.outputDir = options.output;
170
+ }
171
+ if (options.auth === false) {
172
+ config.features.authentication = false;
173
+ }
174
+ if (options.changelog === false) {
175
+ config.features.changelog = false;
176
+ config.changelog.enabled = false;
177
+ }
178
+
179
+ // Legacy mode - auto-detect structure
180
+ if (options.legacy) {
181
+ const docsPath = path.join(process.cwd(), 'docs');
182
+ const htmlPath = path.join(process.cwd(), 'html');
183
+
184
+ if (fs.existsSync(docsPath) && fs.existsSync(htmlPath)) {
185
+ console.log(chalk.gray('Legacy mode: detected docs/ and html/ structure'));
186
+ config.docsDir = 'docs';
187
+ config.outputDir = 'html';
188
+ }
189
+ }
190
+
191
+ // Validate paths
192
+ const docsPath = path.join(process.cwd(), config.docsDir);
193
+ if (!fs.existsSync(docsPath)) {
194
+ throw new Error(`Documentation directory not found: ${config.docsDir}`);
195
+ }
196
+
197
+ return config;
198
+ }
199
+
200
+ /**
201
+ * Create default configuration
202
+ */
203
+ async function createDefaultConfig() {
204
+ const answers = await require('prompts')([
205
+ {
206
+ type: 'text',
207
+ name: 'siteName',
208
+ message: 'Site name:',
209
+ initial: 'My Documentation'
210
+ },
211
+ {
212
+ type: 'text',
213
+ name: 'siteDescription',
214
+ message: 'Site description:',
215
+ initial: 'Documentation for my project'
216
+ },
217
+ {
218
+ type: 'confirm',
219
+ name: 'authentication',
220
+ message: 'Enable authentication?',
221
+ initial: false
222
+ },
223
+ {
224
+ type: prev => prev ? 'text' : null,
225
+ name: 'authUsername',
226
+ message: 'Authentication username:',
227
+ initial: 'admin'
228
+ },
229
+ {
230
+ type: prev => prev ? 'password' : null,
231
+ name: 'authPassword',
232
+ message: 'Authentication password:',
233
+ initial: 'password'
234
+ }
235
+ ]);
236
+
237
+ const config = { ...defaultConfig };
238
+ config.siteName = answers.siteName;
239
+ config.siteDescription = answers.siteDescription;
240
+ config.features.authentication = answers.authentication;
241
+
242
+ if (answers.authentication) {
243
+ config.auth.username = answers.authUsername;
244
+ config.auth.password = answers.authPassword;
245
+ }
246
+
247
+ return config;
248
+ }
249
+
250
+ module.exports = {
251
+ defaultConfig,
252
+ cybersolsticePreset,
253
+ loadConfig,
254
+ createDefaultConfig
255
+ };