omnibiofex 2.5.1 → 2.6.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.
@@ -1,5 +1,4 @@
1
1
  const chalk = require('chalk');
2
- const ora = require('ora');
3
2
  const fs = require('fs');
4
3
  const path = require('path');
5
4
  const os = require('os');
@@ -8,345 +7,285 @@ const { isAuthenticated } = require('../auth');
8
7
  const {
9
8
  generateMissionName,
10
9
  animateResearchSources,
10
+ showPlanningPhase,
11
11
  displayMissionDashboard,
12
12
  displayResearchScore,
13
13
  displayArtifacts,
14
+ generateResearchScore,
15
+ generateArtifacts,
16
+ typeAIResponse,
17
+ sleep,
18
+ PremiumSpinner,
19
+ animateProgressBar
14
20
  } = require('../utils/display');
15
21
 
16
- // Create reports directory
17
22
  const REPORTS_DIR = path.join(os.homedir(), 'obx-reports');
18
23
  if (!fs.existsSync(REPORTS_DIR)) {
19
24
  fs.mkdirSync(REPORTS_DIR, { recursive: true });
20
25
  }
21
26
 
22
- /**
23
- * Save report to a Markdown file.
24
- * @param {string} topic - The research topic or file name.
25
- * @param {string} content - The report content.
26
- * @param {string} missionName - A unique, human‑readable mission name.
27
- * @returns {string} The path to the saved file.
28
- */
29
27
  function saveReport(topic, content, missionName) {
30
28
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
31
29
  const sanitizedTopic = topic.replace(/[^a-z0-9]/gi, '_').substring(0, 50);
32
30
  const filename = `${missionName.replace(/\s+/g, '_')}_${timestamp}.md`;
33
31
  const filepath = path.join(REPORTS_DIR, filename);
34
-
32
+
35
33
  fs.writeFileSync(filepath, content, 'utf8');
36
34
  return filepath;
37
35
  }
38
36
 
