enton-cli 0.1.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,96 @@
1
+ "use strict";
2
+ /**
3
+ * Config Command - Manage CLI configuration
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.configCommand = configCommand;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const cli_table3_1 = __importDefault(require("cli-table3"));
12
+ const manager_1 = require("../config/manager");
13
+ async function configCommand(action, key, value) {
14
+ switch (action) {
15
+ case 'set':
16
+ if (!key || !value) {
17
+ console.log(chalk_1.default.red('Error: Both key and value are required\n'));
18
+ showConfigHelp();
19
+ return;
20
+ }
21
+ await setConfigValue(key, value);
22
+ break;
23
+ case 'get':
24
+ if (!key) {
25
+ console.log(chalk_1.default.red('Error: Key is required\n'));
26
+ showConfigHelp();
27
+ return;
28
+ }
29
+ await getConfigSingle(key);
30
+ break;
31
+ case 'list':
32
+ await listAllConfig();
33
+ break;
34
+ }
35
+ }
36
+ async function setConfigValue(key, value) {
37
+ const validKeys = ['apiUrl', 'defaultAccount', 'outputFormat', 'theme'];
38
+ if (!validKeys.includes(key)) {
39
+ console.log(chalk_1.default.red(`\nError: Unknown config key "${key}"\n`));
40
+ console.log(chalk_1.default.dim('Valid keys: ' + validKeys.join(', ')));
41
+ return;
42
+ }
43
+ // Validate specific values
44
+ if (key === 'outputFormat' && !['text', 'json'].includes(value)) {
45
+ console.log(chalk_1.default.red('\nError: outputFormat must be "text" or "json"\n'));
46
+ return;
47
+ }
48
+ if (key === 'theme' && !['light', 'dark'].includes(value)) {
49
+ console.log(chalk_1.default.red('\nError: theme must be "light" or "dark"\n'));
50
+ return;
51
+ }
52
+ (0, manager_1.setConfig)(key, value);
53
+ console.log(chalk_1.default.green(`\n✅ Set ${key} = ${value}\n`));
54
+ }
55
+ async function getConfigSingle(key) {
56
+ const value = (0, manager_1.getConfigValue)(key);
57
+ if (value === undefined) {
58
+ console.log(chalk_1.default.yellow(`\n⚠️ Config key "${key}" is not set\n`));
59
+ }
60
+ else {
61
+ console.log(`\n${chalk_1.default.bold(key)}: ${chalk_1.default.cyan(String(value))}\n`);
62
+ }
63
+ }
64
+ async function listAllConfig() {
65
+ const config = (0, manager_1.listConfig)();
66
+ console.log(chalk_1.default.bold('\n⚙️ ENTON CLI Configuration\n'));
67
+ const table = new cli_table3_1.default({
68
+ head: [chalk_1.default.bold('Key'), chalk_1.default.bold('Value')],
69
+ style: {
70
+ head: [],
71
+ border: ['dim']
72
+ }
73
+ });
74
+ for (const [key, value] of Object.entries(config)) {
75
+ table.push([
76
+ key,
77
+ value !== undefined ? chalk_1.default.cyan(String(value)) : chalk_1.default.dim('(not set)')
78
+ ]);
79
+ }
80
+ console.log(table.toString());
81
+ console.log(chalk_1.default.dim('\nUse `enton config set <key> <value>` to change values\n'));
82
+ }
83
+ function showConfigHelp() {
84
+ console.log(chalk_1.default.bold('Usage:'));
85
+ console.log(' enton config set <key> <value>');
86
+ console.log(' enton config get <key>');
87
+ console.log(' enton config list');
88
+ console.log('');
89
+ console.log(chalk_1.default.bold('Available Keys:'));
90
+ console.log(' apiUrl - ENTON API URL (default: https://enton.ai)');
91
+ console.log(' defaultAccount - Default trading account to use');
92
+ console.log(' outputFormat - Output format: text | json');
93
+ console.log(' theme - Color theme: light | dark');
94
+ console.log('');
95
+ }
96
+ exports.default = configCommand;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Interactive Mode - REPL-style chat with ENTON
3
+ */
4
+ export declare function interactiveMode(options: {
5
+ json?: boolean;
6
+ quiet?: boolean;
7
+ }): Promise<void>;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ /**
3
+ * Interactive Mode - REPL-style chat with ENTON
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.interactiveMode = interactiveMode;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const ora_1 = __importDefault(require("ora"));
12
+ const inquirer_1 = __importDefault(require("inquirer"));
13
+ const client_1 = require("../api/client");
14
+ const manager_1 = require("../config/manager");
15
+ async function interactiveMode(options) {
16
+ const config = (0, manager_1.getConfig)();
17
+ const client = new client_1.EntonAPIClient(config.apiUrl, config.apiKey);
18
+ console.log(chalk_1.default.dim('Type your questions or commands. Type "exit" to quit.\n'));
19
+ while (true) {
20
+ const { input } = await inquirer_1.default.prompt([
21
+ {
22
+ type: 'input',
23
+ name: 'input',
24
+ message: chalk_1.default.cyan('>'),
25
+ prefix: ''
26
+ }
27
+ ]);
28
+ const trimmed = input.trim();
29
+ // Handle exit commands
30
+ if (['exit', 'quit', 'q', ':q'].includes(trimmed.toLowerCase())) {
31
+ console.log(chalk_1.default.dim('\nGoodbye! 👋\n'));
32
+ break;
33
+ }
34
+ // Handle empty input
35
+ if (!trimmed) {
36
+ continue;
37
+ }
38
+ // Handle special commands
39
+ if (trimmed.startsWith('/')) {
40
+ await handleCommand(trimmed.slice(1), client);
41
+ continue;
42
+ }
43
+ // Send query to ENTON
44
+ await executeQuery(trimmed, client, options);
45
+ }
46
+ }
47
+ async function executeQuery(query, client, options) {
48
+ const spinner = (0, ora_1.default)({
49
+ text: chalk_1.default.dim('Thinking...'),
50
+ color: 'cyan'
51
+ }).start();
52
+ try {
53
+ const response = await client.query(query, {
54
+ onThinking: (message) => {
55
+ spinner.text = chalk_1.default.dim(message);
56
+ },
57
+ onToolStart: (tool, args) => {
58
+ spinner.text = chalk_1.default.yellow(`🔧 ${tool}`);
59
+ },
60
+ onToolResult: (tool, success) => {
61
+ if (success) {
62
+ spinner.text = chalk_1.default.green(`✅ ${tool}`);
63
+ }
64
+ else {
65
+ spinner.text = chalk_1.default.red(`❌ ${tool} failed`);
66
+ }
67
+ }
68
+ });
69
+ spinner.stop();
70
+ if (options.json) {
71
+ console.log(JSON.stringify(response, null, 2));
72
+ }
73
+ else {
74
+ console.log('\n' + formatResponse(response) + '\n');
75
+ }
76
+ }
77
+ catch (error) {
78
+ spinner.fail(chalk_1.default.red('Error'));
79
+ console.log(chalk_1.default.red(` ${error.message}\n`));
80
+ }
81
+ }
82
+ function formatResponse(response) {
83
+ let output = '';
84
+ // Main answer
85
+ if (response.answer) {
86
+ output += chalk_1.default.white(response.answer);
87
+ }
88
+ // Show tools used
89
+ if (response.toolsUsed && response.toolsUsed.length > 0) {
90
+ output += chalk_1.default.dim(`\n\n📊 Tools: ${response.toolsUsed.join(', ')}`);
91
+ }
92
+ // Show timing
93
+ if (response.totalTime) {
94
+ output += chalk_1.default.dim(` | ${response.totalTime}ms`);
95
+ }
96
+ return output;
97
+ }
98
+ async function handleCommand(command, client) {
99
+ const [cmd, ...args] = command.split(' ');
100
+ switch (cmd.toLowerCase()) {
101
+ case 'help':
102
+ showHelp();
103
+ break;
104
+ case 'clear':
105
+ console.clear();
106
+ break;
107
+ case 'history':
108
+ console.log(chalk_1.default.dim('Command history not yet implemented'));
109
+ break;
110
+ case 'status':
111
+ await showStatus(client);
112
+ break;
113
+ default:
114
+ console.log(chalk_1.default.yellow(`Unknown command: /${cmd}`));
115
+ console.log(chalk_1.default.dim('Type /help for available commands'));
116
+ }
117
+ }
118
+ function showHelp() {
119
+ console.log(`
120
+ ${chalk_1.default.bold('Available Commands:')}
121
+ ${chalk_1.default.cyan('/help')} - Show this help message
122
+ ${chalk_1.default.cyan('/clear')} - Clear the screen
123
+ ${chalk_1.default.cyan('/status')} - Show connection status
124
+ ${chalk_1.default.cyan('/history')} - Show command history
125
+
126
+ ${chalk_1.default.bold('Query Examples:')}
127
+ ${chalk_1.default.dim('What is the price of AAPL?')}
128
+ ${chalk_1.default.dim('Get me news about Tesla')}
129
+ ${chalk_1.default.dim('Analyze NVDA stock')}
130
+ ${chalk_1.default.dim('Show my portfolio')}
131
+ ${chalk_1.default.dim('Buy 10 shares of MSFT')}
132
+
133
+ ${chalk_1.default.bold('Exit:')}
134
+ Type ${chalk_1.default.cyan('exit')}, ${chalk_1.default.cyan('quit')}, or ${chalk_1.default.cyan('q')}
135
+ `);
136
+ }
137
+ async function showStatus(client) {
138
+ console.log(`
139
+ ${chalk_1.default.bold('Connection Status:')}
140
+ API URL: ${chalk_1.default.cyan(client.baseUrl)}
141
+ Auth: ${client.isAuthenticated() ? chalk_1.default.green('✅ Connected') : chalk_1.default.yellow('⚠️ Not authenticated')}
142
+ `);
143
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Query Command - Direct single query mode
3
+ */
4
+ export declare function queryCommand(query: string, options: {
5
+ json?: boolean;
6
+ quiet?: boolean;
7
+ }): Promise<void>;
8
+ export default queryCommand;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /**
3
+ * Query Command - Direct single query mode
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.queryCommand = queryCommand;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const ora_1 = __importDefault(require("ora"));
12
+ const client_1 = require("../api/client");
13
+ const manager_1 = require("../config/manager");
14
+ async function queryCommand(query, options) {
15
+ const config = (0, manager_1.getConfig)();
16
+ const client = new client_1.EntonAPIClient(config.apiUrl, config.apiKey);
17
+ const spinner = (0, ora_1.default)({
18
+ text: chalk_1.default.dim('Thinking...'),
19
+ color: 'cyan'
20
+ }).start();
21
+ try {
22
+ const response = await client.query(query, {
23
+ onThinking: (message) => {
24
+ spinner.text = chalk_1.default.dim(message);
25
+ },
26
+ onToolStart: (tool, args) => {
27
+ spinner.text = chalk_1.default.yellow(`🔧 ${tool}`);
28
+ },
29
+ onToolResult: (tool, success) => {
30
+ if (success) {
31
+ spinner.text = chalk_1.default.green(`✅ ${tool}`);
32
+ }
33
+ else {
34
+ spinner.text = chalk_1.default.red(`❌ ${tool} failed`);
35
+ }
36
+ }
37
+ });
38
+ spinner.stop();
39
+ if (options.json) {
40
+ console.log(JSON.stringify(response, null, 2));
41
+ }
42
+ else {
43
+ console.log('\n' + formatResponse(response) + '\n');
44
+ }
45
+ }
46
+ catch (error) {
47
+ spinner.fail(chalk_1.default.red('Error'));
48
+ if (options.json) {
49
+ console.log(JSON.stringify({ error: error.message }, null, 2));
50
+ }
51
+ else {
52
+ console.log(chalk_1.default.red(` ${error.message}\n`));
53
+ }
54
+ process.exit(1);
55
+ }
56
+ }
57
+ function formatResponse(response) {
58
+ let output = '';
59
+ // Main answer
60
+ if (response.answer) {
61
+ output += chalk_1.default.white(response.answer);
62
+ }
63
+ // Show tools used
64
+ if (response.toolsUsed && response.toolsUsed.length > 0) {
65
+ output += chalk_1.default.dim(`\n\n📊 Tools: ${response.toolsUsed.join(', ')}`);
66
+ }
67
+ // Show timing
68
+ if (response.totalTime) {
69
+ output += chalk_1.default.dim(` | ${response.totalTime}ms`);
70
+ }
71
+ return output;
72
+ }
73
+ exports.default = queryCommand;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Watch Command - Real-time price monitoring
3
+ */
4
+ export declare function watchCommand(symbols: string, interval?: number): Promise<void>;
5
+ export default watchCommand;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * Watch Command - Real-time price monitoring
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.watchCommand = watchCommand;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const cli_table3_1 = __importDefault(require("cli-table3"));
12
+ const client_1 = require("../api/client");
13
+ const manager_1 = require("../config/manager");
14
+ async function watchCommand(symbols, interval = 5) {
15
+ const symbolList = symbols.toUpperCase().split(',').map(s => s.trim());
16
+ console.log(chalk_1.default.bold.cyan('\n📈 ENTON Watch Mode\n'));
17
+ console.log(chalk_1.default.dim(`Watching: ${symbolList.join(', ')}`));
18
+ console.log(chalk_1.default.dim(`Refresh: Every ${interval} seconds\n`));
19
+ console.log(chalk_1.default.dim('Press Ctrl+C to exit\n'));
20
+ const config = (0, manager_1.getConfig)();
21
+ const client = new client_1.EntonAPIClient(config.apiUrl, config.apiKey);
22
+ const priceData = new Map();
23
+ // Initial fetch
24
+ await fetchPrices(symbolList, client, priceData);
25
+ displayPrices(priceData);
26
+ // Set up refresh interval
27
+ const intervalId = setInterval(async () => {
28
+ await fetchPrices(symbolList, client, priceData);
29
+ displayPrices(priceData);
30
+ }, interval * 1000);
31
+ // Handle exit
32
+ process.on('SIGINT', () => {
33
+ clearInterval(intervalId);
34
+ console.log(chalk_1.default.dim('\n\nExiting watch mode...\n'));
35
+ process.exit(0);
36
+ });
37
+ }
38
+ async function fetchPrices(symbols, client, priceData) {
39
+ for (const symbol of symbols) {
40
+ try {
41
+ const response = await client.query(`price of ${symbol}`, { stream: false });
42
+ // Parse the response (this is a simplified parser)
43
+ const priceMatch = response.answer.match(/\$?([\d,]+\.?\d*)/);
44
+ const changeMatch = response.answer.match(/(up|down)\s+([\d.]+)%/i);
45
+ if (priceMatch) {
46
+ const price = parseFloat(priceMatch[1].replace(',', ''));
47
+ const isDown = changeMatch?.[1]?.toLowerCase() === 'down';
48
+ const changePercent = changeMatch ? parseFloat(changeMatch[2]) * (isDown ? -1 : 1) : 0;
49
+ const existing = priceData.get(symbol);
50
+ const previousClose = existing?.previousClose || price / (1 + changePercent / 100);
51
+ const change = price - previousClose;
52
+ priceData.set(symbol, {
53
+ symbol,
54
+ price,
55
+ change,
56
+ changePercent,
57
+ previousClose,
58
+ lastUpdated: new Date()
59
+ });
60
+ }
61
+ }
62
+ catch (error) {
63
+ // Keep previous data on error
64
+ console.error(chalk_1.default.dim(`Error fetching ${symbol}`));
65
+ }
66
+ }
67
+ }
68
+ function displayPrices(priceData) {
69
+ // Clear screen and move cursor to top
70
+ console.clear();
71
+ console.log(chalk_1.default.bold.cyan('📈 ENTON Watch Mode'));
72
+ console.log(chalk_1.default.dim(`Last update: ${new Date().toLocaleTimeString()}\n`));
73
+ const table = new cli_table3_1.default({
74
+ head: [
75
+ chalk_1.default.bold('Symbol'),
76
+ chalk_1.default.bold('Price'),
77
+ chalk_1.default.bold('Change'),
78
+ chalk_1.default.bold('% Change')
79
+ ],
80
+ style: {
81
+ head: [],
82
+ border: ['dim']
83
+ }
84
+ });
85
+ for (const [symbol, data] of priceData) {
86
+ const changeColor = data.change >= 0 ? chalk_1.default.green : chalk_1.default.red;
87
+ const arrow = data.change >= 0 ? '▲' : '▼';
88
+ table.push([
89
+ chalk_1.default.bold(symbol),
90
+ `$${data.price.toFixed(2)}`,
91
+ changeColor(`${arrow} $${Math.abs(data.change).toFixed(2)}`),
92
+ changeColor(`${data.changePercent >= 0 ? '+' : ''}${data.changePercent.toFixed(2)}%`)
93
+ ]);
94
+ }
95
+ console.log(table.toString());
96
+ console.log(chalk_1.default.dim('\nPress Ctrl+C to exit'));
97
+ }
98
+ exports.default = watchCommand;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Configuration Manager
3
+ * Simple JSON file-based config storage
4
+ */
5
+ interface EntonConfig {
6
+ apiUrl: string;
7
+ apiKey: string | null;
8
+ defaultAccount?: string;
9
+ outputFormat?: 'text' | 'json';
10
+ theme?: 'light' | 'dark';
11
+ }
12
+ /**
13
+ * Get full config including API key from env
14
+ */
15
+ export declare function getConfig(): EntonConfig;
16
+ /**
17
+ * Get API key
18
+ */
19
+ export declare function getApiKey(): Promise<string | null>;
20
+ /**
21
+ * Save API key
22
+ */
23
+ export declare function saveApiKey(apiKey: string): Promise<void>;
24
+ /**
25
+ * Delete API key
26
+ */
27
+ export declare function deleteApiKey(): Promise<void>;
28
+ /**
29
+ * Set a config value
30
+ */
31
+ export declare function setConfig<K extends keyof EntonConfig>(key: K, value: EntonConfig[K]): void;
32
+ /**
33
+ * Get a config value
34
+ */
35
+ export declare function getConfigValue<K extends keyof EntonConfig>(key: K): EntonConfig[K];
36
+ /**
37
+ * List all config values (without sensitive data)
38
+ */
39
+ export declare function listConfig(): Omit<EntonConfig, 'apiKey'>;
40
+ /**
41
+ * Reset config to defaults
42
+ */
43
+ export declare function resetConfig(): void;
44
+ declare const _default: {
45
+ getConfig: typeof getConfig;
46
+ getApiKey: typeof getApiKey;
47
+ saveApiKey: typeof saveApiKey;
48
+ deleteApiKey: typeof deleteApiKey;
49
+ setConfig: typeof setConfig;
50
+ getConfigValue: typeof getConfigValue;
51
+ listConfig: typeof listConfig;
52
+ resetConfig: typeof resetConfig;
53
+ };
54
+ export default _default;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration Manager
4
+ * Simple JSON file-based config storage
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.getConfig = getConfig;
41
+ exports.getApiKey = getApiKey;
42
+ exports.saveApiKey = saveApiKey;
43
+ exports.deleteApiKey = deleteApiKey;
44
+ exports.setConfig = setConfig;
45
+ exports.getConfigValue = getConfigValue;
46
+ exports.listConfig = listConfig;
47
+ exports.resetConfig = resetConfig;
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const os = __importStar(require("os"));
51
+ const CONFIG_DIR = path.join(os.homedir(), '.enton');
52
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
53
+ const DEFAULT_CONFIG = {
54
+ apiUrl: 'https://enton.ai',
55
+ apiKey: null,
56
+ defaultAccount: undefined,
57
+ outputFormat: 'text',
58
+ theme: 'dark'
59
+ };
60
+ /**
61
+ * Ensure config directory exists
62
+ */
63
+ function ensureConfigDir() {
64
+ if (!fs.existsSync(CONFIG_DIR)) {
65
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
66
+ }
67
+ }
68
+ /**
69
+ * Load config from file
70
+ */
71
+ function loadConfig() {
72
+ ensureConfigDir();
73
+ if (!fs.existsSync(CONFIG_FILE)) {
74
+ return { ...DEFAULT_CONFIG };
75
+ }
76
+ try {
77
+ const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
78
+ return { ...DEFAULT_CONFIG, ...JSON.parse(data) };
79
+ }
80
+ catch {
81
+ return { ...DEFAULT_CONFIG };
82
+ }
83
+ }
84
+ /**
85
+ * Save config to file
86
+ */
87
+ function saveConfig(config) {
88
+ ensureConfigDir();
89
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
90
+ }
91
+ /**
92
+ * Get full config including API key from env
93
+ */
94
+ function getConfig() {
95
+ const config = loadConfig();
96
+ // Environment variable takes precedence
97
+ if (process.env.ENTON_API_KEY) {
98
+ config.apiKey = process.env.ENTON_API_KEY;
99
+ }
100
+ return config;
101
+ }
102
+ /**
103
+ * Get API key
104
+ */
105
+ async function getApiKey() {
106
+ // Try environment variable first
107
+ if (process.env.ENTON_API_KEY) {
108
+ return process.env.ENTON_API_KEY;
109
+ }
110
+ // Then try config file
111
+ const config = loadConfig();
112
+ return config.apiKey;
113
+ }
114
+ /**
115
+ * Save API key
116
+ */
117
+ async function saveApiKey(apiKey) {
118
+ const config = loadConfig();
119
+ config.apiKey = apiKey;
120
+ saveConfig(config);
121
+ }
122
+ /**
123
+ * Delete API key
124
+ */
125
+ async function deleteApiKey() {
126
+ const config = loadConfig();
127
+ config.apiKey = null;
128
+ saveConfig(config);
129
+ }
130
+ /**
131
+ * Set a config value
132
+ */
133
+ function setConfig(key, value) {
134
+ const config = loadConfig();
135
+ config[key] = value;
136
+ saveConfig(config);
137
+ }
138
+ /**
139
+ * Get a config value
140
+ */
141
+ function getConfigValue(key) {
142
+ const config = loadConfig();
143
+ return config[key];
144
+ }
145
+ /**
146
+ * List all config values (without sensitive data)
147
+ */
148
+ function listConfig() {
149
+ const config = loadConfig();
150
+ const { apiKey, ...rest } = config;
151
+ return rest;
152
+ }
153
+ /**
154
+ * Reset config to defaults
155
+ */
156
+ function resetConfig() {
157
+ saveConfig({ ...DEFAULT_CONFIG });
158
+ }
159
+ exports.default = {
160
+ getConfig,
161
+ getApiKey,
162
+ saveApiKey,
163
+ deleteApiKey,
164
+ setConfig,
165
+ getConfigValue,
166
+ listConfig,
167
+ resetConfig
168
+ };
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ENTON CLI - AI-powered financial assistant
4
+ *
5
+ * Usage:
6
+ * enton # Interactive mode
7
+ * enton "query" # Direct query mode
8
+ * enton auth login # Authenticate with ENTON
9
+ * enton watch AAPL,TSLA # Watch mode for real-time prices
10
+ */
11
+ export {};