@clduab11/gemini-flow
Version:
Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.
382 lines (338 loc) • 10.8 kB
text/typescript
/**
* Gemini-Flow - Simplified CLI
*
* Simple AI assistant CLI matching official Gemini CLI patterns
* Core commands: chat, generate, list-models, auth, config
*/
import { Command } from "commander";
import chalk from "chalk";
import { Logger } from "../utils/logger.js";
import { GeminiCLI } from "./gemini-cli.js";
import { readFileSync } from "fs";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
// ES module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Read version from package.json
const packagePath = join(__dirname, "../../package.json");
const packageJson = JSON.parse(readFileSync(packagePath, "utf8"));
const version = packageJson.version;
const program = new Command();
const logger = new Logger("GeminiFlow");
// ASCII art banner - simplified
const banner = chalk.cyan(`
╔═══════════════════════════════════════════╗
║ 🌟 Gemini-Flow v${version} ║
║ Simple AI Assistant CLI ║
║ Powered by Google Gemini ║
╚═══════════════════════════════════════════╝
`);
/**
* Setup the simplified CLI program
*/
function setupProgram(): void {
program
.name("gemini-flow")
.description("Simple AI assistant CLI powered by Google Gemini")
.version(version)
.addHelpText("before", banner);
// Global options - simplified
program
.option("-v, --verbose", "Enable verbose output")
.option("--model <name>", "Model to use (gemini-1.5-flash, gemini-1.5-pro)")
.option("--temperature <temp>", "Temperature (0-2)", parseFloat, 0.7)
.option("--max-tokens <tokens>", "Maximum tokens", parseInt, 1000000)
.option("--json", "JSON output format");
}
/**
* Setup core commands
*/
function setupCommands(): void {
const geminiCLI = new GeminiCLI();
// Chat command (interactive mode) - primary interface
program
.command("chat")
.alias("c")
.description("Start interactive conversation (default mode)")
.argument("[prompt]", "optional initial prompt")
.option("--session <id>", "session ID for persistence")
.action(async (prompt, options) => {
const globalOptions = program.opts();
const mergedOptions = { ...globalOptions, ...options };
try {
await geminiCLI.executeCommand("chat", [prompt], mergedOptions);
} catch (error) {
handleError(error, mergedOptions);
}
});
// Generate command (one-shot generation)
program
.command("generate")
.alias("g")
.description("Generate content from prompt")
.argument("[prompt]", "text prompt to generate from")
.option("-f, --file <path>", "read prompt from file")
.action(async (prompt, options) => {
const globalOptions = program.opts();
const mergedOptions = { ...globalOptions, ...options };
try {
const result = await geminiCLI.executeCommand(
"generate",
[prompt],
mergedOptions,
);
console.log(result);
} catch (error) {
handleError(error, mergedOptions);
}
});
// List models command
program
.command("list-models")
.alias("models")
.description("List available models")
.option("--detailed", "show detailed model information")
.action(async (options) => {
const globalOptions = program.opts();
const mergedOptions = { ...globalOptions, ...options };
try {
const result = await geminiCLI.executeCommand(
"list-models",
[],
mergedOptions,
);
console.log(result);
} catch (error) {
handleError(error, mergedOptions);
}
});
// Auth command
program
.command("auth")
.description("Manage authentication")
.option("--key <apikey>", "set API key")
.option("--test", "test current API key")
.option("--status", "show authentication status")
.option("--clear", "clear authentication")
.action(async (options) => {
try {
const result = await geminiCLI.executeCommand("auth", [], options);
if (result) {
console.log(result);
}
} catch (error) {
handleError(error, options);
}
});
// Config command (simple configuration management)
program
.command("config")
.description("Manage configuration")
.option("--set <key=value>", "set configuration value")
.option("--get <key>", "get configuration value")
.option("--list", "list all configuration")
.option("--reset", "reset to defaults")
.action(async (options) => {
try {
await handleConfigCommand(options);
} catch (error) {
handleError(error, options);
}
});
// Doctor command for diagnostics
program
.command("doctor")
.description("Check system configuration and dependencies")
.action(async () => {
try {
const checks = {
"Node.js version":
process.version.startsWith("v18") ||
process.version.startsWith("v20"),
"Gemini API key":
!!process.env.GEMINI_API_KEY || !!process.env.GOOGLE_AI_API_KEY,
"Memory available":
process.memoryUsage().heapTotal < 1024 * 1024 * 1024, // < 1GB
"Write permissions": true,
};
console.log(chalk.blue("\n🏥 System Health Check:\n"));
Object.entries(checks).forEach(([check, passed]) => {
const status = passed ? chalk.green("✅ PASS") : chalk.red("❌ FAIL");
console.log(`${status} ${check}`);
});
const allPassed = Object.values(checks).every((v) => v);
if (!allPassed) {
console.log(
chalk.yellow(
"\n⚠️ Some checks failed. Please review the configuration.",
),
);
} else {
console.log(
chalk.green("\n✅ All checks passed! Gemini-Flow is ready to use."),
);
}
} catch (error) {
handleError(error, {});
}
});
}
/**
* Handle config command
*/
async function handleConfigCommand(options: any): Promise<void> {
// Simple configuration management
const configFile = join(process.cwd(), ".gemini-flow-config.json");
if (options.reset) {
const fs = await import("fs");
if (fs.existsSync(configFile)) {
fs.unlinkSync(configFile);
}
console.log(chalk.green("✅ Configuration reset to defaults"));
return;
}
if (options.list) {
const fs = await import("fs");
if (fs.existsSync(configFile)) {
const config = JSON.parse(fs.readFileSync(configFile, "utf8"));
console.log(chalk.blue("\n📋 Current Configuration:\n"));
Object.entries(config).forEach(([key, value]) => {
console.log(chalk.cyan(`${key}: ${value}`));
});
} else {
console.log(chalk.yellow("No configuration file found. Using defaults."));
}
return;
}
if (options.set) {
const [key, value] = options.set.split("=");
if (!key || !value) {
throw new Error("Invalid format. Use --set key=value");
}
const fs = await import("fs");
let config = {};
if (fs.existsSync(configFile)) {
config = JSON.parse(fs.readFileSync(configFile, "utf8"));
}
(config as any)[key] = value;
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
console.log(chalk.green(`✅ Set ${key} = ${value}`));
return;
}
if (options.get) {
const fs = await import("fs");
if (fs.existsSync(configFile)) {
const config = JSON.parse(fs.readFileSync(configFile, "utf8"));
const value = (config as any)[options.get];
if (value !== undefined) {
console.log(value);
} else {
console.log(
chalk.yellow(`Configuration key '${options.get}' not found`),
);
}
} else {
console.log(chalk.yellow("No configuration file found"));
}
return;
}
// Default: show available options
console.log(chalk.blue("\n⚙️ Configuration Commands:\n"));
console.log(
chalk.cyan(" --set key=value "),
chalk.gray("Set configuration value"),
);
console.log(
chalk.cyan(" --get key "),
chalk.gray("Get configuration value"),
);
console.log(
chalk.cyan(" --list "),
chalk.gray("List all configuration"),
);
console.log(
chalk.cyan(" --reset "),
chalk.gray("Reset to defaults"),
);
}
/**
* Handle errors
*/
function handleError(error: any, options: any = {}): void {
const message =
error instanceof Error ? error.message : "Unknown error occurred";
if (options.json) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(chalk.red("Error:"), message);
if (options.verbose && error instanceof Error && error.stack) {
console.error(chalk.gray(error.stack));
}
}
process.exit(1);
}
/**
* Check if should default to interactive mode
*/
function shouldUseInteractiveMode(): boolean {
const args = process.argv.slice(2);
// No arguments or just global options
if (args.length === 0) return true;
// Check if only global options provided
const globalOptions = [
"--verbose",
"-v",
"--model",
"--temperature",
"--max-tokens",
"--json",
];
const isOnlyGlobalOptions = args.every(
(arg) =>
globalOptions.includes(arg) ||
globalOptions.some((opt) => arg.startsWith(opt + "=")) ||
(!arg.startsWith("--") && !arg.startsWith("-")),
);
return isOnlyGlobalOptions;
}
/**
* Main execution
*/
async function main(): Promise<void> {
setupProgram();
setupCommands();
// Default to interactive mode if no specific command
if (shouldUseInteractiveMode()) {
console.log(banner);
console.log(
chalk.yellow("Starting interactive mode... (use Ctrl+C to exit)\n"),
);
const geminiCLI = new GeminiCLI();
try {
await geminiCLI.executeCommand("chat", [], program.opts());
} catch (error) {
handleError(error, program.opts());
}
} else {
// Parse commands normally
try {
await program.parseAsync(process.argv);
} catch (error: any) {
if (error.code === "commander.helpDisplayed") {
process.exit(0);
}
handleError(error, program.opts());
}
}
}
// Error handling
program.exitOverride();
// Start the CLI
main().catch((error) => {
logger.error("CLI startup failed", error);
process.exit(1);
});
// Export for testing
export { program };