@meldscience/meld
Version:
pipeable one-shot prompt scripting toolkit
165 lines (145 loc) ⢠5.65 kB
text/typescript
import { Command } from 'commander';
import { setupConfig, loadConfig, RC_FILE } from '../src/config';
import { homedir } from 'os';
import { join } from 'path';
import { existsSync } from 'fs';
import { createInterface } from 'readline';
async function interactiveSetup() {
const rl = createInterface({
input: process.stdin,
output: process.stdout
});
const question = (query: string): Promise<string> => {
return new Promise((resolve) => {
rl.question(query, resolve);
});
};
try {
console.log('\nš§ Welcome to Meld Configuration Setup!\n');
// Ask about default models
console.log('Which model would you like as your default?\n');
console.log(' ⢠claude-3-opus-latest');
console.log(' ⢠claude-3-5-sonnet-latest');
console.log(' ⢠claude-3-5-haiku-latest');
console.log(' ⢠chatgpt-4o-latest');
console.log(' ⢠gpt-4o-mini');
console.log(' ⢠chatgpt-4o1-latest');
console.log(' ⢠gpt-4o1-mini\n');
const defaultOneshot = await question('oneshot default model [claude-3-5-sonnet-latest]: ');
const defaultOneshotcat = await question('oneshotcat default model [claude-3-opus-latest]: ');
// Ask about API keys
console.log('\nNow, let\'s set up your API keys.');
const anthropicKey = await question('Anthropic API key (press Enter to skip): ');
const openaiKey = await question('OpenAI API key (press Enter to skip): ');
// Create config
const config: any = {
modelAliases: {
'claude': 'claude-3-5-sonnet-latest',
'sonnet': 'claude-3-5-sonnet-latest',
'opus': 'claude-3-opus-latest',
'haiku': 'claude-3-5-haiku-latest',
'4o': 'chatgpt-4o-latest',
'4o-mini': 'gpt-4o-mini',
'o1': 'chatgpt-4o1-latest',
'o1-mini': 'gpt-4o1-mini'
},
defaultOneshotModel: defaultOneshot || 'claude-3-5-sonnet-latest',
defaultOneshotcatModel: defaultOneshotcat || 'claude-3-opus-latest'
};
if (anthropicKey) config.anthropicApiKey = anthropicKey;
if (openaiKey) config.openaiApiKey = openaiKey;
setupConfig(config);
console.log('\nā
Configuration saved successfully!');
console.log(`\nYou can modify these settings anytime by editing ${join(homedir(), RC_FILE)}`);
console.log('Or by running meld-config with the appropriate options (see meld-config --help)');
} finally {
rl.close();
}
}
async function main() {
const program = new Command();
program
.name('meld-config')
.description('Configure Meld settings and API keys')
.option('--anthropic-key <key>', 'Set Anthropic API key')
.option('--openai-key <key>', 'Set OpenAI API key')
.option('--default-oneshot <model>', 'Set default model for oneshot command')
.option('--default-oneshotcat <model>', 'Set default model for oneshotcat command')
.option('--alias <alias=model>', 'Add or update a model alias', (value: string, previous: string[]) => {
previous.push(value);
return previous;
}, [])
.option('--init', 'Initialize config with default settings')
.addHelpText('after', `
Examples:
$ meld-config Run interactive setup
$ meld-config --anthropic-key <key> Set Anthropic API key
$ meld-config --openai-key <key> Set OpenAI API key
$ meld-config --default-oneshot claude-3 Set default oneshot model
$ meld-config --default-oneshotcat opus Set default oneshotcat model
$ meld-config --alias "gpt4=gpt-4" Add model alias
$ meld-config --init Reset to default settings
For more examples and documentation:
https://github.com/meldscience/oneshot#readme`);
program.parse(process.argv);
const options = program.opts();
// If no arguments provided and no config exists, run interactive setup
const rcPath = join(homedir(), RC_FILE);
if (process.argv.length === 2 && !existsSync(rcPath)) {
await interactiveSetup();
return;
}
// Handle non-interactive options
if (options.init) {
setupConfig({
modelAliases: {
'claude': 'claude-3-5-sonnet-latest',
'sonnet': 'claude-3-5-sonnet-latest',
'opus': 'claude-3-opus-latest',
'haiku': 'claude-3-5-haiku-latest',
'4o': 'chatgpt-4o-latest',
'4o-mini': 'gpt-4o-mini',
'o1': 'chatgpt-4o1-latest',
'o1-mini': 'gpt-4o1-mini'
},
defaultOneshotModel: 'claude-3-5-sonnet-latest',
defaultOneshotcatModel: 'claude-3-opus-latest'
});
console.log('ā
Initialized default configuration');
return;
}
const config: any = {};
if (options.anthropicKey) {
config.anthropicApiKey = options.anthropicKey;
}
if (options.openaiKey) {
config.openaiApiKey = options.openaiKey;
}
if (options.defaultOneshot) {
config.defaultOneshotModel = options.defaultOneshot;
}
if (options.defaultOneshotcat) {
config.defaultOneshotcatModel = options.defaultOneshotcat;
}
if (options.alias && options.alias.length > 0) {
const aliases: { [key: string]: string } = {};
for (const aliasStr of options.alias) {
const [alias, model] = aliasStr.split('=');
if (!alias || !model) {
console.error('ā Invalid alias format. Use: alias=model');
process.exit(1);
}
aliases[alias] = model;
}
config.modelAliases = aliases;
}
if (Object.keys(config).length > 0) {
setupConfig(config);
console.log('ā
Configuration updated');
}
}
main().catch(error => {
console.error('ā Error:', error.message);
process.exit(1);
});