diff --git a/packages/chronicle/src/cli/commands/build.ts b/packages/chronicle/src/cli/commands/build.ts index 185c2c0..13e5d67 100644 --- a/packages/chronicle/src/cli/commands/build.ts +++ b/packages/chronicle/src/cli/commands/build.ts @@ -1,18 +1,20 @@ import chalk from 'chalk'; import { Command } from 'commander'; -import { resolveContentDir } from '@/cli/utils/config'; +import { resolveConfigPath, resolveContentDir } from '@/cli/utils/config'; import { PACKAGE_ROOT } from '@/cli/utils/resolve'; import { linkContent } from '@/cli/utils/scaffold'; export const buildCommand = new Command('build') .description('Build for production') - .option('-c, --content ', 'Content directory') + .option('--content ', 'Content directory') + .option('--config ', 'Path to chronicle.yaml') .option( '--preset ', 'Deploy preset (vercel, cloudflare, node-server)' ) .action(async options => { const contentDir = resolveContentDir(options.content); + const configPath = resolveConfigPath(options.config); await linkContent(contentDir); console.log(chalk.cyan('Building for production...')); @@ -24,6 +26,7 @@ export const buildCommand = new Command('build') packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir, + configPath: configPath ?? undefined, preset: options.preset }); diff --git a/packages/chronicle/src/cli/commands/dev.ts b/packages/chronicle/src/cli/commands/dev.ts index 82bbbe2..0ad70d6 100644 --- a/packages/chronicle/src/cli/commands/dev.ts +++ b/packages/chronicle/src/cli/commands/dev.ts @@ -2,16 +2,18 @@ import fs from 'node:fs'; import path from 'node:path'; import chalk from 'chalk'; import { Command } from 'commander'; -import { resolveContentDir } from '@/cli/utils/config'; +import { resolveConfigPath, resolveContentDir } from '@/cli/utils/config'; import { PACKAGE_ROOT } from '@/cli/utils/resolve'; import { linkContent } from '@/cli/utils/scaffold'; export const devCommand = new Command('dev') .description('Start development server') .option('-p, --port ', 'Port number', '3000') - .option('-c, --content ', 'Content directory') + .option('--content ', 'Content directory') + .option('--config ', 'Path to chronicle.yaml') .action(async options => { const contentDir = resolveContentDir(options.content); + const configPath = resolveConfigPath(options.config); const port = parseInt(options.port, 10); await linkContent(contentDir); @@ -21,7 +23,7 @@ export const devCommand = new Command('dev') const { createServer } = await import('vite'); const { createViteConfig } = await import('@/server/vite-config'); - const config = await createViteConfig({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir }); + const config = await createViteConfig({ packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir, configPath: configPath ?? undefined }); const server = await createServer({ ...config, server: { ...config.server, port } diff --git a/packages/chronicle/src/cli/commands/serve.ts b/packages/chronicle/src/cli/commands/serve.ts index 65cfd33..3b63c06 100644 --- a/packages/chronicle/src/cli/commands/serve.ts +++ b/packages/chronicle/src/cli/commands/serve.ts @@ -1,19 +1,21 @@ import chalk from 'chalk'; import { Command } from 'commander'; -import { resolveContentDir } from '@/cli/utils/config'; +import { resolveConfigPath, resolveContentDir } from '@/cli/utils/config'; import { PACKAGE_ROOT } from '@/cli/utils/resolve'; import { linkContent } from '@/cli/utils/scaffold'; export const serveCommand = new Command('serve') .description('Build and start production server') .option('-p, --port ', 'Port number', '3000') - .option('-c, --content ', 'Content directory') + .option('--content ', 'Content directory') + .option('--config ', 'Path to chronicle.yaml') .option( '--preset ', 'Deploy preset (vercel, cloudflare, node-server)' ) .action(async options => { const contentDir = resolveContentDir(options.content); + const configPath = resolveConfigPath(options.config); const port = parseInt(options.port, 10); await linkContent(contentDir); @@ -24,6 +26,7 @@ export const serveCommand = new Command('serve') packageRoot: PACKAGE_ROOT, projectRoot: process.cwd(), contentDir, + configPath: configPath ?? undefined, preset: options.preset }); diff --git a/packages/chronicle/src/cli/commands/start.ts b/packages/chronicle/src/cli/commands/start.ts index ed0ee85..9739ed1 100644 --- a/packages/chronicle/src/cli/commands/start.ts +++ b/packages/chronicle/src/cli/commands/start.ts @@ -7,7 +7,7 @@ import { linkContent } from '@/cli/utils/scaffold'; export const startCommand = new Command('start') .description('Start production server') .option('-p, --port ', 'Port number', '3000') - .option('-c, --content ', 'Content directory') + .option('--content ', 'Content directory') .action(async options => { const contentDir = resolveContentDir(options.content); const port = parseInt(options.port, 10); diff --git a/packages/chronicle/src/cli/utils/config.ts b/packages/chronicle/src/cli/utils/config.ts index eba3ea1..d04a768 100644 --- a/packages/chronicle/src/cli/utils/config.ts +++ b/packages/chronicle/src/cli/utils/config.ts @@ -15,21 +15,20 @@ export function resolveContentDir(contentFlag?: string): string { return path.resolve('content'); } -function resolveConfigPath(contentDir: string): string | null { +export function resolveConfigPath(configFlag?: string): string | null { + if (configFlag) return path.resolve(configFlag); const cwdPath = path.join(process.cwd(), 'chronicle.yaml'); if (fs.existsSync(cwdPath)) return cwdPath; - const contentPath = path.join(contentDir, 'chronicle.yaml'); - if (fs.existsSync(contentPath)) return contentPath; return null; } -export function loadCLIConfig(contentDir: string): CLIConfig { - const configPath = resolveConfigPath(contentDir); +export function loadCLIConfig(contentDir: string, configFlag?: string): CLIConfig { + const configPath = resolveConfigPath(configFlag); if (!configPath) { console.log( chalk.red( - `Error: chronicle.yaml not found in '${process.cwd()}' or '${contentDir}'` + `Error: chronicle.yaml not found in '${process.cwd()}'` ) ); console.log(chalk.gray("Run 'chronicle init' to create one")); diff --git a/packages/chronicle/src/server/vite-config.ts b/packages/chronicle/src/server/vite-config.ts index 636d3fa..578e121 100644 --- a/packages/chronicle/src/server/vite-config.ts +++ b/packages/chronicle/src/server/vite-config.ts @@ -19,26 +19,30 @@ export interface ViteConfigOptions { packageRoot: string; projectRoot: string; contentDir: string; + configPath?: string; preset?: string; } -async function readChronicleConfig(projectRoot: string, contentDir: string): Promise { - for (const dir of [projectRoot, contentDir]) { - const filePath = path.join(dir, 'chronicle.yaml'); +async function readChronicleConfig(projectRoot: string, configPath?: string): Promise { + if (configPath) { try { - return await fs.readFile(filePath, 'utf-8'); - } catch { - // not found, try next + return await fs.readFile(configPath, 'utf-8'); + } catch (error) { + throw new Error(`Failed to read config file '${configPath}': ${(error as Error).message}`); } } - return null; + try { + return await fs.readFile(path.join(projectRoot, 'chronicle.yaml'), 'utf-8'); + } catch { + return null; + } } export async function createViteConfig( options: ViteConfigOptions ): Promise { - const { packageRoot, projectRoot, contentDir, preset } = options; - const rawConfig = await readChronicleConfig(projectRoot, contentDir); + const { packageRoot, projectRoot, contentDir, configPath, preset } = options; + const rawConfig = await readChronicleConfig(projectRoot, configPath); return { root: packageRoot,