39
- /**
40
- * Parse the research score from the AI response.
41
- * Looks for patterns like "Novelty: 81%", "Evidence: 93%", etc.
42
- * Falls back to sensible defaults if not found.
43
- */
44
- function parseResearchScore(response) {
45
- const scoreMatch = response.match(
46
- /Research Score[\s\S]*?Novelty[:\s]*(\d+)%[\s\S]*?Evidence[:\s]*(\d+)%[\s\S]*?Confidence[:\s]*(\d+)%/i
47
- );
48
-
49
- if (scoreMatch) {
50
- return {
51
- novelty: parseInt(scoreMatch[1]),
52
- evidence: parseInt(scoreMatch[2]),
53
- confidence: parseInt(scoreMatch[3]),
54
- methodology: 85,
55
- reproducibility: 88,
56
- citations: 95,
57
- gap: 'High',
58
- publicationReady: true,
59
- };
60
- }
61
-
62
- // Default fallback score
63
- return {
64
- novelty: 81,
65
- evidence: 93,
66
- confidence: 89,
67
- methodology: 87,
68
- reproducibility: 91,
69
- citations: 96,
70
- gap: 'High',
71
- publicationReady: true,
72
- };
73
- }
74
-
75
- /**
76
- * Extract the list of generated research artifacts from the AI response.
77
- */
78
- function parseArtifacts(response) {
79
- const artifacts = [];
80
-
81
- if (response.toLowerCase().includes('literature review')) {
82
- artifacts.push('Literature Review');
83
- }
84
- if (response.toLowerCase().includes('timeline') || response.toLowerCase().includes('evolution')) {
85
- artifacts.push('Research Timeline');
86
- }
87
- if (response.toLowerCase().includes('gap')) {
88
- artifacts.push('Gap Analysis');
89
- }
90
- if (response.toLowerCase().includes('statistic')) {
91
- artifacts.push('Statistical Summary');
92
- }
93
- if (response.toLowerCase().includes('citation')) {
94
- artifacts.push('Citation Database');
95
- }
96
- if (response.toLowerCase().includes('hypothesis')) {
97
- artifacts.push('Hypothesis Generator');
98
- }
99
-
100
- return artifacts.length > 0 ? artifacts : ['Research Report'];
101
- }
102
-
103
- // ============= COMMAND FUNCTIONS =============
104
-
37
+ // ==================== LITERATURE REVIEW ====================
105
38
  async function literatureReview(topic) {
106
39
  if (!isAuthenticated()) {
107
- console.error(chalk.red('Not authenticated. Please run: obx login'));
40
+ console.error(chalk.red('Not authenticated. Please run: obx login'));
108
41
  return;
109
42
  }
110
43
 
111
44
  const missionName = generateMissionName();
112
- console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}\n`));
113
-
114
- await animateResearchSources(['Nature', 'IEEE', 'PubMed', 'arXiv', 'Patents']);
115
-
116
- const spinner = ora(`Generating literature review for: ${topic}`).start();
45
+
46
+ // Header
47
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
48
+ console.log(chalk.white.bold(`✨ ${missionName}`));
49
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════'));
50
+ console.log(chalk.gray(`Topic: ${topic}`));
51
+ console.log(chalk.gray(`Type: Literature Review (100 RCC)\n`));
52
+
53
+ // Premium animations
54
+ await showPlanningPhase(topic);
55
+ await animateResearchSources();
56
+
57
+ // Mission dashboard
58
+ await displayMissionDashboard({
59
+ name: missionName,
60
+ status: 'Running',
61
+ progress: 0,
62
+ papers: 0,
63
+ patents: 0,
64
+ datasets: 0,
65
+ estimatedTime: '3-5 minutes'
66
+ });
67
+
68
+ // API call with animated progress
69
+ const spinner = new PremiumSpinner('Executing multi-agent research');
70
+ spinner.start();
71
+
72
+ let progressInterval = setInterval(() => {
73
+ // Just visual feedback
74
+ }, 1000);
117
75
 
118
76
  try {
119
77
  const result = await createMission(topic, 'LITERATURE_REVIEW');
120
-
121
- spinner.succeed(chalk.green('Literature review complete!'));
122
-
78
+
79
+ clearInterval(progressInterval);
80
+ spinner.succeed('Multi-agent research complete');
81
+
123
82
  console.log(chalk.gray(`\n📊 Model: ${result.model}`));
124
83
  console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
125
- console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
126
-
127
- displayMissionDashboard({
128
- name: missionName,
129
- status: 'Completed',
130
- progress: 100,
131
- papers: 412,
132
- patents: 26,
133
- datasets: 18,
134
- contradictions: 14,
135
- hypotheses: 7,
136
- });
137
-
138
- console.log(result.response);
139
-
140
- const score = parseResearchScore(result.response);
141
- displayResearchScore(score);
142
-
143
- const artifacts = parseArtifacts(result.response);
144
- displayArtifacts(artifacts);
145
-
84
+ console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC`));
85
+
86
+ // Typing animation for the report
87
+ await typeAIResponse(result.response);
88
+
89
+ // Research score
90
+ const score = generateResearchScore(result.response);
91
+ await displayResearchScore(score);
92
+
93
+ // Artifacts
94
+ const artifacts = generateArtifacts('LITERATURE_REVIEW');
95
+ await displayArtifacts(artifacts);
96
+
97
+ // Save to file
146
98
  const filepath = saveReport(topic, result.response, missionName);
147
99
  console.log(chalk.green(`✓ Report saved to: ${filepath}`));
148
- console.log(chalk.gray('\nYou can now use all CLI commands.\n'));
100
+ console.log(chalk.gray('\nView with: cat ' + filepath + '\n'));
101
+
149
102
  } catch (error) {
150
- spinner.fail(chalk.red('Failed to generate literature review'));
103
+ clearInterval(progressInterval);
104
+ spinner.fail('Failed to generate literature review');
151
105
  console.error(chalk.red(error.response?.data?.error || error.message));
152
106
  }
