kob-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,55 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { KobApiClient } from '../utils/api.js';
5
+ import { getConfig } from '../utils/config.js';
6
+ import { handleApiError, validateRequired } from '../utils/errors.js';
7
+
8
+ function formatV2Model(provider: string, model?: string): string {
9
+ const m = model || 'deepseek-chat';
10
+ return m.includes('/') ? m : `${provider.toLowerCase()}/${m}`;
11
+ }
12
+
13
+ export const askCommand = new Command('ask')
14
+ .description('Ask a question to AI')
15
+ .argument('<question>', 'Your question')
16
+ .option('-p, --provider <provider>', 'AI provider (DeepSeek, OpenRouter, DeepInfra)', 'DeepSeek')
17
+ .option('-m, --model <model>', 'Model ID')
18
+ .option('-t, --temperature <temperature>', 'Temperature (0.0-2.0)', '0.7')
19
+ .option('--max-tokens <maxTokens>', 'Maximum tokens', '4096')
20
+ .option('--system-prompt <systemPrompt>', 'System prompt')
21
+ .action(async (question, opts) => {
22
+ const spinner = ora('Thinking...').start();
23
+
24
+ try {
25
+ const config = getConfig();
26
+ const client = new KobApiClient(config);
27
+
28
+ validateRequired(opts.provider, 'Provider');
29
+ const model = formatV2Model(opts.provider, opts.model || config.modelId);
30
+
31
+ let fullContent = '';
32
+ for await (const chunk of client.chatStream(
33
+ model,
34
+ [{ role: 'user', content: question }],
35
+ {
36
+ temperature: parseFloat(opts.temperature),
37
+ max_tokens: parseInt(opts.maxTokens),
38
+ system_prompt: opts.systemPrompt,
39
+ }
40
+ )) {
41
+ const delta = chunk.choices?.[0]?.delta?.content;
42
+ if (delta) fullContent += delta;
43
+ }
44
+
45
+ spinner.succeed('Answer received!');
46
+
47
+ console.log(chalk.bold.cyan('\n๐Ÿ’ก Answer:'));
48
+ console.log(chalk.dim('โ”€'.repeat(80)));
49
+ console.log(fullContent);
50
+ console.log('');
51
+ } catch (error) {
52
+ spinner.fail('Failed to get answer');
53
+ handleApiError(error);
54
+ }
55
+ });
@@ -0,0 +1,72 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { KobApiClient } from '../utils/api.js';
5
+ import { getConfig } from '../utils/config.js';
6
+ import { handleApiError } from '../utils/errors.js';
7
+ import type { UserToken } from '../types/index.js';
8
+
9
+ const brand = chalk.hex('#38bdf8');
10
+ const green = chalk.hex('#34d399');
11
+ const dim = chalk.dim;
12
+ const accent = chalk.hex('#a78bfa');
13
+
14
+ export const authVerifyCommand = new Command('auth:verify')
15
+ .description('Verify API connection')
16
+ .action(async () => {
17
+ const spinner = ora({
18
+ text: `${accent('Authenticating')} ${dim('ยท')} ${dim('connecting to API')}`,
19
+ color: 'cyan',
20
+ spinner: 'dots12',
21
+ }).start();
22
+
23
+ try {
24
+ const config = getConfig();
25
+ const client = new KobApiClient(config);
26
+
27
+ const data = await client.post<UserToken>('/api/tokens/verify');
28
+
29
+ spinner.stop();
30
+ process.stdout.write('\x1B[?25l');
31
+
32
+ console.log(` ${green('โœ”')} ${green.bold('Connected')} ${dim('ยท')} ${brand(config.baseUrl)}${' '.repeat(20)}\n`);
33
+ console.log(` ${dim('โ”Œโ”€ Connection ' + 'โ”€'.repeat(38) + 'โ”')}`);
34
+ console.log(` ${dim('โ”‚')} ${dim('User')} ${chalk.bold(data.user_name)} ${dim('ยท')} ${dim(data.key_name)}`);
35
+ console.log(` ${dim('โ”‚')} ${dim('API')} ${brand(config.baseUrl)}`);
36
+ console.log(` ${dim('โ””' + 'โ”€'.repeat(48) + 'โ”˜')}\n`);
37
+ process.stdout.write('\x1B[?25h');
38
+ } catch (error) {
39
+ process.stdout.write('\x1B[?25h');
40
+ spinner.fail('Connection failed');
41
+ handleApiError(error);
42
+ }
43
+ });
44
+
45
+ export const balanceCommand = new Command('balance')
46
+ .description('Check your credit balance')
47
+ .action(async () => {
48
+ const spinner = ora({
49
+ text: `${accent('Fetching balance')} ${dim('ยท')} ${dim('checking credits')}`,
50
+ color: 'cyan',
51
+ spinner: 'dots12',
52
+ }).start();
53
+
54
+ try {
55
+ const config = getConfig();
56
+ const client = new KobApiClient(config);
57
+
58
+ const data = await client.post<UserToken>('/api/tokens/verify');
59
+
60
+ spinner.stop();
61
+ process.stdout.write('\x1B[?25l');
62
+
63
+ console.log(` ${green('โœ”')} ${green.bold('Balance')} ${dim('ยท')} ${brand('credits available')}${' '.repeat(20)}\n`);
64
+ console.log(` ${green.bold(data.credit_balance.toFixed(1))} ${dim('credits')}`);
65
+ console.log(` ${dim('โ‰ˆ $' + (data.credit_balance * 0.01).toFixed(2) + ' USD')}\n`);
66
+ process.stdout.write('\x1B[?25h');
67
+ } catch (error) {
68
+ process.stdout.write('\x1B[?25h');
69
+ spinner.fail('Failed to fetch balance');
70
+ handleApiError(error);
71
+ }
72
+ });
@@ -0,0 +1,146 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { KobApiClient } from '../utils/api.js';
5
+ import { getConfig } from '../utils/config.js';
6
+ import { handleApiError, validateRequired } from '../utils/errors.js';
7
+
8
+ function formatV2Model(provider: string, model: string): string {
9
+ const m = model || 'deepseek-chat';
10
+ return m.includes('/') ? m : `${provider.toLowerCase()}/${m}`;
11
+ }
12
+
13
+ export const chatCommand = new Command('chat')
14
+ .description('Send a message to AI')
15
+ .argument('<message>', 'Message to send to AI')
16
+ .option('-p, --provider <provider>', 'AI provider (DeepSeek, OpenRouter, DeepInfra)', 'DeepSeek')
17
+ .option('-m, --model <model>', 'Model ID')
18
+ .option('-t, --temperature <temperature>', 'Temperature (0.0-2.0)', '0.7')
19
+ .option('--max-tokens <maxTokens>', 'Maximum tokens', '4096')
20
+ .option('--system-prompt <systemPrompt>', 'System prompt')
21
+ .action(async (message, opts) => {
22
+ const spinner = ora('Thinking...').start();
23
+
24
+ try {
25
+ const config = getConfig();
26
+ const client = new KobApiClient(config);
27
+
28
+ validateRequired(opts.provider, 'Provider');
29
+ const model = formatV2Model(opts.provider, opts.model || config.modelId);
30
+
31
+ let fullContent = '';
32
+ for await (const chunk of client.chatStream(
33
+ model,
34
+ [{ role: 'user', content: message }],
35
+ {
36
+ temperature: parseFloat(opts.temperature),
37
+ max_tokens: parseInt(opts.maxTokens),
38
+ system_prompt: opts.systemPrompt,
39
+ }
40
+ )) {
41
+ const delta = chunk.choices?.[0]?.delta?.content;
42
+ if (delta) fullContent += delta;
43
+ }
44
+
45
+ spinner.succeed('Response received!');
46
+
47
+ console.log(chalk.bold.cyan('\n๐Ÿ’ฌ AI Response:'));
48
+ console.log(chalk.dim('โ”€'.repeat(80)));
49
+ console.log(fullContent);
50
+ console.log('');
51
+ } catch (error) {
52
+ spinner.fail('Failed to get response');
53
+ handleApiError(error);
54
+ }
55
+ });
56
+
57
+ export const chatInteractiveCommand = new Command('chat:interactive')
58
+ .description('Interactive chat mode with AI')
59
+ .option('-p, --provider <provider>', 'AI provider (DeepSeek, OpenRouter, DeepInfra)', 'DeepSeek')
60
+ .option('-m, --model <model>', 'Model ID')
61
+ .option('-t, --temperature <temperature>', 'Temperature (0.0-2.0)', '0.7')
62
+ .option('--system-prompt <systemPrompt>', 'System prompt')
63
+ .action(async (opts) => {
64
+ console.log(chalk.bold.cyan('\n๐Ÿค– KOB AI Interactive Chat'));
65
+ console.log(chalk.dim('โ”€'.repeat(60)));
66
+ console.log(chalk.yellow('Type your message and press Enter'));
67
+ console.log(chalk.yellow('Commands: /clear, /stats, /help, /exit'));
68
+ console.log(chalk.dim('โ”€'.repeat(60)));
69
+ console.log('');
70
+
71
+ try {
72
+ const config = getConfig();
73
+ const client = new KobApiClient(config);
74
+
75
+ const model = formatV2Model(opts.provider, opts.model || config.modelId);
76
+ const messages: { role: string; content: string }[] = [];
77
+ let totalTokens = 0;
78
+ let totalCredits = 0;
79
+
80
+ const readline = require('readline');
81
+ const rl = readline.createInterface({
82
+ input: process.stdin,
83
+ output: process.stdout,
84
+ });
85
+
86
+ rl.on('SIGINT', () => {
87
+ console.log(chalk.yellow('\nGoodbye!'));
88
+ rl.close();
89
+ process.exit(0);
90
+ });
91
+
92
+ const askQuestion = () => {
93
+ rl.question(chalk.green('\nYou: '), async (userInput: string) => {
94
+ const input = userInput.trim();
95
+
96
+ if (!input) { askQuestion(); return; }
97
+
98
+ if (input === '/exit' || input === '/quit') {
99
+ console.log(chalk.yellow('\nGoodbye!')); rl.close(); process.exit(0);
100
+ }
101
+ if (input === '/help') {
102
+ console.log(chalk.cyan('\n๐Ÿ“– Commands:\n /clear - Clear history\n /stats - Show statistics\n /exit - Exit\n'));
103
+ askQuestion(); return;
104
+ }
105
+ if (input === '/clear') {
106
+ messages.length = 0; totalTokens = 0; totalCredits = 0;
107
+ console.log(chalk.green('\nโœ“ Conversation cleared'));
108
+ askQuestion(); return;
109
+ }
110
+ if (input === '/stats') {
111
+ console.log(chalk.cyan(`\n๐Ÿ“Š Stats: ${messages.length} msgs, ${totalTokens} tokens, ${totalCredits} credits\n`));
112
+ askQuestion(); return;
113
+ }
114
+
115
+ messages.push({ role: 'user', content: input });
116
+ const spinner = ora('Thinking...').start();
117
+
118
+ try {
119
+ let fullContent = '';
120
+ for await (const chunk of client.chatStream(model, messages, {
121
+ temperature: parseFloat(opts.temperature),
122
+ system_prompt: opts.systemPrompt,
123
+ })) {
124
+ const delta = chunk.choices?.[0]?.delta?.content;
125
+ if (delta) fullContent += delta;
126
+ }
127
+
128
+ spinner.stop();
129
+ messages.push({ role: 'assistant', content: fullContent });
130
+ console.log(chalk.bold.cyan('\nAI:'));
131
+ console.log(fullContent);
132
+ console.log('');
133
+ askQuestion();
134
+ } catch (error) {
135
+ spinner.fail('Failed to get response');
136
+ handleApiError(error);
137
+ askQuestion();
138
+ }
139
+ });
140
+ };
141
+
142
+ askQuestion();
143
+ } catch (error) {
144
+ handleApiError(error);
145
+ }
146
+ });
@@ -0,0 +1,78 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { KobApiClient } from '../utils/api.js';
5
+ import { getConfig } from '../utils/config.js';
6
+ import { handleApiError, validateRequired } from '../utils/errors.js';
7
+ import { runCodeTui, writeFiles, parseFileChanges } from '../ui/code-tui.js';
8
+
9
+ function formatV2Model(provider: string, model?: string): string {
10
+ const m = model || 'deepseek-chat';
11
+ return m.includes('/') ? m : `${provider.toLowerCase()}/${m}`;
12
+ }
13
+
14
+ export const codeCommand = new Command('code')
15
+ .description('Generate code with AI (TUI mode if no args)')
16
+ .argument('[prompt]', 'Code description or request')
17
+ .option('-p, --provider <provider>', 'AI provider (DeepSeek, OpenRouter, DeepInfra)', 'DeepSeek')
18
+ .option('-m, --model <model>', 'Model ID')
19
+ .option('-t, --temperature <temperature>', 'Temperature (0.0-1.0)', '0.3')
20
+ .option('--max-tokens <maxTokens>', 'Maximum tokens', '8192')
21
+ .option('--lang <language>', 'Programming language')
22
+ .option('--system-prompt <systemPrompt>', 'Additional system prompt')
23
+ .action(async (prompt, opts) => {
24
+ if (!prompt) {
25
+ await runCodeTui();
26
+ return;
27
+ }
28
+
29
+ const spinner = ora('Generating code...').start();
30
+
31
+ try {
32
+ const config = getConfig();
33
+ const client = new KobApiClient(config);
34
+
35
+ validateRequired(opts.provider, 'Provider');
36
+ const model = formatV2Model(opts.provider, opts.model || config.modelId);
37
+
38
+ const langHint = opts.lang ? ` in ${opts.lang}` : '';
39
+ const systemPrompt = opts.systemPrompt
40
+ ? opts.systemPrompt
41
+ : `You are an expert programmer. Generate clean, production-ready code${langHint}. Provide code with brief explanations. Use proper syntax, error handling, and comments where needed.`;
42
+
43
+ let fullContent = '';
44
+ for await (const chunk of client.chatStream(
45
+ model,
46
+ [{ role: 'user', content: prompt }],
47
+ {
48
+ temperature: parseFloat(opts.temperature),
49
+ max_tokens: parseInt(opts.maxTokens),
50
+ system_prompt: systemPrompt,
51
+ }
52
+ )) {
53
+ const delta = chunk.choices?.[0]?.delta?.content;
54
+ if (delta) fullContent += delta;
55
+ }
56
+
57
+ spinner.succeed('Code generated!');
58
+
59
+ const files = parseFileChanges(fullContent);
60
+ const created = writeFiles(files);
61
+
62
+ if (created.length > 0) {
63
+ console.log(chalk.bold.green('\nโœ… Files created:'));
64
+ for (const f of created) {
65
+ console.log(` ${chalk.green('โœ“')} ${chalk.bold(f)}`);
66
+ }
67
+ console.log('');
68
+ }
69
+
70
+ console.log(chalk.bold.green('\n๐Ÿ’ป Generated Code:'));
71
+ console.log(chalk.dim('โ”€'.repeat(80)));
72
+ console.log(fullContent);
73
+ console.log('');
74
+ } catch (error) {
75
+ spinner.fail('Failed to generate code');
76
+ handleApiError(error);
77
+ }
78
+ });
@@ -0,0 +1,66 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { KobApiClient } from '../utils/api.js';
5
+ import { getConfig } from '../utils/config.js';
6
+ import { handleApiError } from '../utils/errors.js';
7
+ import type { ModelsResponse, ProviderModels, AIModel } from '../types/index.js';
8
+
9
+ export const modelsCommand = new Command('models')
10
+ .description('List available AI models')
11
+ .option('-p, --provider <provider>', 'Filter by provider name')
12
+ .option('-f, --format <format>', 'Output format (table|json)', 'table')
13
+ .action(async (opts) => {
14
+ const spinner = ora('Fetching available models...').start();
15
+
16
+ try {
17
+ const config = getConfig();
18
+ const client = new KobApiClient(config);
19
+
20
+ const data = await client.post<ModelsResponse>('/api/models');
21
+
22
+ spinner.succeed(`Found ${data.model_count} models across ${data.provider_count} providers`);
23
+
24
+ let providers = data.providers;
25
+
26
+ // Filter by provider if specified
27
+ if (opts.provider) {
28
+ providers = providers.filter(p =>
29
+ p.provider.toLowerCase().includes(opts.provider.toLowerCase())
30
+ );
31
+
32
+ if (providers.length === 0) {
33
+ console.log(chalk.yellow(`\nNo providers found matching "${opts.provider}"`));
34
+ return;
35
+ }
36
+ }
37
+
38
+ if (opts.format === 'json') {
39
+ console.log(JSON.stringify(providers, null, 2));
40
+ return;
41
+ }
42
+
43
+ // Display as formatted table
44
+ console.log(chalk.bold.cyan(`\n๐Ÿค– Available AI Models (${data.model_count} total)`));
45
+ console.log('');
46
+
47
+ providers.forEach((provider: ProviderModels) => {
48
+ console.log(chalk.bold.blue(`\n๐Ÿ“ฆ ${provider.provider} (${provider.models.length} models)`));
49
+ console.log(chalk.dim('โ”€'.repeat(100)));
50
+
51
+ provider.models.forEach((model: AIModel, index: number) => {
52
+ console.log(chalk.bold(` ${index + 1}. ${model.displayName}`));
53
+ console.log(` Model ID: ${chalk.cyan(model.modelId)}`);
54
+ console.log(` Input: ${chalk.yellow('$' + model.inputPricePer1M.toFixed(2))}/1M tokens`);
55
+ console.log(` Output: ${chalk.yellow('$' + model.outputPricePer1M.toFixed(2))}/1M tokens`);
56
+ console.log('');
57
+ });
58
+ });
59
+
60
+ console.log(chalk.dim('\n๐Ÿ’ก Use --provider to filter by specific provider'));
61
+ console.log(chalk.dim('๐Ÿ’ก Use --format json for JSON output\n'));
62
+ } catch (error) {
63
+ spinner.fail('Failed to fetch models');
64
+ handleApiError(error);
65
+ }
66
+ });
@@ -0,0 +1,36 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+
4
+ interface Skill {
5
+ name: string;
6
+ icon: string;
7
+ description: string;
8
+ example: string;
9
+ }
10
+
11
+ const skills: Skill[] = [
12
+ { name: 'ask', icon: '๐Ÿ’ก', description: 'Ask questions and get answers from AI', example: 'kob ask "What is TypeScript?"' },
13
+ { name: 'code', icon: '๐Ÿ’ป', description: 'Generate code in any language', example: 'kob code "Write a REST API in Python" --lang python' },
14
+ { name: 'chat', icon: '๐Ÿ’ฌ', description: 'Send messages to AI', example: 'kob chat "Hello"' },
15
+ { name: 'chat:interactive', icon: '๐Ÿ”„', description: 'Interactive conversation mode', example: 'kob chat:interactive' },
16
+ { name: 'stream', icon: '๐ŸŒŠ', description: 'Real-time streaming AI responses', example: 'kob stream "Tell me a story"' },
17
+ { name: 'auth:verify', icon: '๐Ÿ”', description: 'Verify API connection and credentials', example: 'kob auth:verify' },
18
+ { name: 'balance', icon: '๐Ÿ’ฐ', description: 'Check credit balance', example: 'kob balance' },
19
+ { name: 'models', icon: '๐Ÿค–', description: 'Browse available AI models', example: 'kob models --provider DeepSeek' },
20
+ ];
21
+
22
+ export const skillsCommand = new Command('skills')
23
+ .description('List all available KOB CLI skills')
24
+ .action(() => {
25
+ console.log(chalk.bold.cyan('\n๐Ÿง  KOB CLI Skills'));
26
+ console.log(chalk.dim('โ”€'.repeat(60)));
27
+
28
+ skills.forEach((skill) => {
29
+ console.log(`\n ${skill.icon} ${chalk.bold(skill.name)}`);
30
+ console.log(` ${skill.description}`);
31
+ console.log(` ${chalk.dim(skill.example)}`);
32
+ });
33
+
34
+ console.log(chalk.dim('\n๐Ÿ’ก Use: kob <skill> --help for detailed options'));
35
+ console.log('');
36
+ });
@@ -0,0 +1,53 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { KobApiClient } from '../utils/api.js';
4
+ import { getConfig } from '../utils/config.js';
5
+ import { handleApiError, validateRequired } from '../utils/errors.js';
6
+
7
+ function formatV2Model(provider: string, model?: string): string {
8
+ const m = model || 'deepseek-chat';
9
+ return m.includes('/') ? m : `${provider.toLowerCase()}/${m}`;
10
+ }
11
+
12
+ export const streamCommand = new Command('stream')
13
+ .description('Stream AI response in real-time')
14
+ .argument('<message>', 'Message to send to AI')
15
+ .option('-p, --provider <provider>', 'AI provider', 'DeepSeek')
16
+ .option('-m, --model <model>', 'Model ID')
17
+ .option('-t, --temperature <temperature>', 'Temperature (0.0-2.0)', '0.7')
18
+ .option('--system-prompt <systemPrompt>', 'System prompt')
19
+ .action(async (message, opts) => {
20
+ console.log(chalk.bold.cyan('\n๐ŸŒŠ Streaming AI Response...'));
21
+ console.log(chalk.dim('โ”€'.repeat(80)));
22
+
23
+ try {
24
+ const config = getConfig();
25
+ const client = new KobApiClient(config);
26
+
27
+ validateRequired(opts.provider, 'Provider');
28
+ const model = formatV2Model(opts.provider, opts.model || config.modelId);
29
+
30
+ let fullContent = '';
31
+ for await (const chunk of client.chatStream(
32
+ model,
33
+ [{ role: 'user', content: message }],
34
+ {
35
+ temperature: parseFloat(opts.temperature),
36
+ system_prompt: opts.systemPrompt,
37
+ }
38
+ )) {
39
+ const delta = chunk.choices?.[0]?.delta?.content;
40
+ if (delta) {
41
+ process.stdout.write(delta);
42
+ fullContent += delta;
43
+ }
44
+ }
45
+
46
+ console.log('');
47
+ console.log(chalk.dim('โ”€'.repeat(80)));
48
+ console.log(chalk.bold.green('\nโœ“ Stream complete!'));
49
+ console.log('');
50
+ } catch (error) {
51
+ handleApiError(error);
52
+ }
53
+ });
package/src/index.ts ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { authVerifyCommand, balanceCommand } from './commands/auth.js';
6
+ import { modelsCommand } from './commands/models.js';
7
+ import { chatCommand, chatInteractiveCommand } from './commands/chat.js';
8
+ import { streamCommand } from './commands/stream.js';
9
+ import { askCommand } from './commands/ask.js';
10
+ import { codeCommand } from './commands/code.js';
11
+ import { skillsCommand } from './commands/skills.js';
12
+
13
+ const program = new Command();
14
+
15
+ program
16
+ .name('kob')
17
+ .description('KOB CLI - Command-line interface for Kob AI')
18
+ .version('1.0.0');
19
+
20
+ program.addCommand(authVerifyCommand);
21
+ program.addCommand(balanceCommand);
22
+ program.addCommand(chatCommand);
23
+ program.addCommand(chatInteractiveCommand);
24
+ program.addCommand(streamCommand);
25
+ program.addCommand(askCommand);
26
+ program.addCommand(codeCommand);
27
+ program.addCommand(skillsCommand);
28
+ program.addCommand(modelsCommand);
29
+
30
+ function showWelcome(): void {
31
+ const line = chalk.dim('โ”€'.repeat(58));
32
+ const accent = chalk.hex('#a78bfa');
33
+ const subtle = chalk.dim;
34
+ const label = chalk.hex('#fbbf24');
35
+ const green = chalk.hex('#34d399');
36
+ const blue = chalk.hex('#38bdf8');
37
+ const pink = chalk.hex('#f472b6');
38
+
39
+ console.log(`
40
+
41
+ ${blue.bold(' โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— ')}${pink.bold(' โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—')}
42
+ ${green.bold(' โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—')}${pink.bold(' โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘')}
43
+ ${blue.bold(' โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•')}${pink.bold(' โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘')}
44
+ ${accent.bold(' โ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—')}${pink.bold(' โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•‘')}
45
+ ${pink.bold(' โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•')}${pink.bold(' โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘')}
46
+ ${subtle(' โ•šโ•โ• โ•šโ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•')}${subtle(' โ•šโ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•')}
47
+
48
+ ${subtle('โ•ญ' + 'โ”€'.repeat(56) + 'โ•ฎ')}
49
+ ${subtle('โ”‚')} ${chalk.bold('KOB CLI')} ${subtle('ยท')} ${blue.bold('powered by')} ${green.bold('Kob AI')} ${subtle('ยท')} ${pink.bold('made in Thailand')} ${chalk.bold('๐Ÿ‡น๐Ÿ‡ญ')} ${subtle('โ”‚')}
50
+ ${subtle('โ”‚')} ${subtle.italic('v1.0.0')} ${subtle('ยท')} ${subtle('www.kob-ai.dev')} ${subtle('ยท')} ${subtle('AI Command-Line Interface')} ${subtle('โ”‚')}
51
+ ${subtle('โ•ฐ' + 'โ”€'.repeat(56) + 'โ•ฏ')}
52
+
53
+ ${line}
54
+ ${label.bold(' ๐Ÿš€ QUICK START')}
55
+ ${line}
56
+
57
+ ${accent('kob ask "What is AI?"')} ${subtle('Ask anything to AI')}
58
+ ${accent('kob code "REST API"')} ${subtle('Generate code')}
59
+ ${accent('kob skills')} ${subtle('List all available skills')}
60
+
61
+ ${line}
62
+ ${label.bold(' ๐Ÿ“‹ COMMANDS')}
63
+ ${line}
64
+
65
+ ${chalk.hex('#f97316')('๐Ÿ”')} ${accent.bold('auth:verify')} ${accent('balance')} ${subtle('Authentication')}
66
+ ${chalk.hex('#22d3ee')('๐Ÿ’ก')} ${accent.bold('ask')} ${subtle('Ask questions')}
67
+ ${chalk.hex('#34d399')('๐Ÿ’ป')} ${accent.bold('code')} ${accent('--lang python')} ${subtle('Generate code')}
68
+ ${chalk.hex('#38bdf8')('๐Ÿ’ฌ')} ${accent.bold('chat')} ${accent('chat:interactive')} ${accent('stream')} ${subtle('AI Chat')}
69
+ ${chalk.hex('#a78bfa')('๐Ÿค–')} ${accent.bold('models')} ${accent('--provider DeepSeek')} ${subtle('AI Models')}
70
+ ${chalk.hex('#f472b6')('๐Ÿง ')} ${accent.bold('skills')} ${subtle('All skills')}
71
+
72
+ ${line}
73
+ ${subtle('๐Ÿ’ก')} ${subtle.italic('kob <command> --help for detailed options')}
74
+ ${chalk.dim('โ”€').repeat(58)}
75
+ `);
76
+ }
77
+
78
+ // Display welcome if no command provided
79
+ if (process.argv.length <= 2) {
80
+ showWelcome();
81
+ process.exit(0);
82
+ }
83
+
84
+ program.parse(process.argv);