mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 17:27:54 +00:00
Introduce a config module to manage configuration (#22)
* Introduce a config module to manage configuration * Remove public modifier
This commit is contained in:
@@ -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;
|
||||
}
|
||||
110
packages/cli/src/config/config.ts
Normal file
110
packages/cli/src/config/config.ts
Normal file
@@ -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 });
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user