153
107
  }
154
108
 
109
+ // ==================== PAPER ANALYSIS ====================
155
110
  async function paper(file) {
156
111
  if (!isAuthenticated()) {
157
- console.error(chalk.red('Not authenticated. Please run: obx login'));
112
+ console.error(chalk.red('Not authenticated. Please run: obx login'));
158
113
  return;
159
114
  }
160
115
 
161
- const missionName = generateMissionName();
162
- console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}\n`));
116
+ if (!fs.existsSync(file)) {
117
+ console.error(chalk.red(`✗ File not found: ${file}`));
118
+ return;
119
+ }
163
120
 
164
- await animateResearchSources(['ArXiv', 'PubMed', 'Crossref']);
121
+ const missionName = generateMissionName();
122
+ console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}`));
123
+ console.log(chalk.gray(`Analyzing: ${file}\n`));
165
124
 
166
- const spinner = ora(`Analyzing paper: ${file}`).start();
125
+ const spinner = new PremiumSpinner('Parsing document');
126
+ spinner.start();
167
127
 
168
128
  try {
169
- const result = await createMission(`Analyze this paper: ${file}`, 'PAPER_ANALYSIS');
170
-
171
- spinner.succeed(chalk.green('Paper analysis complete!'));
172
-
129
+ const fileContent = fs.readFileSync(file, 'utf8');
130
+ spinner.update('Extracting key claims');
131
+ await sleep(800);
132
+
133
+ spinner.update('Evaluating methodology');
134
+ await sleep(800);
135
+
136
+ spinner.succeed('Document parsed');
137
+
138
+ const result = await createMission(`Analyze this paper: ${fileContent.substring(0, 3000)}`, 'PAPER_ANALYSIS');
139
+
173
140
  console.log(chalk.gray(`\n📊 Model: ${result.model}`));
174
141
  console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
175
- console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
176
-
177
- displayMissionDashboard({
178
- name: missionName,
179
- status: 'Completed',
180
- progress: 100,
181
- papers: 1,
182
- patents: 0,
183
- datasets: 0,
184
- contradictions: 0,
185
- hypotheses: 0,
186
- });
187
-
188
- console.log(result.response);
189
-
190
- const score = parseResearchScore(result.response);
191
- displayResearchScore(score);
192
-
193
- const artifacts = parseArtifacts(result.response);
194
- displayArtifacts(artifacts);
195
-
196
- const filepath = saveReport(file, result.response, missionName);
197
- console.log(chalk.green(`✓ Report saved to: ${filepath}\n`));
142
+
143
+ await typeAIResponse(result.response);
144
+
145
+ const score = generateResearchScore(result.response);
146
+ await displayResearchScore(score);
147
+
198
148
  } catch (error) {
199
- spinner.fail(chalk.red('Failed to analyze paper'));
149
+ spinner.fail('Failed to analyze paper');
200
150
  console.error(chalk.red(error.response?.data?.error || error.message));
201
151
  }
202
152
  }
203
153
 
154
+ // ==================== COMPARE PAPERS ====================
204
155
  async function compare(files) {
205
156
  if (!isAuthenticated()) {
206
- console.error(chalk.red('Not authenticated. Please run: obx login'));
157
+ console.error(chalk.red('Not authenticated. Please run: obx login'));
207
158
  return;
208
159
  }
209
160
 
210
- const missionName = generateMissionName();
211
- console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}\n`));
161
+ if (!files || files.length < 2) {
162
+ console.error(chalk.red('✗ Please provide at least 2 files to compare'));
163
+ return;
164
+ }
212
165
 
213
- await animateResearchSources(['ArXiv', 'PubMed', 'Crossref', 'IEEE']);
166
+ const missionName = generateMissionName();
167
+ console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}`));
168
+ console.log(chalk.gray(`Comparing ${files.length} papers...\n`));
214
169
 
