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,191 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.listOutputs = listOutputs;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const cli_table3_1 = __importDefault(require("cli-table3"));
44
+ const inquirer_1 = __importDefault(require("inquirer"));
45
+ const loader_1 = require("../config/loader");
46
+ const banner_1 = require("./banner");
47
+ async function listOutputs() {
48
+ (0, banner_1.printSection)('Research Outputs');
49
+ const projectsDir = (0, loader_1.getProjectsDir)();
50
+ if (!fs.existsSync(projectsDir)) {
51
+ (0, banner_1.printInfo)('No projects found yet. Run "autoscholar run" to start.');
52
+ return;
53
+ }
54
+ const dirs = fs.readdirSync(projectsDir).filter((d) => {
55
+ return fs.statSync(path.join(projectsDir, d)).isDirectory();
56
+ });
57
+ if (dirs.length === 0) {
58
+ (0, banner_1.printInfo)('No projects found yet. Run "autoscholar run" to start.');
59
+ return;
60
+ }
61
+ const projects = [];
62
+ for (const dir of dirs) {
63
+ const metaPath = path.join(projectsDir, dir, 'meta.json');
64
+ if (fs.existsSync(metaPath)) {
65
+ try {
66
+ const meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
67
+ projects.push({
68
+ id: dir,
69
+ topic: meta.topic || 'Unknown',
70
+ status: meta.status || 'unknown',
71
+ createdAt: meta.createdAt || 'unknown',
72
+ method: meta.method,
73
+ pdfPath: meta.pdfPath,
74
+ figureCount: meta.figureCount,
75
+ });
76
+ }
77
+ catch {
78
+ projects.push({
79
+ id: dir,
80
+ topic: 'Unknown',
81
+ status: 'unknown',
82
+ createdAt: 'unknown',
83
+ });
84
+ }
85
+ }
86
+ }
87
+ projects.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
88
+ const table = new cli_table3_1.default({
89
+ head: [
90
+ chalk_1.default.cyan('ID'),
91
+ chalk_1.default.cyan('Topic'),
92
+ chalk_1.default.cyan('Status'),
93
+ chalk_1.default.cyan('Method'),
94
+ chalk_1.default.cyan('Figures'),
95
+ chalk_1.default.cyan('Date'),
96
+ ],
97
+ colWidths: [14, 40, 12, 16, 9, 12],
98
+ style: { 'padding-left': 1, 'padding-right': 1 },
99
+ });
100
+ for (const p of projects) {
101
+ const statusColor = p.status === 'complete' ? chalk_1.default.green : p.status === 'running' ? chalk_1.default.yellow : chalk_1.default.dim;
102
+ table.push([
103
+ chalk_1.default.dim(p.id.substring(0, 12)),
104
+ p.topic.substring(0, 38),
105
+ statusColor(p.status),
106
+ p.method || chalk_1.default.dim('—'),
107
+ p.figureCount !== undefined ? String(p.figureCount) : chalk_1.default.dim('—'),
108
+ p.createdAt.substring(0, 10),
109
+ ]);
110
+ }
111
+ console.log(table.toString());
112
+ console.log();
113
+ if (projects.length > 0) {
114
+ const { action } = await inquirer_1.default.prompt([
115
+ {
116
+ type: 'list',
117
+ name: 'action',
118
+ message: 'Actions:',
119
+ choices: [
120
+ { name: 'View project details', value: 'view' },
121
+ { name: 'Open PDF', value: 'pdf' },
122
+ { name: 'Back', value: 'back' },
123
+ ],
124
+ },
125
+ ]);
126
+ if (action === 'view' || action === 'pdf') {
127
+ const { projectId } = await inquirer_1.default.prompt([
128
+ {
129
+ type: 'list',
130
+ name: 'projectId',
131
+ message: 'Select project:',
132
+ choices: projects.map((p) => ({
133
+ name: `${p.id.substring(0, 8)} — ${p.topic.substring(0, 50)}`,
134
+ value: p.id,
135
+ })),
136
+ },
137
+ ]);
138
+ if (action === 'view') {
139
+ viewProject(projectId);
140
+ }
141
+ else {
142
+ openPdf(projectId);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ function viewProject(projectId) {
148
+ const projectDir = path.join((0, loader_1.getProjectsDir)(), projectId);
149
+ (0, banner_1.printSection)(`Project: ${projectId}`);
150
+ const showDir = (dir, indent = ' ') => {
151
+ if (!fs.existsSync(dir))
152
+ return;
153
+ const items = fs.readdirSync(dir);
154
+ for (const item of items) {
155
+ const fullPath = path.join(dir, item);
156
+ const stat = fs.statSync(fullPath);
157
+ if (stat.isDirectory()) {
158
+ console.log(chalk_1.default.cyan(`${indent}📁 ${item}/`));
159
+ showDir(fullPath, indent + ' ');
160
+ }
161
+ else {
162
+ const size = (stat.size / 1024).toFixed(1);
163
+ console.log(chalk_1.default.dim(`${indent}📄 ${item} (${size} KB)`));
164
+ }
165
+ }
166
+ };
167
+ showDir(projectDir);
168
+ console.log();
169
+ }
170
+ function openPdf(projectId) {
171
+ const projectDir = path.join((0, loader_1.getProjectsDir)(), projectId);
172
+ const outputDir = path.join(projectDir, 'output');
173
+ if (!fs.existsSync(outputDir)) {
174
+ (0, banner_1.printWarning)('No output directory found');
175
+ return;
176
+ }
177
+ const pdfs = fs.readdirSync(outputDir).filter((f) => f.endsWith('.pdf'));
178
+ if (pdfs.length === 0) {
179
+ (0, banner_1.printWarning)('No PDF files found');
180
+ return;
181
+ }
182
+ const pdfPath = path.join(outputDir, pdfs[0]);
183
+ (0, banner_1.printInfo)(`Opening: ${pdfPath}`);
184
+ const { execSync } = require('child_process');
185
+ try {
186
+ execSync(`open "${pdfPath}"`);
187
+ }
188
+ catch {
189
+ (0, banner_1.printInfo)(`PDF path: ${pdfPath}`);
190
+ }
191
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.resumeProject = resumeProject;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const loader_1 = require("../config/loader");
44
+ const runCommand_1 = require("./runCommand");
45
+ const banner_1 = require("./banner");
46
+ async function resumeProject(projectId, config) {
47
+ (0, banner_1.printSection)(`Resuming Project: ${projectId}`);
48
+ const projectDir = path.join((0, loader_1.getProjectsDir)(), projectId);
49
+ if (!fs.existsSync(projectDir)) {
50
+ (0, banner_1.printError)(`Project not found: ${projectId}`);
51
+ (0, banner_1.printInfo)('Run "autoscholar outputs" to see available projects.');
52
+ return;
53
+ }
54
+ const metaPath = path.join(projectDir, 'meta.json');
55
+ if (!fs.existsSync(metaPath)) {
56
+ (0, banner_1.printError)('Project metadata not found');
57
+ return;
58
+ }
59
+ const meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
60
+ if (meta.status === 'complete') {
61
+ (0, banner_1.printInfo)('This project is already complete.');
62
+ (0, banner_1.printInfo)(`PDF: ${path.join(projectDir, 'output', 'paper.pdf')}`);
63
+ return;
64
+ }
65
+ console.log(chalk_1.default.dim(` Topic: ${meta.topic}`));
66
+ console.log(chalk_1.default.dim(` Status: ${meta.status}`));
67
+ console.log(chalk_1.default.dim(` Last stage: ${meta.lastStage || 'unknown'}`));
68
+ console.log();
69
+ const opts = {
70
+ topic: meta.topic,
71
+ assets: meta.assets,
72
+ method: meta.method,
73
+ hf: meta.highFrequency,
74
+ resumeFrom: meta.lastStage,
75
+ projectId: projectId,
76
+ };
77
+ await (0, runCommand_1.runPipeline)(opts, config);
78
+ }
@@ -0,0 +1,91 @@
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.runPipeline = runPipeline;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const project_1 = require("../utils/project");
10
+ const logger_1 = require("../utils/logger");
11
+ const euler_1 = require("../agents/euler");
12
+ const runner_1 = require("../python/runner");
13
+ const banner_1 = require("./banner");
14
+ async function runPipeline(opts, config) {
15
+ if (!opts.topic) {
16
+ (0, banner_1.printError)('No topic specified. Use --topic or interactive mode.');
17
+ return;
18
+ }
19
+ (0, banner_1.printSection)('Pre-flight Checks');
20
+ console.log();
21
+ const spinner = (0, ora_1.default)({
22
+ text: chalk_1.default.hex('#94A3B8')('Checking Python environment...'),
23
+ indent: 2,
24
+ spinner: 'dots12',
25
+ color: 'cyan',
26
+ }).start();
27
+ const pyCheck = await (0, runner_1.checkPythonDeps)();
28
+ spinner.stop();
29
+ if (!pyCheck.available) {
30
+ (0, banner_1.printError)('Missing required Python packages:');
31
+ for (const pkg of pyCheck.missing) {
32
+ console.log(chalk_1.default.hex('#EF4444')(` \u2022 ${pkg}`));
33
+ }
34
+ console.log();
35
+ (0, banner_1.printInfo)(`Install with: ${chalk_1.default.white.bold(`pip3 install ${pyCheck.missing.join(' ')}`)}`);
36
+ return;
37
+ }
38
+ (0, banner_1.printSuccess)(`Python ${chalk_1.default.hex('#94A3B8')(`(${pyCheck.python})`)} \u2014 ${pyCheck.installed.length} packages ready`);
39
+ (0, banner_1.printSuccess)(`API keys \u2014 ${countActiveKeys(config)} configured`);
40
+ console.log();
41
+ const { meta, dir } = opts.projectId
42
+ ? { meta: { id: opts.projectId, topic: opts.topic }, dir: '' }
43
+ : (0, project_1.createProject)(opts.topic, opts.assets, opts.method, opts.hf);
44
+ const projectId = meta.id;
45
+ const logger = new logger_1.Logger(dir || require('path').join(require('os').homedir(), '.autoscholar', 'projects', projectId));
46
+ (0, banner_1.printKV)('Project', projectId);
47
+ (0, banner_1.printKV)('Output', `~/.autoscholar/projects/${projectId}/`);
48
+ console.log();
49
+ logger.info(`Starting pipeline for: ${opts.topic}`);
50
+ logger.info(`Options: ${JSON.stringify(opts)}`);
51
+ try {
52
+ const result = await (0, euler_1.runEulerPipeline)(opts.topic, projectId, config, logger, {
53
+ assets: opts.assets,
54
+ method: opts.method,
55
+ hf: opts.hf,
56
+ dryRun: opts.dry,
57
+ resumeFrom: opts.resumeFrom,
58
+ });
59
+ if (result.success) {
60
+ const summaryLines = [
61
+ chalk_1.default.hex('#22C55E').bold(`\u2714 Paper generated successfully`),
62
+ '',
63
+ `${chalk_1.default.hex('#94A3B8')('Title')} ${chalk_1.default.white(result.title || opts.topic)}`,
64
+ result.pdfPath ? `${chalk_1.default.hex('#94A3B8')('PDF')} ${chalk_1.default.white(result.pdfPath)}` : '',
65
+ `${chalk_1.default.hex('#94A3B8')('Figures')} ${chalk_1.default.white(String(result.figureCount))}`,
66
+ result.pageCount ? `${chalk_1.default.hex('#94A3B8')('Pages')} ${chalk_1.default.white(String(result.pageCount))}` : '',
67
+ `${chalk_1.default.hex('#94A3B8')('Project')} ${chalk_1.default.hex('#60A5FA')(`~/.autoscholar/projects/${projectId}/`)}`,
68
+ ].filter(Boolean);
69
+ (0, banner_1.printSummaryBox)(summaryLines, true);
70
+ }
71
+ else {
72
+ const summaryLines = [
73
+ chalk_1.default.hex('#F59E0B').bold(`\u26A0 Pipeline completed with issues`),
74
+ '',
75
+ `${chalk_1.default.hex('#94A3B8')('Logs')} ${chalk_1.default.hex('#60A5FA')(`~/.autoscholar/projects/${projectId}/logs/`)}`,
76
+ ];
77
+ (0, banner_1.printSummaryBox)(summaryLines, false);
78
+ }
79
+ }
80
+ catch (err) {
81
+ (0, banner_1.printError)(`Pipeline error: ${err.message}`);
82
+ logger.error(`Fatal: ${err.message}`);
83
+ (0, project_1.updateProject)(projectId, { status: 'failed' });
84
+ }
85
+ finally {
86
+ logger.close();
87
+ }
88
+ }
89
+ function countActiveKeys(config) {
90
+ return Object.values(config).filter((v) => v && String(v).length > 0).length;
91
+ }
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getConfigDir = getConfigDir;
40
+ exports.getEnvPath = getEnvPath;
41
+ exports.getProjectsDir = getProjectsDir;
42
+ exports.ensureDirectories = ensureDirectories;
43
+ exports.envExists = envExists;
44
+ exports.loadConfig = loadConfig;
45
+ exports.validateConfig = validateConfig;
46
+ exports.ensureConfig = ensureConfig;
47
+ exports.saveEnvFile = saveEnvFile;
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const os = __importStar(require("os"));
51
+ const dotenv = __importStar(require("dotenv"));
52
+ const chalk_1 = __importDefault(require("chalk"));
53
+ const setup_1 = require("./setup");
54
+ const banner_1 = require("../cli/banner");
55
+ const CONFIG_DIR = path.join(os.homedir(), '.autoscholar');
56
+ const ENV_PATH = path.join(CONFIG_DIR, '.env');
57
+ const PROJECTS_DIR = path.join(CONFIG_DIR, 'projects');
58
+ function getConfigDir() {
59
+ return CONFIG_DIR;
60
+ }
61
+ function getEnvPath() {
62
+ return ENV_PATH;
63
+ }
64
+ function getProjectsDir() {
65
+ return PROJECTS_DIR;
66
+ }
67
+ function ensureDirectories() {
68
+ if (!fs.existsSync(CONFIG_DIR)) {
69
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
70
+ }
71
+ if (!fs.existsSync(PROJECTS_DIR)) {
72
+ fs.mkdirSync(PROJECTS_DIR, { recursive: true });
73
+ }
74
+ }
75
+ function envExists() {
76
+ return fs.existsSync(ENV_PATH);
77
+ }
78
+ function loadConfig() {
79
+ if (!envExists())
80
+ return null;
81
+ dotenv.config({ path: ENV_PATH });
82
+ const config = {
83
+ ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY || '',
84
+ OPENAI_API_KEY: process.env.OPENAI_API_KEY || '',
85
+ FMP_API_KEY: process.env.FMP_API_KEY || '',
86
+ EODHD_API_KEY: process.env.EODHD_API_KEY || '',
87
+ FRED_API_KEY: process.env.FRED_API_KEY || '',
88
+ SERPER_API_KEY: process.env.SERPER_API_KEY || '',
89
+ SERPAPI_API_KEY: process.env.SERPAPI_API_KEY || '',
90
+ FIRECRAWL_API_KEY: process.env.FIRECRAWL_API_KEY || '',
91
+ TAVILY_API_KEY: process.env.TAVILY_API_KEY || '',
92
+ EXA_API_KEY: process.env.EXA_API_KEY || '',
93
+ };
94
+ return config;
95
+ }
96
+ function validateConfig(config) {
97
+ const errors = [];
98
+ const warnings = [];
99
+ if (!config.ANTHROPIC_API_KEY) {
100
+ errors.push('ANTHROPIC_API_KEY is required (powers the AI agents)');
101
+ }
102
+ if (!config.FMP_API_KEY) {
103
+ warnings.push('FMP_API_KEY not set — financial data collection will be limited');
104
+ }
105
+ if (!config.EODHD_API_KEY) {
106
+ warnings.push('EODHD_API_KEY not set — historical price data will be limited');
107
+ }
108
+ if (!config.FRED_API_KEY) {
109
+ warnings.push('FRED_API_KEY not set — macroeconomic data will be limited');
110
+ }
111
+ if (!config.SERPER_API_KEY && !config.SERPAPI_API_KEY) {
112
+ warnings.push('No search API key set — web research will be limited');
113
+ }
114
+ if (!config.FIRECRAWL_API_KEY) {
115
+ warnings.push('FIRECRAWL_API_KEY not set — web scraping will be unavailable');
116
+ }
117
+ return { valid: errors.length === 0, warnings, errors };
118
+ }
119
+ async function ensureConfig() {
120
+ ensureDirectories();
121
+ if (!envExists()) {
122
+ console.log(chalk_1.default.yellow(' No configuration found. Starting setup wizard...\n'));
123
+ const config = await (0, setup_1.runSetupWizard)();
124
+ if (!config) {
125
+ (0, banner_1.printError)('Setup cancelled. Run "autoscholar config" to configure later.');
126
+ return null;
127
+ }
128
+ return config;
129
+ }
130
+ const config = loadConfig();
131
+ if (!config) {
132
+ (0, banner_1.printError)('Failed to load configuration.');
133
+ return null;
134
+ }
135
+ const validation = validateConfig(config);
136
+ if (!validation.valid) {
137
+ for (const err of validation.errors) {
138
+ (0, banner_1.printError)(err);
139
+ }
140
+ console.log(chalk_1.default.dim('\n Run "autoscholar config" to fix configuration.\n'));
141
+ return null;
142
+ }
143
+ for (const warn of validation.warnings) {
144
+ (0, banner_1.printWarning)(warn);
145
+ }
146
+ return config;
147
+ }
148
+ function saveEnvFile(config) {
149
+ ensureDirectories();
150
+ const lines = Object.entries(config)
151
+ .filter(([_, v]) => v && v.trim().length > 0)
152
+ .map(([k, v]) => `${k}=${v}`);
153
+ fs.writeFileSync(ENV_PATH, lines.join('\n') + '\n', 'utf-8');
154
+ }
@@ -0,0 +1,179 @@
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.runSetupWizard = runSetupWizard;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const axios_1 = __importDefault(require("axios"));
11
+ const loader_1 = require("./loader");
12
+ const banner_1 = require("../cli/banner");
13
+ const API_KEYS = [
14
+ {
15
+ name: 'Anthropic API Key',
16
+ envKey: 'ANTHROPIC_API_KEY',
17
+ description: 'Powers all AI agents (Euler, Gauss, Turing, Newton, Fisher)',
18
+ required: true,
19
+ },
20
+ {
21
+ name: 'OpenAI API Key',
22
+ envKey: 'OPENAI_API_KEY',
23
+ description: 'Optional fallback LLM provider',
24
+ required: false,
25
+ },
26
+ {
27
+ name: 'FMP API Key',
28
+ envKey: 'FMP_API_KEY',
29
+ description: 'Financial Modeling Prep — company fundamentals, market data, SEC filings',
30
+ required: false,
31
+ testUrl: (key) => `https://financialmodelingprep.com/stable/profile?symbol=AAPL&apikey=${key}`,
32
+ },
33
+ {
34
+ name: 'EODHD API Key',
35
+ envKey: 'EODHD_API_KEY',
36
+ description: 'Historical prices, intraday data, options chains with Greeks',
37
+ required: false,
38
+ testUrl: (key) => `https://eodhd.com/api/eod/AAPL.US?api_token=${key}&fmt=json&limit=1`,
39
+ },
40
+ {
41
+ name: 'FRED API Key',
42
+ envKey: 'FRED_API_KEY',
43
+ description: 'Federal Reserve Economic Data — 840,000+ macroeconomic series',
44
+ required: false,
45
+ testUrl: (key) => `https://api.stlouisfed.org/fred/series?series_id=GDP&api_key=${key}&file_type=json`,
46
+ },
47
+ {
48
+ name: 'Serper API Key',
49
+ envKey: 'SERPER_API_KEY',
50
+ description: 'Google Search API for web research',
51
+ required: false,
52
+ },
53
+ {
54
+ name: 'SerpAPI Key',
55
+ envKey: 'SERPAPI_API_KEY',
56
+ description: 'Google Scholar search for academic papers',
57
+ required: false,
58
+ },
59
+ {
60
+ name: 'Firecrawl API Key',
61
+ envKey: 'FIRECRAWL_API_KEY',
62
+ description: 'Web scraping and data extraction',
63
+ required: false,
64
+ },
65
+ {
66
+ name: 'Tavily API Key',
67
+ envKey: 'TAVILY_API_KEY',
68
+ description: 'AI-powered web search with generated answers',
69
+ required: false,
70
+ },
71
+ {
72
+ name: 'Exa API Key',
73
+ envKey: 'EXA_API_KEY',
74
+ description: 'Semantic neural search for research discovery',
75
+ required: false,
76
+ },
77
+ ];
78
+ async function runSetupWizard() {
79
+ (0, banner_1.printSection)('AutoScholar Setup Wizard');
80
+ console.log(chalk_1.default.gray(' Configure your API keys to enable data collection and analysis.\n'));
81
+ console.log(chalk_1.default.gray(' Required keys are marked with *. Press Enter to skip optional keys.\n'));
82
+ const envValues = {};
83
+ for (const key of API_KEYS) {
84
+ const label = key.required
85
+ ? chalk_1.default.bold.white(` ${key.name}`) + chalk_1.default.red(' *')
86
+ : chalk_1.default.white(` ${key.name}`);
87
+ console.log(label);
88
+ console.log(chalk_1.default.dim(` ${key.description}`));
89
+ const { value } = await inquirer_1.default.prompt([
90
+ {
91
+ type: 'password',
92
+ name: 'value',
93
+ message: ` ${key.envKey}:`,
94
+ mask: '*',
95
+ validate: (input) => {
96
+ if (key.required && (!input || input.trim().length === 0)) {
97
+ return `${key.name} is required`;
98
+ }
99
+ return true;
100
+ },
101
+ },
102
+ ]);
103
+ if (value && value.trim().length > 0) {
104
+ envValues[key.envKey] = value.trim();
105
+ }
106
+ console.log();
107
+ }
108
+ (0, banner_1.printSection)('Validating API Keys');
109
+ const spinner = (0, ora_1.default)({ text: 'Testing connections...', indent: 2 }).start();
110
+ let allValid = true;
111
+ const results = [];
112
+ for (const key of API_KEYS) {
113
+ const val = envValues[key.envKey];
114
+ if (!val) {
115
+ results.push({ name: key.name, status: 'skip' });
116
+ continue;
117
+ }
118
+ if (key.testUrl) {
119
+ try {
120
+ spinner.text = `Testing ${key.name}...`;
121
+ const resp = await axios_1.default.get(key.testUrl(val), { timeout: 10000 });
122
+ if (resp.status === 200) {
123
+ results.push({ name: key.name, status: 'ok' });
124
+ }
125
+ else {
126
+ results.push({ name: key.name, status: 'fail' });
127
+ allValid = false;
128
+ }
129
+ }
130
+ catch {
131
+ results.push({ name: key.name, status: 'fail' });
132
+ allValid = false;
133
+ }
134
+ }
135
+ else {
136
+ results.push({ name: key.name, status: 'ok' });
137
+ }
138
+ }
139
+ spinner.stop();
140
+ for (const r of results) {
141
+ if (r.status === 'ok') {
142
+ (0, banner_1.printSuccess)(`${r.name} — connected`);
143
+ }
144
+ else if (r.status === 'skip') {
145
+ console.log(chalk_1.default.dim(` ○ ${r.name} — skipped`));
146
+ }
147
+ else {
148
+ (0, banner_1.printError)(`${r.name} — invalid key`);
149
+ }
150
+ }
151
+ if (!allValid) {
152
+ console.log();
153
+ (0, banner_1.printWarning)('Some keys failed validation. They will still be saved.');
154
+ }
155
+ (0, loader_1.saveEnvFile)(envValues);
156
+ console.log();
157
+ (0, banner_1.printSuccess)('AutoScholar CLI successfully configured');
158
+ console.log(chalk_1.default.dim(` Config saved to ~/.autoscholar/.env\n`));
159
+ const config = {
160
+ ANTHROPIC_API_KEY: envValues.ANTHROPIC_API_KEY || '',
161
+ OPENAI_API_KEY: envValues.OPENAI_API_KEY,
162
+ FMP_API_KEY: envValues.FMP_API_KEY,
163
+ EODHD_API_KEY: envValues.EODHD_API_KEY,
164
+ FRED_API_KEY: envValues.FRED_API_KEY,
165
+ SERPER_API_KEY: envValues.SERPER_API_KEY,
166
+ SERPAPI_API_KEY: envValues.SERPAPI_API_KEY,
167
+ FIRECRAWL_API_KEY: envValues.FIRECRAWL_API_KEY,
168
+ TAVILY_API_KEY: envValues.TAVILY_API_KEY,
169
+ EXA_API_KEY: envValues.EXA_API_KEY,
170
+ };
171
+ const validation = (0, loader_1.validateConfig)(config);
172
+ if (!validation.valid) {
173
+ for (const err of validation.errors) {
174
+ (0, banner_1.printError)(err);
175
+ }
176
+ return null;
177
+ }
178
+ return config;
179
+ }