capsule-ai-cli
Version:
The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing
170 lines • 8.46 kB
JavaScript
import { Command } from 'commander';
import chalk from 'chalk';
import { startWindow } from './ui/window.js';
import { configManager } from './core/config.js';
import { authService } from './services/auth.js';
import { stateService } from './services/state.js';
import { contextManager } from './services/context.js';
const version = '0.1.5';
const program = new Command();
function getTimeAgo(date) {
const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000);
if (seconds < 60)
return 'just now';
if (seconds < 3600)
return `${Math.floor(seconds / 60)}m ago`;
if (seconds < 86400)
return `${Math.floor(seconds / 3600)}h ago`;
if (seconds < 604800)
return `${Math.floor(seconds / 86400)}d ago`;
return date.toLocaleDateString();
}
async function main() {
try {
await configManager.loadConfig();
program
.name('capsule')
.description('')
.version(version)
.usage('[options]')
.option('--resume', 'Resume the last conversation')
.option('--continue', 'Choose from previous conversations to continue')
.option('--model <model>', 'Set the model to use')
.option('--provider <provider>', 'Set the provider to use')
.option('--task <task>', 'Execute a task in micro mode')
.option('--json', 'Output task results as JSON')
.option('--timeout <seconds>', 'Task execution timeout in seconds');
await program.parseAsync(process.argv);
const options = program.opts();
if (!options.dev) {
const status = await authService.getStatus();
stateService.setLicenseStatus(status);
}
if (options.task) {
const { executeTaskMode } = await import('./services/task-executor.js');
const result = await executeTaskMode({
task: options.task,
model: options.model,
provider: options.provider,
json: options.json,
timeout: options.timeout ? parseInt(options.timeout) : undefined
});
process.exit(result.success ? 0 : 1);
}
if (options.model) {
stateService.setModel(options.model);
}
if (options.provider) {
stateService.setProvider(options.provider);
}
if (options.resume) {
const contexts = contextManager.listContexts();
if (contexts.length > 0) {
const mostRecent = contexts.sort((a, b) => b.created.getTime() - a.created.getTime())[0];
contextManager.setCurrentContext(mostRecent.id);
console.log(chalk.green(`✓ Resumed last conversation from ${getTimeAgo(mostRecent.created)}\n`));
const context = contextManager.getCurrentContext();
console.log(chalk.dim(`Loaded ${context.messages.length} messages`));
console.log(chalk.dim(`Token count: ${context.metadata.totalTokens}\n`));
const messages = context.messages;
const recentMessages = messages.slice(-3);
if (recentMessages.length > 0) {
console.log(chalk.dim('Recent messages:'));
recentMessages.forEach(msg => {
if (msg.role === 'user' || msg.role === 'assistant') {
const role = msg.role === 'user' ? chalk.blue('You:') : chalk.green('Assistant:');
const content = typeof msg.content === 'string' ? msg.content : '(multimodal content)';
const preview = content.substring(0, 80) + (content.length > 80 ? '...' : '');
console.log(`${role} ${chalk.gray(preview)}`);
}
});
console.log();
}
}
else {
console.log(chalk.yellow('No previous conversations found. Starting new chat.\n'));
}
}
if (options.continue) {
const contexts = contextManager.listContexts();
if (contexts.length > 0) {
console.log(chalk.yellow('\nSelect a conversation to continue:\n'));
const inquirer = (await import('inquirer')).default;
const sortedContexts = contexts.sort((a, b) => b.created.getTime() - a.created.getTime());
const choices = sortedContexts.map((ctx, index) => {
const currentContextId = contextManager.getCurrentContext().id;
contextManager.setCurrentContext(ctx.id);
const messages = contextManager.getCurrentContext().messages;
const firstUserMsg = messages.find(m => m.role === 'user');
let contentStr = 'Empty conversation';
if (firstUserMsg) {
if (typeof firstUserMsg.content === 'string') {
contentStr = firstUserMsg.content;
}
else if (Array.isArray(firstUserMsg.content)) {
const textContent = firstUserMsg.content.find((c) => c.type === 'text');
contentStr = textContent?.text || '[multimodal content]';
}
else {
contentStr = '[complex content]';
}
}
contextManager.setCurrentContext(currentContextId);
const previewText = contentStr.substring(0, 50) + (contentStr.length > 50 ? '...' : '');
const timeAgo = getTimeAgo(ctx.created);
return {
name: `${index + 1}. ${previewText} ${chalk.dim(`(${ctx.messageCount} messages, ${timeAgo})`)}`,
value: ctx.id
};
});
choices.push({ name: chalk.gray('Cancel'), value: null });
const { selectedId } = await inquirer.prompt([{
type: 'list',
name: 'selectedId',
message: 'Choose a conversation:',
choices,
pageSize: 10
}]);
if (selectedId) {
contextManager.setCurrentContext(selectedId);
const selected = contexts.find(c => c.id === selectedId);
console.log(chalk.green(`\n✓ Resumed conversation from ${getTimeAgo(selected.created)}\n`));
const context = contextManager.getCurrentContext();
console.log(chalk.dim(`Loaded ${context.messages.length} messages`));
console.log(chalk.dim(`Token count: ${context.metadata.totalTokens}\n`));
const messages = context.messages;
const recentMessages = messages.slice(-3);
if (recentMessages.length > 0) {
console.log(chalk.dim('Recent messages:'));
recentMessages.forEach(msg => {
if (msg.role === 'user' || msg.role === 'assistant') {
const role = msg.role === 'user' ? chalk.blue('You:') : chalk.green('Assistant:');
const content = typeof msg.content === 'string' ? msg.content : '(multimodal content)';
const preview = content.substring(0, 80) + (content.length > 80 ? '...' : '');
console.log(`${role} ${chalk.gray(preview)}`);
}
});
console.log();
}
}
else {
console.log(chalk.gray('\nStarting new conversation.\n'));
}
}
else {
console.log(chalk.yellow('No previous conversations found. Starting new chat.\n'));
}
}
await startWindow();
}
catch (error) {
console.error(chalk.red('Error:'), error);
process.exit(1);
}
}
main().catch((error) => {
console.error(chalk.red('Unhandled error:'), error);
process.exit(1);
});
//# sourceMappingURL=cli.js.map