Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/bench_models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs/promises';
import path from 'path';
import chalk from 'chalk';
import { performance } from 'perf_hooks';
import { getBenchmarkModels, generateBenchmarkText, Command, generateCommandStruct, ModelConfig } from './lib/ai';
import { getBenchmarkModels, Command, generateCommandStruct, ModelConfig } from './lib/ai';
import { spinner } from '@clack/prompts';

// Get the models to benchmark from our AI library
Expand Down
10 changes: 0 additions & 10 deletions src/commands/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ async function showCurrentConfig(config: Config) {
}

async function editProvider(config: Config) {
// console.log(chalk.blue('🔄 Change Provider'));

const newProvider = await promptProvider();
config.provider = newProvider;
config.model = SUPPORTED_PROVIDERS[newProvider].defaultModel;
Expand All @@ -130,8 +128,6 @@ async function editProvider(config: Config) {
}

async function editApiKey(config: Config) {
// console.log(chalk.blue('🔑 Update API Key'));

const providerInfo = SUPPORTED_PROVIDERS[config.provider];

// Handle providers that don't support API keys at all
Expand Down Expand Up @@ -159,8 +155,6 @@ async function editApiKey(config: Config) {
}

async function editModel(config: Config) {
// console.log(chalk.blue('🤖 Change Model'));

const currentModel = config.model || SUPPORTED_PROVIDERS[config.provider].defaultModel;

const newModel = await input({
Expand All @@ -185,8 +179,6 @@ async function editModel(config: Config) {
}

async function editBaseUrl(config: Config) {
// console.log(chalk.blue('🌐 Change Base URL'));

const providerInfo = SUPPORTED_PROVIDERS[config.provider];

// Check if the provider supports custom base URL
Expand Down Expand Up @@ -220,8 +212,6 @@ async function editBaseUrl(config: Config) {
}

async function resetConfiguration() {
// console.log(chalk.blue('🔄 Reset Configuration'));

const confirmed = await confirm({
message: chalk.yellow('Are you sure you want to reset your configuration? This will delete your current settings.'),
});
Expand Down
40 changes: 2 additions & 38 deletions src/helpers/hardware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export interface HardwareInfo {

async function getGpuInfo(): Promise<string> {
try {
// Try to dynamically import systeminformation
const si = await import('systeminformation').catch(() => null);

if (si) {
Expand All @@ -18,12 +17,10 @@ async function getGpuInfo(): Promise<string> {
const gpu = graphics.controllers[0];
let gpuInfo = gpu.model || gpu.name || 'Unknown GPU';

// Add vendor if available and not already included
if (gpu.vendor && !gpuInfo.toLowerCase().includes(gpu.vendor.toLowerCase())) {
gpuInfo = `${gpu.vendor} ${gpuInfo}`;
}

// Add VRAM info if available
if (gpu.vram && gpu.vram > 0) {
gpuInfo += ` (${gpu.vram}MB VRAM)`;
}
Expand All @@ -36,19 +33,7 @@ async function getGpuInfo(): Promise<string> {
// Fall through to basic detection
}

// Fallback: Basic GPU detection based on platform
const platform = os.platform();

switch (platform) {
case 'linux':
return 'GPU info unavailable (install systeminformation for detailed info)';
case 'darwin':
return 'GPU info unavailable (install systeminformation for detailed info)';
case 'win32':
return 'GPU info unavailable (install systeminformation for detailed info)';
default:
return 'Unknown GPU';
}
return 'GPU info unavailable (install systeminformation for detailed info)';
}

export async function getHardwareInfo(): Promise<HardwareInfo> {
Expand All @@ -59,28 +44,7 @@ export async function getHardwareInfo(): Promise<HardwareInfo> {
const gpu = await getGpuInfo();

return { cpu, memory, arch, gpu };
} catch (error) {
console.error('Error getting hardware info:', error);
return {
cpu: 'Unknown CPU',
memory: 'Unknown Memory',
arch: 'Unknown Architecture',
gpu: 'Unknown GPU',
};
}
}

// Async version for detailed hardware info including GPU
export async function getDetailedHardwareInfo(): Promise<HardwareInfo> {
try {
const cpu = os.cpus()[0]?.model || 'Unknown CPU';
const memory = `${Math.round(os.totalmem() / 1024 / 1024 / 1024)} GB`;
const arch = os.arch();
const gpu = await getGpuInfo();

return { cpu, memory, arch, gpu };
} catch (error) {
console.error('Error getting detailed hardware info:', error);
} catch {
return {
cpu: 'Unknown CPU',
memory: 'Unknown Memory',
Expand Down
96 changes: 17 additions & 79 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,54 @@ import { Command } from 'commander';
import { select, text as input, spinner, outro, isCancel, cancel, intro } from '@clack/prompts';
import chalk from 'chalk';
import { info, print, runCommand, printWrapped } from './utils';
import { generateCommand, generateCommandStruct, getDefaultModel, getModelFromConfig } from './lib/ai';
import { generateCommandStruct, getDefaultModel, getModelFromConfig, type ModelConfig } from './lib/ai';
import { getOrInitializeConfig } from './lib/config';

import { showConfigUI } from './commands/config';

// Conditional clipboard functionality
async function copyToClipboard(text: string): Promise<boolean> {
try {
// Only import and use clipboard on supported platforms
const os = require('os');
const platform = os.platform();

// Skip clipboard on Android (which shows up as linux) and potentially problematic ARM systems
// Check for Android-specific indicators
const isAndroid = process.env.ANDROID_ROOT || process.env.ANDROID_DATA || platform === 'android';

// Skip if it's Android or if we're on ARM and the environment looks mobile
const isAndroid = process.env.ANDROID_ROOT || process.env.ANDROID_DATA;
if (isAndroid) {
return false;
}

// Try to import the clipboard module
const { Clipboard } = await import('@napi-rs/clipboard');
const clipboard = new Clipboard();
clipboard.setText(text);
return true;
} catch {
// Silently fail if clipboard is not available
return false;
}
}

async function genCommand(prompt: string) {
// Get configuration first
async function resolveModelConfig(): Promise<ModelConfig> {
const config = await getOrInitializeConfig();
if (!config) {
console.error(chalk.red('Failed to initialize configuration. Exiting.'));
process.exit(1);
}

let modelConfig;
try {
modelConfig = getModelFromConfig(config);
return getModelFromConfig(config);
} catch (error) {
await print(chalk.red(`Configuration error: ${error}`));
await print(chalk.yellow('Falling back to environment variables...'));
modelConfig = getDefaultModel();
}

// console log the model being used
// console.log(chalk.blue(`Using model: ${modelConfig.provider}/${modelConfig.modelId}`));

// Show spinner while generating command
const spin = spinner();
spin.start('Loading...');
try {
const result = await generateCommand(prompt);
spin.stop('Command generated successfully!');
return { text: result };
} catch (error) {
spin.stop(chalk.red('Failed to generate command'));
throw error;
console.error(chalk.red(`Configuration error: ${error}`));
console.log(chalk.yellow('Falling back to environment variables...'));
return getDefaultModel();
}
}

async function editPrompt(command: string): Promise<string> {
// For now, just return the command as is
// In a real implementation, this would open an editor
const editedCommand = await input({
message: 'How would you like to edit the command?',
placeholder: command,
});
if (isCancel(editedCommand)) {
cancel('Editing cancelled.');
process.exit(0);
}
return editedCommand;
}

async function refineCommand(currentPrompt: string, command: string): Promise<string> {
const refineText = await input({
message: 'How would you like to refine the command?',
placeholder: '',
});

// Combine the original prompt with the refinement
return `former prompt:${currentPrompt} its command is ${command} refining prompt: ${refineText as string}`;
if (isCancel(refineText)) {
cancel('Refinement cancelled.');
process.exit(0);
}

return `former prompt:${currentPrompt} its command is ${command} refining prompt: ${refineText}`;
}

const program = new Command();
Expand All @@ -105,38 +66,18 @@ program

while (shouldContinue) {
try {
// const result = await genCommand(currentPrompt);
// const command = result.text.trim();

// Get configuration and use it for command generation
const config = await getOrInitializeConfig();
if (!config) {
console.error(chalk.red('Failed to initialize configuration. Exiting.'));
process.exit(1);
}

let modelConfig;
try {
modelConfig = getModelFromConfig(config);
} catch (error) {
console.error(chalk.red(`Configuration error: ${error}`));
console.log(chalk.yellow('Falling back to environment variables...'));
modelConfig = getDefaultModel();
}

// console.log(chalk.blue(`Using model: ${modelConfig.provider}/${modelConfig.modelId}`));
const modelConfig = await resolveModelConfig();

const spin = spinner();
spin.start('Loading...');
const result = await generateCommandStruct(currentPrompt, modelConfig, !silent);

spin.stop('Your command: ');
const command = result.command.trim();
await print(`${command}`);
await print(command);
if ('explanation' in result && result.explanation) {
await info('Explanation:');
const lineWidth = 80;
await printWrapped(`${result.explanation.trim()}`, lineWidth);
await printWrapped(result.explanation.trim(), 80);
}

const clipboardSuccess = await copyToClipboard(command);
Expand All @@ -148,7 +89,6 @@ program
message: 'Run command?',
options: [
{ label: '✅ Yes', value: 'execute' },
// { name: '✏️ Edit command', value: 'edit' },
{ label: '🔧 Refine', value: 'refine' },
{ label: '❌ Cancel', value: 'cancel' },
],
Expand All @@ -164,9 +104,6 @@ program
runCommand(command);
shouldContinue = false;
break;
// case 'edit':
// currentPrompt = await editPrompt(command);
// break;
case 'refine':
currentPrompt = await refineCommand(currentPrompt, command);
break;
Expand All @@ -180,6 +117,7 @@ program
}
}
});

program
.command('config')
.description('Open configuration UI')
Expand Down
Loading
Loading