1- import { WorkerConfig , loadConfig } from "./config.js" ;
1+ import { WorkerConfig , loadConfig , loadConfigFromPath } from "./config.js" ;
22import { CLIError } from "./errors.js" ;
33import {
44 CONFIG ,
@@ -31,6 +31,10 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
3131
3232type BackendChoice = "sqlite" | "postgres" | "both" ;
3333
34+ interface CommandOptions {
35+ config ?: string ;
36+ }
37+
3438/**
3539 * openworkflow -V | --version
3640 * @returns the version string, or "-" if it cannot be determined
@@ -57,11 +61,15 @@ export function getVersion(): string {
5761 return "-" ;
5862}
5963
60- /** openworkflow init */
61- export async function init ( ) : Promise < void > {
64+ /**
65+ * openworkflow init
66+ * @param options - Command options
67+ */
68+ export async function init ( options : CommandOptions = { } ) : Promise < void > {
69+ const configPath = options . config ;
6270 p . intro ( "Initializing OpenWorkflow..." ) ;
6371
64- const { configFile } = await loadConfigWithEnv ( ) ;
72+ const { configFile } = await loadConfigWithEnv ( configPath ) ;
6573 let configFileToDelete : string | null = null ;
6674
6775 if ( configFile ) {
@@ -123,7 +131,7 @@ export async function init(): Promise<void> {
123131 ) ;
124132 }
125133
126- const configFileName = getConfigFileName ( packageJson ) ;
134+ const configFileName = configPath ?? getConfigFileName ( packageJson ) ;
127135 const clientFileName = getClientFileName ( packageJson ) ;
128136 const exampleWorkflowFileName = getExampleWorkflowFileName ( packageJson ) ;
129137 const runFileName = getRunFileName ( packageJson ) ;
@@ -191,11 +199,15 @@ export async function init(): Promise<void> {
191199 p . outro ( "✅ Setup complete!" ) ;
192200}
193201
194- /** openworkflow doctor */
195- export async function doctor ( ) : Promise < void > {
202+ /**
203+ * openworkflow doctor
204+ * @param options - Command options
205+ */
206+ export async function doctor ( options : CommandOptions = { } ) : Promise < void > {
207+ const configPath = options . config ;
196208 consola . start ( "Running OpenWorkflow doctor..." ) ;
197209
198- const { config, configFile } = await loadConfigWithEnv ( ) ;
210+ const { config, configFile } = await loadConfigWithEnv ( configPath ) ;
199211 if ( ! configFile ) {
200212 throw new CLIError (
201213 "No config file found." ,
@@ -244,14 +256,19 @@ export async function doctor(): Promise<void> {
244256 }
245257}
246258
259+ export type WorkerStartOptions = WorkerConfig & CommandOptions ;
260+
247261/**
248262 * openworkflow worker start
249- * @param cliOptions - Worker config overrides
263+ * @param options - Worker config and command options
250264 */
251- export async function workerStart ( cliOptions : WorkerConfig ) : Promise < void > {
265+ export async function workerStart (
266+ options : WorkerStartOptions = { } ,
267+ ) : Promise < void > {
268+ const { config : configPath , ...workerConfig } = options ;
252269 consola . start ( "Starting worker..." ) ;
253270
254- const { config, configFile } = await loadConfigWithEnv ( ) ;
271+ const { config, configFile } = await loadConfigWithEnv ( configPath ) ;
255272 if ( ! configFile ) {
256273 throw new CLIError (
257274 "No config file found." ,
@@ -297,7 +314,7 @@ export async function workerStart(cliOptions: WorkerConfig): Promise<void> {
297314
298315 assertNoDuplicateWorkflows ( workflows ) ;
299316
300- const workerOptions = mergeDefinedOptions ( config . worker , cliOptions ) ;
317+ const workerOptions = mergeDefinedOptions ( config . worker , workerConfig ) ;
301318 if ( workerOptions . concurrency !== undefined ) {
302319 assertPositiveInteger ( "concurrency" , workerOptions . concurrency ) ;
303320 }
@@ -323,11 +340,13 @@ export async function workerStart(cliOptions: WorkerConfig): Promise<void> {
323340/**
324341 * openworkflow dashboard
325342 * Starts the dashboard by delegating to `@openworkflow/dashboard` via npx.
343+ * @param options - Command options
326344 */
327- export async function dashboard ( ) : Promise < void > {
345+ export async function dashboard ( options : CommandOptions = { } ) : Promise < void > {
346+ const configPath = options . config ;
328347 consola . start ( "Starting dashboard..." ) ;
329348
330- const { configFile } = await loadConfigWithEnv ( ) ;
349+ const { configFile } = await loadConfigWithEnv ( configPath ) ;
331350 if ( ! configFile ) {
332351 throw new CLIError (
333352 "No config file found." ,
@@ -808,7 +827,11 @@ function getDevDependenciesToInstall(): string[] {
808827function createConfigFile ( configFileName : string ) : void {
809828 const spinner = p . spinner ( ) ;
810829 spinner . start ( "Writing config..." ) ;
811- const configDestPath = path . join ( process . cwd ( ) , configFileName ) ;
830+ const configDestPath = path . resolve ( process . cwd ( ) , configFileName ) ;
831+
832+ // mkdir if the user specified a config file, and they want it in a dir
833+ mkdirSync ( path . dirname ( configDestPath ) , { recursive : true } ) ;
834+
812835 writeFileSync ( configDestPath , CONFIG , "utf8" ) ;
813836 spinner . stop ( `Config written to ${ configDestPath } ` ) ;
814837}
@@ -1001,12 +1024,15 @@ function updateEnvForPostgres(): void {
10011024
10021025/**
10031026 * Load CLI config after loading .env, and wrap errors for user-facing output.
1027+ * @param configPath - Optional explicit config file path
10041028 * @returns Loaded config and metadata.
10051029 */
1006- async function loadConfigWithEnv ( ) {
1030+ async function loadConfigWithEnv ( configPath ?: string ) {
10071031 loadDotenv ( { quiet : true } ) ;
10081032 try {
1009- return await loadConfig ( ) ;
1033+ return configPath
1034+ ? await loadConfigFromPath ( configPath )
1035+ : await loadConfig ( ) ;
10101036 } catch ( error ) {
10111037 const message = error instanceof Error ? error . message : String ( error ) ;
10121038 throw new CLIError ( "Failed to load OpenWorkflow config." , message ) ;
0 commit comments