autoscholar-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,307 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runTuring = runTuring;
7
+ const ora_1 = __importDefault(require("ora"));
8
+ const llm_1 = require("../utils/llm");
9
+ const fmp_1 = require("../connectors/fmp");
10
+ const eodhd_1 = require("../connectors/eodhd");
11
+ const fred_1 = require("../connectors/fred");
12
+ const websearch_1 = require("../connectors/websearch");
13
+ const banner_1 = require("../cli/banner");
14
+ const project_1 = require("../utils/project");
15
+ async function runTuring(topic, assets, method, highFrequency, projectId, config, logger, gapAnalysis) {
16
+ const spinner = (0, ora_1.default)({ text: 'Turing: Planning data collection...', indent: 2 }).start();
17
+ logger.info(`[TURING] Starting data collection for: ${topic}`);
18
+ const datasets = [];
19
+ const errors = [];
20
+ const sources = [];
21
+ spinner.text = 'Turing: Designing data collection strategy...';
22
+ const plan = await planDataCollection(topic, assets, method, config, gapAnalysis);
23
+ logger.info(`[TURING] Data plan: ${JSON.stringify(plan)}`);
24
+ for (const task of plan.tasks) {
25
+ spinner.text = `Turing: Collecting ${task.description}...`;
26
+ try {
27
+ const result = await executeDataTask(task, projectId, config, highFrequency);
28
+ if (result) {
29
+ datasets.push(result);
30
+ sources.push(task.source);
31
+ (0, banner_1.printSuccess)(`${task.source}: ${result.description} (${result.rows} rows)`);
32
+ logger.info(`[TURING] Collected: ${result.filename} — ${result.rows} rows`);
33
+ }
34
+ }
35
+ catch (err) {
36
+ const errMsg = `${task.source}: ${err.message || 'Unknown error'}`;
37
+ errors.push(errMsg);
38
+ (0, banner_1.printWarning)(errMsg);
39
+ logger.warn(`[TURING] Failed: ${errMsg}`);
40
+ }
41
+ }
42
+ spinner.stop();
43
+ const totalRows = datasets.reduce((sum, d) => sum + d.rows, 0);
44
+ if (datasets.length === 0) {
45
+ (0, banner_1.printError)('No data collected. Check API keys and connectivity.');
46
+ return { success: false, datasets: [], totalRows: 0, sources: [], errors };
47
+ }
48
+ (0, banner_1.printSuccess)(`Data collection complete: ${datasets.length} datasets, ${totalRows.toLocaleString()} total rows`);
49
+ logger.info(`[TURING] Complete — ${datasets.length} datasets, ${totalRows} rows`);
50
+ return {
51
+ success: true,
52
+ datasets,
53
+ totalRows,
54
+ sources: [...new Set(sources)],
55
+ errors,
56
+ };
57
+ }
58
+ async function planDataCollection(topic, assets, method, config, gapAnalysis) {
59
+ const availableSources = [];
60
+ if (config.FMP_API_KEY)
61
+ availableSources.push('FMP (Financial Modeling Prep — stocks, fundamentals, ratios, SEC filings)');
62
+ if (config.EODHD_API_KEY)
63
+ availableSources.push('EODHD (historical prices, intraday, options)');
64
+ if (config.FRED_API_KEY)
65
+ availableSources.push('FRED (840K+ macroeconomic series)');
66
+ availableSources.push('World Bank (development indicators, free)');
67
+ availableSources.push('IMF (global economic data, free)');
68
+ const gapContext = gapAnalysis
69
+ ? `\nResearch gap: ${gapAnalysis.recommendedGap?.title || 'N/A'}\nSuggested approach: ${gapAnalysis.recommendedGap?.suggestedApproach || 'N/A'}\nDominant methods: ${gapAnalysis.scientificLandscape?.dominantMethods?.join(', ') || 'N/A'}`
70
+ : '';
71
+ const response = await (0, llm_1.callLLM)(config, `You are Turing, the data collection agent of AutoScholar. Plan data collection tasks.
72
+
73
+ Available data sources:
74
+ ${availableSources.map((s) => `- ${s}`).join('\n')}
75
+
76
+ Rules:
77
+ - Only use sources that are available
78
+ - For FMP: use symbols like AAPL, MSFT, BTC-USD
79
+ - For EODHD: use tickers like AAPL.US, MSFT.US
80
+ - For FRED: use series IDs like GDP, CPIAUCSL, FEDFUNDS, VIXCLS, SP500
81
+ - For World Bank: use indicator codes like NY.GDP.MKTP.CD, FP.CPI.TOTL.ZG
82
+ - Plan 3-8 data collection tasks
83
+ - Cover both the main variables and control variables
84
+ - Include date ranges (YYYY-MM-DD format)
85
+
86
+ Respond as JSON:
87
+ {
88
+ "tasks": [
89
+ {
90
+ "source": "FMP|EODHD|FRED|WorldBank|IMF",
91
+ "type": "prices|fundamentals|macro|indicators",
92
+ "description": "What this data is",
93
+ "params": {
94
+ "symbols": ["AAPL", "MSFT"],
95
+ "seriesIds": ["GDP"],
96
+ "indicators": ["NY.GDP.MKTP.CD"],
97
+ "fromDate": "2015-01-01",
98
+ "toDate": "2025-01-01",
99
+ "period": "annual|quarterly|daily",
100
+ "country": "US"
101
+ }
102
+ }
103
+ ]
104
+ }`, `Topic: ${topic}\nAssets: ${assets || 'auto-detect'}\nMethod: ${method || 'auto-detect'}${gapContext}`, { maxTokens: 4096 });
105
+ const parsed = (0, llm_1.parseJsonResponse)(response);
106
+ if (parsed?.tasks && Array.isArray(parsed.tasks)) {
107
+ return parsed;
108
+ }
109
+ const tasks = [];
110
+ if (config.FRED_API_KEY) {
111
+ tasks.push({
112
+ source: 'FRED',
113
+ type: 'macro',
114
+ description: 'GDP and inflation data',
115
+ params: { seriesIds: ['GDP', 'CPIAUCSL', 'FEDFUNDS'], fromDate: '2000-01-01', toDate: '2025-01-01' },
116
+ });
117
+ }
118
+ if (config.FMP_API_KEY && assets) {
119
+ const symbols = assets.split(',').map((s) => s.trim());
120
+ tasks.push({
121
+ source: 'FMP',
122
+ type: 'prices',
123
+ description: `Historical prices for ${symbols.join(', ')}`,
124
+ params: { symbols, fromDate: '2015-01-01', toDate: '2025-01-01' },
125
+ });
126
+ }
127
+ return { tasks };
128
+ }
129
+ async function executeDataTask(task, projectId, config, highFrequency) {
130
+ switch (task.source) {
131
+ case 'FMP':
132
+ return executeFMPTask(task, projectId, config);
133
+ case 'EODHD':
134
+ return executeEODHDTask(task, projectId, config, highFrequency);
135
+ case 'FRED':
136
+ return executeFREDTask(task, projectId, config);
137
+ case 'WorldBank':
138
+ return executeWorldBankTask(task, projectId);
139
+ default:
140
+ return null;
141
+ }
142
+ }
143
+ async function executeFMPTask(task, projectId, config) {
144
+ if (!config.FMP_API_KEY)
145
+ return null;
146
+ const fmp = new fmp_1.FMPClient(config.FMP_API_KEY);
147
+ const symbols = task.params.symbols || [];
148
+ if (task.type === 'prices') {
149
+ const allData = [];
150
+ for (const symbol of symbols) {
151
+ try {
152
+ const data = await fmp.getHistoricalPrices(symbol, task.params.fromDate, task.params.toDate);
153
+ const historical = Array.isArray(data) ? data : data?.historical || [];
154
+ for (const row of historical) {
155
+ allData.push({ symbol, ...row });
156
+ }
157
+ }
158
+ catch { }
159
+ }
160
+ if (allData.length === 0)
161
+ return null;
162
+ const csv = arrayToCSV(allData);
163
+ const filename = 'fmp_prices.csv';
164
+ const filePath = (0, project_1.saveProjectFile)(projectId, `data/${filename}`, csv);
165
+ return {
166
+ filename, source: 'FMP', description: `Historical prices for ${symbols.join(', ')}`,
167
+ rows: allData.length, columns: Object.keys(allData[0] || {}),
168
+ dateRange: `${task.params.fromDate} to ${task.params.toDate}`, filePath,
169
+ };
170
+ }
171
+ if (task.type === 'fundamentals') {
172
+ const allData = [];
173
+ for (const symbol of symbols) {
174
+ try {
175
+ const data = await fmp.getIncomeStatement(symbol, task.params.period || 'annual', 20);
176
+ for (const row of (Array.isArray(data) ? data : [])) {
177
+ allData.push({ symbol, ...row });
178
+ }
179
+ }
180
+ catch { }
181
+ }
182
+ if (allData.length === 0)
183
+ return null;
184
+ const csv = arrayToCSV(allData);
185
+ const filename = 'fmp_fundamentals.csv';
186
+ const filePath = (0, project_1.saveProjectFile)(projectId, `data/${filename}`, csv);
187
+ return {
188
+ filename, source: 'FMP', description: `Fundamentals for ${symbols.join(', ')}`,
189
+ rows: allData.length, columns: Object.keys(allData[0] || {}), filePath,
190
+ };
191
+ }
192
+ return null;
193
+ }
194
+ async function executeEODHDTask(task, projectId, config, hf) {
195
+ if (!config.EODHD_API_KEY)
196
+ return null;
197
+ const eodhd = new eodhd_1.EODHDClient(config.EODHD_API_KEY);
198
+ const symbols = task.params.symbols || [];
199
+ const allData = [];
200
+ for (const symbol of symbols) {
201
+ try {
202
+ if (hf) {
203
+ const data = await eodhd.getIntraday(symbol, '1h', task.params.fromDate, task.params.toDate);
204
+ for (const row of data)
205
+ allData.push({ symbol, ...row });
206
+ }
207
+ else {
208
+ const data = await eodhd.getEOD(symbol, task.params.fromDate, task.params.toDate);
209
+ for (const row of data)
210
+ allData.push({ symbol, ...row });
211
+ }
212
+ }
213
+ catch { }
214
+ }
215
+ if (allData.length === 0)
216
+ return null;
217
+ const csv = arrayToCSV(allData);
218
+ const filename = hf ? 'eodhd_intraday.csv' : 'eodhd_eod.csv';
219
+ const filePath = (0, project_1.saveProjectFile)(projectId, `data/${filename}`, csv);
220
+ return {
221
+ filename, source: 'EODHD',
222
+ description: `${hf ? 'Intraday' : 'Daily'} prices for ${symbols.join(', ')}`,
223
+ rows: allData.length, columns: Object.keys(allData[0] || {}),
224
+ dateRange: `${task.params.fromDate} to ${task.params.toDate}`, filePath,
225
+ };
226
+ }
227
+ async function executeFREDTask(task, projectId, config) {
228
+ if (!config.FRED_API_KEY)
229
+ return null;
230
+ const fred = new fred_1.FREDClient(config.FRED_API_KEY);
231
+ const seriesIds = task.params.seriesIds || [];
232
+ const allData = [];
233
+ for (const seriesId of seriesIds) {
234
+ try {
235
+ const observations = await fred.getObservations(seriesId, {
236
+ observationStart: task.params.fromDate,
237
+ observationEnd: task.params.toDate,
238
+ });
239
+ for (const obs of observations) {
240
+ if (obs.value !== '.') {
241
+ allData.push({ series_id: seriesId, date: obs.date, value: obs.value });
242
+ }
243
+ }
244
+ }
245
+ catch { }
246
+ }
247
+ if (allData.length === 0)
248
+ return null;
249
+ const csv = arrayToCSV(allData);
250
+ const filename = 'fred_macro.csv';
251
+ const filePath = (0, project_1.saveProjectFile)(projectId, `data/${filename}`, csv);
252
+ return {
253
+ filename, source: 'FRED',
254
+ description: `Macroeconomic data: ${seriesIds.join(', ')}`,
255
+ rows: allData.length, columns: ['series_id', 'date', 'value'],
256
+ dateRange: `${task.params.fromDate} to ${task.params.toDate}`, filePath,
257
+ };
258
+ }
259
+ async function executeWorldBankTask(task, projectId) {
260
+ const indicators = task.params.indicators || [];
261
+ const country = task.params.country || 'all';
262
+ const allData = [];
263
+ for (const indicator of indicators) {
264
+ try {
265
+ const data = await (0, websearch_1.searchWorldBank)(indicator, country, {
266
+ dateRange: `${task.params.fromDate?.substring(0, 4) || '2000'}:${task.params.toDate?.substring(0, 4) || '2025'}`,
267
+ });
268
+ for (const row of data) {
269
+ if (row.value !== null) {
270
+ allData.push({
271
+ indicator: row.indicator?.id || indicator,
272
+ country: row.country?.value || country,
273
+ date: row.date,
274
+ value: row.value,
275
+ });
276
+ }
277
+ }
278
+ }
279
+ catch { }
280
+ }
281
+ if (allData.length === 0)
282
+ return null;
283
+ const csv = arrayToCSV(allData);
284
+ const filename = 'worldbank_data.csv';
285
+ const filePath = (0, project_1.saveProjectFile)(projectId, `data/${filename}`, csv);
286
+ return {
287
+ filename, source: 'World Bank',
288
+ description: `Development indicators: ${indicators.join(', ')}`,
289
+ rows: allData.length, columns: ['indicator', 'country', 'date', 'value'], filePath,
290
+ };
291
+ }
292
+ function arrayToCSV(data) {
293
+ if (data.length === 0)
294
+ return '';
295
+ const headers = Object.keys(data[0]);
296
+ const rows = data.map((row) => headers.map((h) => {
297
+ const val = row[h];
298
+ if (val === null || val === undefined)
299
+ return '';
300
+ const str = String(val);
301
+ if (str.includes(',') || str.includes('"') || str.includes('\n')) {
302
+ return `"${str.replace(/"/g, '""')}"`;
303
+ }
304
+ return str;
305
+ }).join(','));
306
+ return [headers.join(','), ...rows].join('\n');
307
+ }
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.showBanner = showBanner;
7
+ exports.showWelcome = showWelcome;
8
+ exports.printSection = printSection;
9
+ exports.printSuccess = printSuccess;
10
+ exports.printError = printError;
11
+ exports.printWarning = printWarning;
12
+ exports.printInfo = printInfo;
13
+ exports.printStep = printStep;
14
+ exports.printStageHeader = printStageHeader;
15
+ exports.printSummaryBox = printSummaryBox;
16
+ exports.printKV = printKV;
17
+ const chalk_1 = __importDefault(require("chalk"));
18
+ const boxen_1 = __importDefault(require("boxen"));
19
+ const LOGO_LINES = [
20
+ ' _ _ ____ _ _ ',
21
+ ' / \\ _ _| |_ ___ / ___| ___| |__ ___ | | __ _ _ __ ',
22
+ ' / _ \\| | | | __/ _ \\ \\___ \\ / __| \'_ \\ / _ \\| |/ _` | \'__|',
23
+ ' / ___ \\ |_| | || (_) | ___) | (__| | | | (_) | | (_| | | ',
24
+ ' /_/ \\_\\__,_|\\__\\___/ |____/ \\___|_| |_|\\___/|_|\\__,_|_| ',
25
+ ];
26
+ const TAGLINE = 'Autonomous Scientific Research Agent';
27
+ const VERSION = '1.0.0';
28
+ const GRADIENT = [
29
+ '#0EA5E9',
30
+ '#06B6D4',
31
+ '#14B8A6',
32
+ '#0EA5E9',
33
+ '#0284C7',
34
+ ];
35
+ function applyGradient(lines) {
36
+ return lines.map((line, i) => {
37
+ const color = GRADIENT[i % GRADIENT.length];
38
+ return chalk_1.default.hex(color).bold(line);
39
+ }).join('\n');
40
+ }
41
+ function charGradient(text, from, to) {
42
+ const r1 = parseInt(from.slice(1, 3), 16);
43
+ const g1 = parseInt(from.slice(3, 5), 16);
44
+ const b1 = parseInt(from.slice(5, 7), 16);
45
+ const r2 = parseInt(to.slice(1, 3), 16);
46
+ const g2 = parseInt(to.slice(3, 5), 16);
47
+ const b2 = parseInt(to.slice(5, 7), 16);
48
+ const len = text.length || 1;
49
+ return text.split('').map((ch, i) => {
50
+ const t = i / len;
51
+ const r = Math.round(r1 + (r2 - r1) * t);
52
+ const g = Math.round(g1 + (g2 - g1) * t);
53
+ const b = Math.round(b1 + (b2 - b1) * t);
54
+ return chalk_1.default.rgb(r, g, b)(ch);
55
+ }).join('');
56
+ }
57
+ function showBanner() {
58
+ console.log();
59
+ console.log(applyGradient(LOGO_LINES));
60
+ console.log();
61
+ const tagline = charGradient(` ${TAGLINE}`, '#06B6D4', '#8B5CF6');
62
+ console.log(tagline + chalk_1.default.dim.hex('#64748B')(` v${VERSION}`));
63
+ const bar = chalk_1.default.hex('#1E293B')(' ' + '━'.repeat(58));
64
+ console.log(bar);
65
+ console.log();
66
+ }
67
+ function showWelcome() {
68
+ const box = (0, boxen_1.default)(chalk_1.default.white.bold('Welcome to AutoScholar') + '\n' +
69
+ chalk_1.default.hex('#94A3B8')('A quant researcher + economist + data scientist') + '\n' +
70
+ chalk_1.default.hex('#94A3B8')('living inside your terminal.'), {
71
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
72
+ margin: { top: 0, bottom: 1, left: 1, right: 0 },
73
+ borderStyle: 'round',
74
+ borderColor: '#0EA5E9',
75
+ });
76
+ console.log(box);
77
+ }
78
+ function printSection(title) {
79
+ console.log();
80
+ const icon = SECTION_ICONS[title.toLowerCase()] || '>';
81
+ const header = chalk_1.default.hex('#0EA5E9').bold(` ${icon} ${title}`);
82
+ const line = chalk_1.default.hex('#1E293B')(' ' + '─'.repeat(56));
83
+ console.log(header);
84
+ console.log(line);
85
+ }
86
+ const SECTION_ICONS = {
87
+ 'pre-flight checks': '\u25C6',
88
+ 'euler: research pipeline': '\u25B6',
89
+ 'pipeline complete': '\u2605',
90
+ 'new research paper': '\u270E',
91
+ 'configuration management': '\u2699',
92
+ 'research outputs': '\u25A0',
93
+ 'autoscholar setup wizard': '\u26A1',
94
+ 'validating api keys': '\u2713',
95
+ };
96
+ function printSuccess(msg) {
97
+ console.log(chalk_1.default.hex('#22C55E')(` \u2714 ${msg}`));
98
+ }
99
+ function printError(msg) {
100
+ console.log(chalk_1.default.hex('#EF4444')(` \u2718 ${msg}`));
101
+ }
102
+ function printWarning(msg) {
103
+ console.log(chalk_1.default.hex('#F59E0B')(` \u26A0 ${msg}`));
104
+ }
105
+ function printInfo(msg) {
106
+ console.log(chalk_1.default.hex('#60A5FA')(` \u2139 ${msg}`));
107
+ }
108
+ function printStep(step, total, msg) {
109
+ const filled = Math.round((step / total) * 20);
110
+ const empty = 20 - filled;
111
+ const bar = chalk_1.default.hex('#0EA5E9')('\u2588'.repeat(filled)) + chalk_1.default.hex('#1E293B')('\u2591'.repeat(empty));
112
+ const pct = Math.round((step / total) * 100);
113
+ console.log(` ${bar} ${chalk_1.default.hex('#94A3B8')(`${pct}%`)} ${chalk_1.default.white.bold(msg)}`);
114
+ }
115
+ function printStageHeader(name, icon) {
116
+ console.log();
117
+ console.log(chalk_1.default.hex('#0EA5E9')(` ${icon} `) + chalk_1.default.white.bold(name));
118
+ console.log(chalk_1.default.hex('#1E293B')(' ' + '\u2500'.repeat(50)));
119
+ }
120
+ function printSummaryBox(lines, success) {
121
+ const borderColor = success ? '#22C55E' : '#F59E0B';
122
+ const title = success ? ' Research Complete ' : ' Pipeline Finished ';
123
+ const content = lines.join('\n');
124
+ const box = (0, boxen_1.default)(content, {
125
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
126
+ margin: { top: 1, bottom: 1, left: 1, right: 0 },
127
+ borderStyle: 'double',
128
+ borderColor,
129
+ title,
130
+ titleAlignment: 'center',
131
+ });
132
+ console.log(box);
133
+ }
134
+ function printKV(key, value) {
135
+ console.log(` ${chalk_1.default.hex('#94A3B8')(key.padEnd(14))} ${chalk_1.default.white(value)}`);
136
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.manageConfig = manageConfig;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const loader_1 = require("../config/loader");
10
+ const setup_1 = require("../config/setup");
11
+ const banner_1 = require("./banner");
12
+ async function manageConfig() {
13
+ (0, banner_1.printSection)('Configuration Management');
14
+ if (!(0, loader_1.envExists)()) {
15
+ console.log(chalk_1.default.yellow(' No configuration found.\n'));
16
+ await (0, setup_1.runSetupWizard)();
17
+ return;
18
+ }
19
+ const { action } = await inquirer_1.default.prompt([
20
+ {
21
+ type: 'list',
22
+ name: 'action',
23
+ message: 'Configuration options:',
24
+ prefix: ' ⚙️',
25
+ choices: [
26
+ { name: 'View current keys (masked)', value: 'view' },
27
+ { name: 'Edit a key', value: 'edit' },
28
+ { name: 'Validate all keys', value: 'validate' },
29
+ { name: 'Re-run setup wizard', value: 'reset' },
30
+ { name: 'Back', value: 'back' },
31
+ ],
32
+ },
33
+ ]);
34
+ switch (action) {
35
+ case 'view':
36
+ await viewConfig();
37
+ break;
38
+ case 'edit':
39
+ await editKey();
40
+ break;
41
+ case 'validate':
42
+ await validateKeys();
43
+ break;
44
+ case 'reset':
45
+ await (0, setup_1.runSetupWizard)();
46
+ break;
47
+ case 'back':
48
+ break;
49
+ }
50
+ }
51
+ async function viewConfig() {
52
+ const config = (0, loader_1.loadConfig)();
53
+ if (!config) {
54
+ (0, banner_1.printError)('No configuration found');
55
+ return;
56
+ }
57
+ console.log();
58
+ const entries = Object.entries(config);
59
+ for (const [key, value] of entries) {
60
+ const val = value;
61
+ if (val && val.length > 0) {
62
+ const masked = val.substring(0, 4) + '•'.repeat(Math.max(0, val.length - 8)) + val.substring(val.length - 4);
63
+ (0, banner_1.printSuccess)(`${key}: ${chalk_1.default.dim(masked)}`);
64
+ }
65
+ else {
66
+ console.log(chalk_1.default.dim(` ○ ${key}: not set`));
67
+ }
68
+ }
69
+ console.log();
70
+ }
71
+ async function editKey() {
72
+ const config = (0, loader_1.loadConfig)();
73
+ if (!config)
74
+ return;
75
+ const keys = Object.keys(config);
76
+ const { keyToEdit } = await inquirer_1.default.prompt([
77
+ {
78
+ type: 'list',
79
+ name: 'keyToEdit',
80
+ message: 'Select key to edit:',
81
+ choices: keys.map((k) => ({
82
+ name: `${k} ${config[k] ? chalk_1.default.green('(set)') : chalk_1.default.dim('(empty)')}`,
83
+ value: k,
84
+ })),
85
+ },
86
+ ]);
87
+ const { newValue } = await inquirer_1.default.prompt([
88
+ {
89
+ type: 'password',
90
+ name: 'newValue',
91
+ message: `New value for ${keyToEdit}:`,
92
+ mask: '*',
93
+ },
94
+ ]);
95
+ const envValues = {};
96
+ for (const [k, v] of Object.entries(config)) {
97
+ if (v)
98
+ envValues[k] = v;
99
+ }
100
+ if (newValue && newValue.trim()) {
101
+ envValues[keyToEdit] = newValue.trim();
102
+ }
103
+ else {
104
+ delete envValues[keyToEdit];
105
+ }
106
+ (0, loader_1.saveEnvFile)(envValues);
107
+ (0, banner_1.printSuccess)(`${keyToEdit} updated`);
108
+ }
109
+ async function validateKeys() {
110
+ const config = (0, loader_1.loadConfig)();
111
+ if (!config)
112
+ return;
113
+ const validation = (0, loader_1.validateConfig)(config);
114
+ if (validation.valid && validation.warnings.length === 0) {
115
+ (0, banner_1.printSuccess)('All required keys are configured');
116
+ }
117
+ else {
118
+ for (const err of validation.errors) {
119
+ (0, banner_1.printError)(err);
120
+ }
121
+ for (const warn of validation.warnings) {
122
+ (0, banner_1.printWarning)(warn);
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runInteractiveMode = runInteractiveMode;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const runCommand_1 = require("./runCommand");
10
+ const configCommand_1 = require("./configCommand");
11
+ const outputsCommand_1 = require("./outputsCommand");
12
+ const banner_1 = require("./banner");
13
+ async function runInteractiveMode(config) {
14
+ let running = true;
15
+ while (running) {
16
+ const { choice } = await inquirer_1.default.prompt([
17
+ {
18
+ type: 'list',
19
+ name: 'choice',
20
+ message: chalk_1.default.white.bold('What would you like to do?'),
21
+ choices: [
22
+ new inquirer_1.default.Separator(chalk_1.default.hex('#1E293B')(' ──────────────────────────────')),
23
+ { name: `${chalk_1.default.hex('#0EA5E9').bold('New Research Paper')} ${chalk_1.default.hex('#64748B')('Generate a full paper from scratch')}`, value: 'new' },
24
+ { name: `${chalk_1.default.hex('#06B6D4').bold('Load Existing Project')} ${chalk_1.default.hex('#64748B')('Resume or inspect a project')}`, value: 'load' },
25
+ { name: `${chalk_1.default.hex('#14B8A6').bold('Configure APIs')} ${chalk_1.default.hex('#64748B')('Manage API keys and settings')}`, value: 'config' },
26
+ { name: `${chalk_1.default.hex('#8B5CF6').bold('View Outputs')} ${chalk_1.default.hex('#64748B')('Browse generated papers')}`, value: 'outputs' },
27
+ new inquirer_1.default.Separator(chalk_1.default.hex('#1E293B')(' ──────────────────────────────')),
28
+ { name: `${chalk_1.default.hex('#64748B')('Exit')}`, value: 'exit' },
29
+ ],
30
+ prefix: chalk_1.default.hex('#0EA5E9')('\u25C6'),
31
+ pageSize: 10,
32
+ },
33
+ ]);
34
+ switch (choice) {
35
+ case 'new':
36
+ await startNewResearch(config);
37
+ break;
38
+ case 'load':
39
+ await (0, outputsCommand_1.listOutputs)();
40
+ break;
41
+ case 'config':
42
+ await (0, configCommand_1.manageConfig)();
43
+ break;
44
+ case 'outputs':
45
+ await (0, outputsCommand_1.listOutputs)();
46
+ break;
47
+ case 'exit':
48
+ console.log();
49
+ console.log(chalk_1.default.hex('#64748B')(' Until next time. Happy researching.'));
50
+ console.log();
51
+ running = false;
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ async function startNewResearch(config) {
57
+ (0, banner_1.printSection)('New Research Paper');
58
+ console.log();
59
+ const answers = await inquirer_1.default.prompt([
60
+ {
61
+ type: 'input',
62
+ name: 'topic',
63
+ message: chalk_1.default.white('Research topic:'),
64
+ prefix: chalk_1.default.hex('#0EA5E9')('\u25B8'),
65
+ validate: (input) => input.trim().length > 0 || 'Topic is required',
66
+ },
67
+ {
68
+ type: 'input',
69
+ name: 'assets',
70
+ message: chalk_1.default.white('Assets / variables') + chalk_1.default.hex('#64748B')(' (comma-separated, optional)') + chalk_1.default.white(':'),
71
+ prefix: chalk_1.default.hex('#06B6D4')('\u25B8'),
72
+ default: '',
73
+ },
74
+ {
75
+ type: 'list',
76
+ name: 'methodology',
77
+ message: chalk_1.default.white('Preferred methodology:'),
78
+ prefix: chalk_1.default.hex('#14B8A6')('\u25B8'),
79
+ choices: [
80
+ { name: `${chalk_1.default.white('Auto-detect')} ${chalk_1.default.hex('#64748B')('Let Euler decide the best approach')}`, value: 'auto' },
81
+ { name: `${chalk_1.default.white('Econometrics')} ${chalk_1.default.hex('#64748B')('OLS, IV, GMM, Panel FE/RE')}`, value: 'econometrics' },
82
+ { name: `${chalk_1.default.white('Time Series')} ${chalk_1.default.hex('#64748B')('VAR, GARCH, DCC, VECM')}`, value: 'timeseries' },
83
+ { name: `${chalk_1.default.white('Machine Learning')} ${chalk_1.default.hex('#64748B')('RandomForest, XGBoost, SHAP')}`, value: 'ml' },
84
+ { name: `${chalk_1.default.white('Statistics')} ${chalk_1.default.hex('#64748B')('Hypothesis testing, ANOVA')}`, value: 'statistics' },
85
+ { name: `${chalk_1.default.white('Custom')} ${chalk_1.default.hex('#64748B')('Specify in topic description')}`, value: 'custom' },
86
+ ],
87
+ },
88
+ {
89
+ type: 'confirm',
90
+ name: 'highFrequency',
91
+ message: chalk_1.default.white('Use high-frequency (intraday) data?'),
92
+ prefix: chalk_1.default.hex('#8B5CF6')('\u25B8'),
93
+ default: false,
94
+ },
95
+ {
96
+ type: 'confirm',
97
+ name: 'dryRun',
98
+ message: chalk_1.default.white('Dry run') + chalk_1.default.hex('#64748B')(' (show plan only)') + chalk_1.default.white('?'),
99
+ prefix: chalk_1.default.hex('#64748B')('\u25B8'),
100
+ default: false,
101
+ },
102
+ ]);
103
+ const opts = {
104
+ topic: answers.topic,
105
+ dry: answers.dryRun,
106
+ hf: answers.highFrequency,
107
+ };
108
+ if (answers.assets) {
109
+ opts.assets = answers.assets;
110
+ }
111
+ if (answers.methodology !== 'auto') {
112
+ opts.method = answers.methodology;
113
+ }
114
+ await (0, runCommand_1.runPipeline)(opts, config);
115
+ }