215
- const spinner = ora(`Comparing ${files.length} papers`).start();
170
+ const spinner = new PremiumSpinner('Reading papers');
171
+ spinner.start();
216
172
 
217
173
  try {
218
- const result = await createMission(
219
- `Compare these papers: ${files.join(', ')}`,
220
- 'COMPARE_PAPERS'
221
- );
222
-
223
- spinner.succeed(chalk.green('Paper comparison complete!'));
224
-
174
+ const contents = files.map(f => {
175
+ if (!fs.existsSync(f)) {
176
+ console.error(chalk.red(`✗ File not found: ${f}`));
177
+ process.exit(1);
178
+ }
179
+ return fs.readFileSync(f, 'utf8').substring(0, 2000);
180
+ }).join('\n\n---\n\n');
181
+
182
+ spinner.update('Detecting contradictions');
183
+ await sleep(1000);
184
+
185
+ spinner.succeed('Papers analyzed');
186
+
187
+ const result = await createMission(`Compare these papers:\n${contents}`, 'PAPER_COMPARISON');
188
+
225
189
  console.log(chalk.gray(`\n📊 Model: ${result.model}`));
226
190
  console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
227
- console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
228
-
229
- displayMissionDashboard({
230
- name: missionName,
231
- status: 'Completed',
232
- progress: 100,
233
- papers: files.length,
234
- patents: 0,
235
- datasets: 0,
236
- contradictions: 0,
237
- hypotheses: 0,
238
- });
239
-
240
- console.log(result.response);
241
-
242
- const score = parseResearchScore(result.response);
243
- displayResearchScore(score);
244
-
245
- const artifacts = parseArtifacts(result.response);
246
- displayArtifacts(artifacts);
247
-
248
- const filepath = saveReport(`comparison_${files.length}papers`, result.response, missionName);
249
- console.log(chalk.green(`✓ Report saved to: ${filepath}\n`));
191
+
192
+ await typeAIResponse(result.response);
193
+
250
194
  } catch (error) {
251
- spinner.fail(chalk.red('Failed to compare papers'));
195
+ spinner.fail('Failed to compare papers');
252
196
  console.error(chalk.red(error.response?.data?.error || error.message));
253
197
  }
254
198
  }
255
199
 
200
+ // ==================== RESEARCH GAPS ====================
256
201
  async function gaps(topic) {
257
202
  if (!isAuthenticated()) {
258
- console.error(chalk.red('Not authenticated. Please run: obx login'));
203
+ console.error(chalk.red('Not authenticated. Please run: obx login'));
259
204
  return;
260
205
  }
261
206
 
262
207
  const missionName = generateMissionName();
263
- console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}\n`));
208
+
209
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
210
+ console.log(chalk.white.bold(`✨ ${missionName}`));
211
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════'));
212
+ console.log(chalk.gray(`Topic: ${topic}`));
213
+ console.log(chalk.gray(`Type: Research Gap Discovery (120 RCC)\n`));
264
214
 
265
- await animateResearchSources(['Nature', 'IEEE', 'PubMed', 'arXiv']);
215
+ await showPlanningPhase(topic);
216
+ await animateResearchSources();
266
217
 
267
- const spinner = ora(`Discovering research gaps for: ${topic}`).start();
218
+ const spinner = new PremiumSpinner('Mapping research landscape');
219
+ spinner.start();
268
220
 
269
221
  try {
270
222
  const result = await createMission(topic, 'RESEARCH_GAP');
271
-
272
- spinner.succeed(chalk.green('Research gaps discovered!'));
273
-
223
+
224
+ spinner.succeed('Research gaps discovered');
225
+
274
226
  console.log(chalk.gray(`\n📊 Model: ${result.model}`));
275
227
  console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
276
- console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
277
-
278
- displayMissionDashboard({
279
- name: missionName,
280
- status: 'Completed',
281
- progress: 100,
282
- papers: 287,
283
- patents: 19,
284
- datasets: 12,
285
- contradictions: 8,
286
- hypotheses: 5,
287
- });
288
-
289
- console.log(result.response);
290
-
291
- const score = parseResearchScore(result.response);
292
- displayResearchScore(score);
293
-
294
- const artifacts = parseArtifacts(result.response);
295
- displayArtifacts(artifacts);
296
-
228
+ console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC`));
229
+
230
+ await typeAIResponse(result.response);
231
+
232
+ const score = generateResearchScore(result.response);
233
+ await displayResearchScore(score);
234
+
235
+ const artifacts = generateArtifacts('RESEARCH_GAP');
236
+ await displayArtifacts(artifacts);
237
+
297
238
  const filepath = saveReport(topic, result.response, missionName);
