diff options
Diffstat (limited to 'packages/cli/src/config')
| -rw-r--r-- | packages/cli/src/config/args.ts | 43 | ||||
| -rw-r--r-- | packages/cli/src/config/config.ts | 110 | ||||
| -rw-r--r-- | packages/cli/src/config/env.ts | 48 | ||||
| -rw-r--r-- | packages/cli/src/config/globalConfig.ts | 50 |
4 files changed, 110 insertions, 141 deletions
diff --git a/packages/cli/src/config/args.ts b/packages/cli/src/config/args.ts deleted file mode 100644 index a71b4b66..00000000 --- a/packages/cli/src/config/args.ts +++ /dev/null @@ -1,43 +0,0 @@ -import yargs from 'yargs/yargs'; -import { hideBin } from 'yargs/helpers'; - -const DEFAULT_GEMINI_MODEL = 'gemini-2.5-flash-preview-04-17'; - -export interface CliArgs { - target_dir: string | undefined; - model: string | undefined; - _: Array<string | number>; // Captures positional arguments - // Add other expected args here if needed - // e.g., verbose?: boolean; -} - -export async function parseArguments(): Promise<CliArgs> { - const argv = await yargs(hideBin(process.argv)) - .option('target_dir', { - alias: 'd', - type: 'string', - description: - 'The target directory for Gemini operations. Defaults to the current working directory.', - }) - .option('model', { - alias: 'm', - type: 'string', - description: `The Gemini model to use. Defaults to ${DEFAULT_GEMINI_MODEL}.`, - default: DEFAULT_GEMINI_MODEL, - }) - .help() - .alias('h', 'help') - .strict() // Keep strict mode to error on unknown options - .parseAsync(); - - // Handle warnings for extra arguments here - if (argv._ && argv._.length > 0) { - console.warn( - `Warning: Additional arguments provided (${argv._.join(', ')}), but will be ignored.`, - ); - } - - // Cast to the interface to ensure the structure aligns with expectations - // Use `unknown` first for safer casting if types might not perfectly match - return argv as unknown as CliArgs; -} diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts new file mode 100644 index 00000000..ca9cbc18 --- /dev/null +++ b/packages/cli/src/config/config.ts @@ -0,0 +1,110 @@ +import yargs from 'yargs/yargs'; +import { hideBin } from 'yargs/helpers'; +import * as dotenv from 'dotenv'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import process from 'node:process'; + +const DEFAULT_GEMINI_MODEL = 'gemini-2.5-flash-preview-04-17'; + +export class Config { + private apiKey: string; + private model: string; + private targetDir: string; + private extraArgs: (string | number)[]; // Captures positional arguments + + constructor(apiKey: string, model: string, targetDir: string, extraArgs: (string | number)[]) { + this.apiKey = apiKey; + this.model = model; + this.targetDir = targetDir; + this.extraArgs = extraArgs; + } + + getApiKey(): string { + return this.apiKey; + } + + getModel(): string { + return this.model; + } + + getTargetDir(): string { + return this.targetDir; + } + + getExtraArgs(): (string | number)[] { + return this.extraArgs; + } +} + +export function loadConfig(): Config { + loadEnvironment(); + const argv = parseArguments(); + return new Config( + process.env.GEMINI_API_KEY || "", + argv.model || process.env.GEMINI_API_KEY || DEFAULT_GEMINI_MODEL, + argv.target_dir || process.cwd(), + argv._, + ); +} + +export const globalConfig = loadConfig(); // TODO(jbd): Remove global state. + +interface CliArgs { + target_dir: string | undefined; + model: string | undefined; + _: (string | number)[]; // Captures positional arguments + // Add other expected args here if needed + // e.g., verbose?: boolean; +} + +function parseArguments(): CliArgs { + const argv = yargs(hideBin(process.argv)) + .option('target_dir', { + alias: 'd', + type: 'string', + description: + 'The target directory for Gemini operations. Defaults to the current working directory.', + }) + .option('model', { + alias: 'm', + type: 'string', + description: `The Gemini model to use. Defaults to ${DEFAULT_GEMINI_MODEL}.`, + default: DEFAULT_GEMINI_MODEL, + }) + .help() + .alias('h', 'help') + .strict() // Keep strict mode to error on unknown options + .argv; + + // Cast to the interface to ensure the structure aligns with expectations + // Use `unknown` first for safer casting if types might not perfectly match + return argv as unknown as CliArgs; +} + + +function findEnvFile(startDir: string): string | null { + // Start search from the provided directory (e.g., current working directory) + let currentDir = path.resolve(startDir); // Ensure absolute path + while (true) { + const envPath = path.join(currentDir, '.env'); + if (fs.existsSync(envPath)) { + return envPath; + } + + const parentDir = path.dirname(currentDir); + if (parentDir === currentDir || !parentDir) { + return null; + } + currentDir = parentDir; + } +} + +function loadEnvironment(): void { + // Start searching from the current working directory by default + const envFilePath = findEnvFile(process.cwd()); + if (!envFilePath) { + return; + } + dotenv.config({ path: envFilePath }); +} diff --git a/packages/cli/src/config/env.ts b/packages/cli/src/config/env.ts deleted file mode 100644 index 51fc0a9c..00000000 --- a/packages/cli/src/config/env.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as dotenv from 'dotenv'; -import * as fs from 'node:fs'; -import * as path from 'node:path'; -import process from 'node:process'; - -function findEnvFile(startDir: string): string | null { - // Start search from the provided directory (e.g., current working directory) - let currentDir = path.resolve(startDir); // Ensure absolute path - while (true) { - const envPath = path.join(currentDir, '.env'); - if (fs.existsSync(envPath)) { - return envPath; - } - - const parentDir = path.dirname(currentDir); - if (parentDir === currentDir || !parentDir) { - return null; - } - currentDir = parentDir; - } -} - -export function loadEnvironment(): void { - // Start searching from the current working directory by default - const envFilePath = findEnvFile(process.cwd()); - - if (envFilePath) { - dotenv.config({ path: envFilePath }); - } - - if (!process.env.GEMINI_API_KEY?.length) { - console.error( - 'Error: GEMINI_API_KEY environment variable is not set. Please visit https://ai.google.dev/gemini-api/docs/api-key to set up a new one.', - ); - process.exit(0); - } -} - -export function getApiKey(): string { - loadEnvironment(); - const apiKey = process.env.GEMINI_API_KEY; - if (!apiKey) { - throw new Error( - 'GEMINI_API_KEY environment variable is not set. Please visit https://ai.google.dev/gemini-api/docs/api-key to set up a new one.', - ); - } - return apiKey; -} diff --git a/packages/cli/src/config/globalConfig.ts b/packages/cli/src/config/globalConfig.ts deleted file mode 100644 index 2b6ad518..00000000 --- a/packages/cli/src/config/globalConfig.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { CliArgs } from './args.js'; // Assuming CliArgs contains the needed fields - -interface GlobalConfig { - model: string; - // Add other global config values here if needed - // e.g., targetDir?: string; -} - -let config: GlobalConfig | null = null; - -/** - * Initializes the global configuration. Should only be called once at application startup. - * @param args The parsed command-line arguments. - */ -export function initializeConfig(args: Pick<CliArgs, 'model'>): void { - if (config) { - console.warn('Global configuration already initialized.'); - return; - } - if (!args.model) { - // This shouldn't happen if default is set correctly in args.ts - throw new Error('Model not provided during config initialization.'); - } - config = { - model: args.model, - // Initialize other config values from args here - }; -} - -/** - * Retrieves the globally stored configuration. - * Throws an error if the configuration has not been initialized. - * @returns The global configuration object. - */ -export function getConfig(): GlobalConfig { - if (!config) { - throw new Error( - 'Global configuration accessed before initialization. Call initializeConfig() first.', - ); - } - return config; -} - -/** - * Helper function to get the configured Gemini model name. - * @returns The model name string. - */ -export function getModel(): string { - return getConfig().model; -}
\ No newline at end of file |