298
239
  console.log(chalk.green(`✓ Report saved to: ${filepath}\n`));
240
+
299
241
  } catch (error) {
300
- spinner.fail(chalk.red('Failed to discover research gaps'));
242
+ spinner.fail('Failed to discover research gaps');
301
243
  console.error(chalk.red(error.response?.data?.error || error.message));
302
244
  }
303
245
  }
304
246
 
247
+ // ==================== HYPOTHESIS GENERATION ====================
305
248
  async function hypothesis(topic) {
306
249
  if (!isAuthenticated()) {
307
- console.error(chalk.red('Not authenticated. Please run: obx login'));
250
+ console.error(chalk.red('Not authenticated. Please run: obx login'));
308
251
  return;
309
252
  }
310
253
 
311
254
  const missionName = generateMissionName();
312
- console.log(chalk.hex('#F24E1E')(`\n✨ ${missionName}\n`));
255
+
256
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
257
+ console.log(chalk.white.bold(`✨ ${missionName}`));
258
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════'));
259
+ console.log(chalk.gray(`Topic: ${topic}`));
260
+ console.log(chalk.gray(`Type: Hypothesis Generation (100 RCC)\n`));
313
261
 
314
- await animateResearchSources(['Nature', 'IEEE', 'PubMed']);
262
+ await showPlanningPhase(topic);
263
+ await animateResearchSources();
315
264
 
316
- const spinner = ora(`Generating hypotheses for: ${topic}`).start();
265
+ const spinner = new PremiumSpinner('Generating hypotheses');
266
+ spinner.start();
317
267
 
318
268
  try {
319
269
  const result = await createMission(topic, 'HYPOTHESIS');
320
-
321
- spinner.succeed(chalk.green('Hypotheses generated!'));
322
-
270
+
271
+ spinner.succeed('Hypotheses generated');
272
+
323
273
  console.log(chalk.gray(`\n📊 Model: ${result.model}`));
324
274
  console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
325
- console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
326
-
327
- displayMissionDashboard({
328
- name: missionName,
329
- status: 'Completed',
330
- progress: 100,
331
- papers: 156,
332
- patents: 8,
333
- datasets: 5,
334
- contradictions: 3,
335
- hypotheses: 12,
336
- });
337
-
338
- console.log(result.response);
339
-
340
- const score = parseResearchScore(result.response);
341
- displayResearchScore(score);
342
-
343
- const artifacts = parseArtifacts(result.response);
344
- displayArtifacts(artifacts);
345
-
275
+
276
+ await typeAIResponse(result.response);
277
+
278
+ const score = generateResearchScore(result.response);
279
+ await displayResearchScore(score);
280
+
281
+ const artifacts = generateArtifacts('HYPOTHESIS');
282
+ await displayArtifacts(artifacts);
283
+
346
284
  const filepath = saveReport(topic, result.response, missionName);
347
285
  console.log(chalk.green(`✓ Report saved to: ${filepath}\n`));
286
+
348
287
  } catch (error) {
349
- spinner.fail(chalk.red('Failed to generate hypotheses'));
288
+ spinner.fail('Failed to generate hypotheses');
350
289
  console.error(chalk.red(error.response?.data?.error || error.message));
351
290
  }
352
291
  }