omnibiofex 2.7.1 → 2.8.1

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.
package/bin/obx CHANGED
@@ -6,7 +6,7 @@ const figlet = require('figlet');
6
6
  const path = require('path');
7
7
  const fs = require('fs');
8
8
 
9
- // šŸ”„ FIX: Read version dynamically from package.json
9
+ // Read version dynamically from package.json
10
10
  const packageJson = JSON.parse(
11
11
  fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8')
12
12
  );
@@ -18,7 +18,8 @@ console.log(
18
18
  figlet.textSync('OmniBioFex X', { horizontalLayout: 'full' })
19
19
  )
20
20
  );
21
- console.log(chalk.gray(`The Autonomous Research Terminal v${VERSION}\n`));
21
+ console.log(chalk.gray(`The Autonomous Research Operating System v${VERSION}\n`));
22
+ console.log(chalk.hex('#F24E1E')('Create Research. Publish It. Earn From It.\n'));
22
23
 
23
24
  // Global error handler
24
25
  process.on('unhandledRejection', (error) => {
@@ -26,11 +27,11 @@ process.on('unhandledRejection', (error) => {
26
27
  process.exit(1);
27
28
  });
28
29
 
29
- // šŸ”„ FIX: Register --version flag properly
30
+ // Register --version flag
30
31
  program
31
32
  .name('obx')
32
33
  .version(VERSION, '-v, --version', 'Show CLI version')
33
- .description('OmniBioFex X - The Autonomous Research Terminal');
34
+ .description('OmniBioFex X - The Autonomous Research Operating System');
34
35
 
35
36
  // ==================== AUTHENTICATION ====================
36
37
  const { login, logout } = require('../src/auth');
@@ -125,6 +126,41 @@ program
125
126
  .argument('<file>', 'DICOM/image file path')
126
127
  .action(medical);
127
128
 
129
+ // ==================== PUBLISH & EARN COMMANDS ====================
130
+ const { publish } = require('../src/commands/publish');
131
+ const { earnings } = require('../src/commands/earnings');
132
+
133
+ program
134
+ .command('publish')
135
+ .description('šŸ“¤ Publish research and start earning')
136
+ .argument('[mission-id]', 'Mission ID to publish')
137
+ .action(publish);
138
+
139
+ program
140
+ .command('earnings')
141
+ .description('šŸ’° View your earnings dashboard')
142
+ .action(earnings);
143
+
144
+ // ==================== OPEN COMMANDS ====================
145
+ const { openPage } = require('../src/commands/open');
146
+
147
+ program
148
+ .command('open')
149
+ .description('🌐 Open OmniBioFex X pages in browser')
150
+ .argument('[page]', 'Page to open (dashboard, earn, pricing, agents, etc.)')
151
+ .action(openPage);
152
+
153
+ // Shortcut commands
154
+ program
155
+ .command('dashboard')
156
+ .description('šŸ  Open web dashboard')
157
+ .action(() => openPage('dashboard'));
158
+
159
+ program
160
+ .command('earn')
161
+ .description('šŸ’° Open earn page')
162
+ .action(() => openPage('earn'));
163
+
128
164
  // ==================== ACCOUNT COMMANDS ====================
129
165
  const { credits, usage, buy } = require('../src/commands/account');
130
166
 
@@ -143,29 +179,6 @@ program
143
179
  .description('Open browser to purchase credits')
144
180
  .action(buy);
145
181
 
146
- // ==================== TIMELINE COMMAND ====================
147
- const { timeline } = require('../src/commands/timeline');
148
-
149
- program
150
- .command('timeline')
151
- .description('Generate research timeline for a topic')
152
- .argument('<topic>', 'Research topic')
153
- .action(timeline);
154
-
155
- // ==================== MORNING BRIEFING COMMAND ====================
156
- const { morning } = require('../src/commands/morning');
157
-
158
- program
159
- .command('morning')
160
- .description('Get your daily research briefing')
161
- .action(morning);
162
-
163
- // Also add short alias
164
- program
165
- .command('briefing')
166
- .description('Get your daily research briefing (alias for morning)')
167
- .action(morning);
168
-
169
182
  // ==================== DEBUG COMMAND ====================
170
183
  const { debug } = require('../src/commands/debug');
171
184
 
@@ -179,5 +192,11 @@ program.parse(process.argv);
179
192
 
180
193
  // Show help if no command provided
181
194
  if (!process.argv.slice(2).length) {
182
- program.outputHelp();
195
+ console.log(chalk.hex('#F24E1E')('\nšŸ“š QUICK START:\n'));
196
+ console.log(chalk.white(' obx login # Authenticate'));
197
+ console.log(chalk.white(' obx mission create # Create research'));
198
+ console.log(chalk.white(' obx publish <mission-id> # Publish & earn'));
199
+ console.log(chalk.white(' obx earnings # View earnings'));
200
+ console.log(chalk.white(' obx open # Open web pages\n'));
201
+ console.log(chalk.gray(' Run "obx --help" for all commands\n'));
183
202
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnibiofex",
3
- "version": "2.7.1",
3
+ "version": "2.8.1",
4
4
  "description": "OmniBioFex X - The Autonomous Research Terminal for AI-powered research missions",
5
5
  "main": "bin/obx",
6
6
  "bin": {
@@ -1,47 +1,173 @@
1
1
  const chalk = require('chalk');
2
2
  const open = require('open');
3
- const { isAuthenticated } = require('../auth');
4
- const { getUserCredits } = require('../api');
5
- const config = require('../config');
3
+ const { getAuthToken, isAuthenticated } = require('../auth');
4
+ const { PremiumSpinner, sleep } = require('../utils/display');
5
+ const { initializeApp } = require('firebase/app');
6
+ const { getAuth } = require('firebase/auth');
7
+ const { getFirestore, collection, query, where, getDocs } = require('firebase/firestore');
8
+
9
+ const firebaseConfig = {
10
+ apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
11
+ authDomain: "omnibiofex-x.firebaseapp.com",
12
+ projectId: "omnibiofex-x",
13
+ storageBucket: "omnibiofex-x.firebasestorage.app",
14
+ messagingSenderId: "292246591666",
15
+ appId: "1:292246591666:web:a182851585e4b0f79511ab"
16
+ };
17
+
18
+ const app = initializeApp(firebaseConfig);
19
+ const db = getFirestore(app);
6
20
 
7
21
  async function credits() {
8
22
  if (!isAuthenticated()) {
9
- console.error(chalk.red('Not authenticated. Please run: obx login'));
23
+ console.error(chalk.red('āœ— Not authenticated. Please run: obx login'));
10
24
  return;
11
25
  }
12
26
 
13
- console.log(chalk.hex('#F24E1E')('\nšŸ’° Research Compute Credits\n'));
14
-
27
+ const spinner = new PremiumSpinner('Fetching your credit balance');
28
+ spinner.start();
29
+
15
30
  try {
16
- const data = await getUserCredits();
17
- console.log(chalk.white(`Current Balance: ${chalk.hex('#F24E1E')(data.balance.toLocaleString())} RCC`));
18
- console.log(chalk.gray(`Used: ${data.used.toLocaleString()} RCC`));
19
- console.log(chalk.gray(`Total: ${data.total.toLocaleString()} RCC\n`));
31
+ const token = await getAuthToken();
32
+
33
+ const response = await fetch('https://getusercredits-yyedhmslhq-uc.a.run.app', {
34
+ headers: { 'Authorization': `Bearer ${token}` }
35
+ });
36
+
37
+ const data = await response.json();
38
+ const balance = data.tokens || 0;
39
+
40
+ spinner.succeed('Credits loaded');
41
+
42
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
43
+ console.log(chalk.white.bold('šŸ’° RESEARCH FUEL (RCC)'));
44
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
45
+
46
+ console.log(chalk.white(` Current Balance: ${chalk.green(balance.toLocaleString() + ' RCC')}`));
47
+ console.log(chalk.white(` Status: ${balance > 100 ? chalk.green('āœ“ Healthy') : chalk.yellow('⚠ Low')}`));
48
+
49
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
50
+ console.log(chalk.white.bold('šŸ“Š WHAT YOU CAN DO'));
51
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
52
+
53
+ console.log(chalk.white(` šŸ“š Literature Reviews: ${chalk.green(Math.floor(balance / 100))}`));
54
+ console.log(chalk.white(` šŸ“„ Paper Analyses: ${chalk.green(Math.floor(balance / 40))}`));
55
+ console.log(chalk.white(` šŸ” Quick Searches: ${chalk.green(Math.floor(balance / 10))}`));
56
+ console.log(chalk.white(` 🧪 Gap Discoveries: ${chalk.green(Math.floor(balance / 120))}`));
57
+
58
+ if (balance < 500) {
59
+ console.log(chalk.yellow('\n āš ļø Your fuel is running low!'));
60
+ console.log(chalk.gray(' Run "obx buy" to purchase more credits\n'));
61
+ }
62
+
63
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
64
+
20
65
  } catch (error) {
21
- console.error(chalk.red('Failed to fetch credits'));
22
- console.error(chalk.gray('Error details:', error.message));
66
+ spinner.fail('Failed to fetch credits');
67
+ console.error(chalk.red(error.message));
23
68
  }
24
69
  }
25
70
 
26
71
  async function usage() {
27
72
  if (!isAuthenticated()) {
28
- console.error(chalk.red('Not authenticated. Please run: obx login'));
73
+ console.error(chalk.red('āœ— Not authenticated. Please run: obx login'));
29
74
  return;
30
75
  }
31
76
 
32
- console.log(chalk.hex('#F24E1E')('\nšŸ“Š Usage Statistics\n'));
33
- console.log(chalk.gray('Total missions: 0'));
34
- console.log(chalk.gray('Total RCC spent: 0'));
35
- console.log(chalk.gray('Active missions: 0\n'));
77
+ const spinner = new PremiumSpinner('Fetching usage statistics');
78
+ spinner.start();
79
+
80
+ try {
81
+ const auth = getAuth(app);
82
+ const user = auth.currentUser;
83
+
84
+ if (!user) {
85
+ spinner.fail('Not authenticated');
86
+ console.error(chalk.red('Please run: obx login'));
87
+ return;
88
+ }
89
+
90
+ // Fetch ALL missions (real data)
91
+ const allMissionsQuery = query(
92
+ collection(db, 'missions'),
93
+ where('uid', '==', user.uid)
94
+ );
95
+
96
+ const allMissionsSnapshot = await getDocs(allMissionsQuery);
97
+ const allMissions = [];
98
+
99
+ allMissionsSnapshot.forEach((docSnap) => {
100
+ allMissions.push({
101
+ id: docSnap.id,
102
+ ...docSnap.data()
103
+ });
104
+ });
105
+
106
+ // Calculate real statistics
107
+ const totalMissions = allMissions.length;
108
+ const completedMissions = allMissions.filter(m => m.status === 'completed').length;
109
+ const activeMissions = allMissions.filter(m => m.status === 'running' || m.status === 'pending').length;
110
+ const publishedMissions = allMissions.filter(m => m.isPublished === true).length;
111
+ const totalRCCSpent = allMissions.reduce((sum, m) => sum + (m.rccCost || 0), 0);
112
+
113
+ // Fetch published missions for earnings
114
+ const publishedQuery = query(
115
+ collection(db, 'missions'),
116
+ where('uid', '==', user.uid),
117
+ where('isPublished', '==', true)
118
+ );
119
+
120
+ const publishedSnapshot = await getDocs(publishedQuery);
121
+ const publishedMissionsData = [];
122
+
123
+ publishedSnapshot.forEach((docSnap) => {
124
+ publishedMissionsData.push({
125
+ id: docSnap.id,
126
+ ...docSnap.data()
127
+ });
128
+ });
129
+
130
+ const totalViews = publishedMissionsData.reduce((sum, m) => sum + (m.views || 0), 0);
131
+ const totalEarnings = publishedMissionsData.reduce((sum, m) => sum + (m.earnings || 0), 0);
132
+
133
+ spinner.succeed('Usage statistics loaded');
134
+
135
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
136
+ console.log(chalk.white.bold('šŸ“Š USAGE STATISTICS'));
137
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
138
+
139
+ console.log(chalk.white(` šŸŽÆ Total Missions: ${chalk.green(totalMissions)}`));
140
+ console.log(chalk.white(` āœ… Completed: ${chalk.green(completedMissions)}`));
141
+ console.log(chalk.white(` ā³ Active: ${chalk.yellow(activeMissions)}`));
142
+ console.log(chalk.white(` ⛽ RCC Spent: ${chalk.green(totalRCCSpent.toLocaleString())}`));
143
+ console.log(chalk.white(` šŸ“¤ Published: ${chalk.green(publishedMissions)}`));
144
+ console.log(chalk.white(` šŸ‘ Total Views: ${chalk.green(totalViews.toLocaleString())}`));
145
+ console.log(chalk.white(` šŸ’° Total Earnings: ${chalk.green('₹' + totalEarnings.toLocaleString())}`));
146
+
147
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
148
+
149
+ } catch (error) {
150
+ spinner.fail('Failed to fetch usage statistics');
151
+ console.error(chalk.red(error.message));
152
+ }
36
153
  }
37
154
 
38
155
  async function buy() {
39
- console.log(chalk.hex('#F24E1E')('\nšŸ’³ Purchase Research Credits\n'));
40
- console.log(chalk.gray('Opening browser to dashboard...\n'));
41
-
42
- await open(config.get('dashboardUrl'));
156
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
157
+ console.log(chalk.white.bold('šŸ’³ PURCHASE RESEARCH FUEL'));
158
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
159
+
160
+ console.log(chalk.gray('Opening pricing page in your browser...\n'));
43
161
 
44
- console.log(chalk.gray('āœ“ Browser opened. Complete purchase in the dashboard.\n'));
162
+ try {
163
+ await open('https://x.omnibiofex.cloud/pricing');
164
+ console.log(chalk.green('āœ“ Opened pricing page\n'));
165
+ console.log(chalk.gray('Choose the plan that fits your research needs.\n'));
166
+ console.log(chalk.gray('All plans include 80%+ revenue share on published research.\n'));
167
+ } catch (error) {
168
+ console.error(chalk.red('āœ— Failed to open browser'));
169
+ console.log(chalk.gray('\nPlease visit: https://x.omnibiofex.cloud/pricing\n'));
170
+ }
45
171
  }
46
172
 
47
173
  module.exports = { credits, usage, buy };
@@ -0,0 +1,147 @@
1
+ const chalk = require('chalk');
2
+ const { getAuthToken, isAuthenticated } = require('../auth');
3
+ const { PremiumSpinner, sleep } = require('../utils/display');
4
+ const { initializeApp } = require('firebase/app');
5
+ const { getAuth } = require('firebase/auth');
6
+ const { getFirestore, collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
7
+
8
+ const firebaseConfig = {
9
+ apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
10
+ authDomain: "omnibiofex-x.firebaseapp.com",
11
+ projectId: "omnibiofex-x",
12
+ storageBucket: "omnibiofex-x.firebasestorage.app",
13
+ messagingSenderId: "292246591666",
14
+ appId: "1:292246591666:web:a182851585e4b0f79511ab"
15
+ };
16
+
17
+ const app = initializeApp(firebaseConfig);
18
+ const db = getFirestore(app);
19
+
20
+ async function earnings() {
21
+ if (!isAuthenticated()) {
22
+ console.error(chalk.red('āœ— Not authenticated. Please run: obx login'));
23
+ return;
24
+ }
25
+
26
+ const spinner = new PremiumSpinner('Fetching your earnings data');
27
+ spinner.start();
28
+
29
+ try {
30
+ const auth = getAuth(app);
31
+ const user = auth.currentUser;
32
+
33
+ if (!user) {
34
+ spinner.fail('Not authenticated');
35
+ console.error(chalk.red('Please run: obx login'));
36
+ return;
37
+ }
38
+
39
+ // Fetch real published missions with earnings data
40
+ const publishedQuery = query(
41
+ collection(db, 'missions'),
42
+ where('uid', '==', user.uid),
43
+ where('isPublished', '==', true),
44
+ orderBy('publishedAt', 'desc'),
45
+ limit(100)
46
+ );
47
+
48
+ const querySnapshot = await getDocs(publishedQuery);
49
+ const publishedMissions = [];
50
+
51
+ querySnapshot.forEach((docSnap) => {
52
+ publishedMissions.push({
53
+ id: docSnap.id,
54
+ ...docSnap.data()
55
+ });
56
+ });
57
+
58
+ spinner.succeed('Earnings data loaded');
59
+
60
+ // Calculate real earnings from actual data
61
+ const totalViews = publishedMissions.reduce((sum, m) => sum + (m.views || 0), 0);
62
+ const totalDownloads = publishedMissions.reduce((sum, m) => sum + (m.downloads || 0), 0);
63
+ const totalCitations = publishedMissions.reduce((sum, m) => sum + (m.citations || 0), 0);
64
+ const totalEarnings = publishedMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
65
+
66
+ // Calculate monthly breakdown
67
+ const now = new Date();
68
+ const thisMonth = now.getMonth();
69
+ const thisYear = now.getFullYear();
70
+ const lastMonth = thisMonth === 0 ? 11 : thisMonth - 1;
71
+ const lastMonthYear = thisMonth === 0 ? thisYear - 1 : thisYear;
72
+
73
+ const thisMonthMissions = publishedMissions.filter(m => {
74
+ const publishedDate = m.publishedAt?.toDate?.();
75
+ return publishedDate && publishedDate.getMonth() === thisMonth && publishedDate.getFullYear() === thisYear;
76
+ });
77
+
78
+ const lastMonthMissions = publishedMissions.filter(m => {
79
+ const publishedDate = m.publishedAt?.toDate?.();
80
+ return publishedDate && publishedDate.getMonth() === lastMonth && publishedDate.getFullYear() === lastMonthYear;
81
+ });
82
+
83
+ const thisMonthEarnings = thisMonthMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
84
+ const thisMonthViews = thisMonthMissions.reduce((sum, m) => sum + (m.views || 0), 0);
85
+ const lastMonthEarnings = lastMonthMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
86
+
87
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
88
+ console.log(chalk.white.bold('šŸ’° EARNINGS DASHBOARD'));
89
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
90
+
91
+ console.log(chalk.white.bold('šŸ“Š OVERVIEW'));
92
+ console.log(chalk.gray('─'.repeat(60)));
93
+ console.log(chalk.white(`\n šŸ’° Total Earnings: ${chalk.green('₹' + totalEarnings.toLocaleString())}`));
94
+ console.log(chalk.white(` šŸ“… This Month: ${chalk.green('₹' + thisMonthEarnings.toLocaleString())}`));
95
+ console.log(chalk.white(` šŸ“… Last Month: ${chalk.gray('₹' + lastMonthEarnings.toLocaleString())}`));
96
+ console.log(chalk.white(` šŸ“„ Published Research: ${chalk.green(publishedMissions.length)}`));
97
+
98
+ console.log(chalk.white.bold('\n\nšŸ“ˆ TRAFFIC METRICS'));
99
+ console.log(chalk.gray('─'.repeat(60)));
100
+ console.log(chalk.white(`\n šŸ‘ Total Views: ${chalk.green(totalViews.toLocaleString())}`));
101
+ console.log(chalk.white(` šŸ‘ This Month: ${chalk.green(thisMonthViews.toLocaleString())}`));
102
+ console.log(chalk.white(` šŸ’¾ Total Downloads: ${chalk.green(totalDownloads.toLocaleString())}`));
103
+ console.log(chalk.white(` šŸ“š Total Citations: ${chalk.green(totalCitations.toLocaleString())}`));
104
+
105
+ if (totalViews > 0) {
106
+ const averagePerView = totalEarnings / totalViews;
107
+ console.log(chalk.white(` šŸ’µ Average Per View: ${chalk.green('₹' + averagePerView.toFixed(3))}`));
108
+ }
109
+
110
+ console.log(chalk.white.bold('\n\nšŸ’³ PAYOUT DETAILS'));
111
+ console.log(chalk.gray('─'.repeat(60)));
112
+ console.log(chalk.white(`\n šŸ“Š Revenue Share: ${chalk.green('80%')}`));
113
+ console.log(chalk.white(` šŸ“… Next Payout: ${chalk.green('1st of next month')}`));
114
+ console.log(chalk.white(` šŸ’³ Payout Method: ${chalk.green('Bank Transfer / UPI')}`));
115
+
116
+ if (publishedMissions.length > 0) {
117
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
118
+ console.log(chalk.white.bold('šŸ“Š YOUR PUBLISHED RESEARCH'));
119
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
120
+
121
+ publishedMissions.slice(0, 10).forEach((m, i) => {
122
+ const publishedDate = m.publishedAt?.toDate?.().toLocaleDateString() || 'N/A';
123
+ console.log(chalk.white(`\n ${i + 1}. ${chalk.hex('#F24E1E')(m.id)}`));
124
+ console.log(chalk.white(` Topic: ${(m.message || 'No topic').substring(0, 50)}${(m.message?.length || 0) > 50 ? '...' : ''}`));
125
+ console.log(chalk.white(` šŸ‘ Views: ${chalk.green((m.views || 0).toLocaleString())}`));
126
+ console.log(chalk.white(` šŸ’° Earnings: ${chalk.green('₹' + (m.earnings || 0).toLocaleString())}`));
127
+ console.log(chalk.gray(` šŸ“… Published: ${publishedDate}`));
128
+ });
129
+ }
130
+
131
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
132
+
133
+ console.log(chalk.white.bold('šŸ’” TIPS TO INCREASE EARNINGS'));
134
+ console.log(chalk.gray('─'.repeat(60)));
135
+ console.log(chalk.white('\n āœ“ Publish more research to increase views'));
136
+ console.log(chalk.white(' āœ“ Share your research on social media'));
137
+ console.log(chalk.white(' āœ“ Use relevant tags for better discoverability'));
138
+ console.log(chalk.white(' āœ“ Create high-quality, comprehensive research'));
139
+ console.log(chalk.white(' āœ“ Update research regularly with new findings\n'));
140
+
141
+ } catch (error) {
142
+ spinner.fail('Failed to fetch earnings data');
143
+ console.error(chalk.red(error.message));
144
+ }
145
+ }
146
+
147
+ module.exports = { earnings };
@@ -0,0 +1,62 @@
1
+ const chalk = require('chalk');
2
+ const open = require('open');
3
+ const inquirer = require('inquirer');
4
+
5
+ async function openPage(page) {
6
+ const pages = {
7
+ 'dashboard': { url: 'https://x.omnibiofex.cloud/dash', name: 'Web Dashboard' },
8
+ 'earn': { url: 'https://x.omnibiofex.cloud/earn', name: 'How to Earn' },
9
+ 'pricing': { url: 'https://x.omnibiofex.cloud/pricing', name: 'Pricing Plans' },
10
+ 'agents': { url: 'https://x.omnibiofex.cloud/agents', name: 'AI Agents' },
11
+ 'how-it-works': { url: 'https://x.omnibiofex.cloud/how-it-works', name: 'How It Works' },
12
+ 'commands': { url: 'https://x.omnibiofex.cloud/commands', name: 'Commands Reference' },
13
+ 'cli-guide': { url: 'https://x.omnibiofex.cloud/cli-guide', name: 'CLI Guide' },
14
+ 'auth': { url: 'https://x.omnibiofex.cloud/auth', name: 'Authentication' },
15
+ 'home': { url: 'https://x.omnibiofex.cloud/', name: 'Home Page' }
16
+ };
17
+
18
+ if (!page) {
19
+ const { selectedPage } = await inquirer.prompt([
20
+ {
21
+ type: 'list',
22
+ name: 'selectedPage',
23
+ message: 'Which page would you like to open?',
24
+ choices: [
25
+ { name: 'šŸ  Home Page', value: 'home' },
26
+ { name: 'šŸ“Š Web Dashboard', value: 'dashboard' },
27
+ { name: 'šŸ’° How to Earn', value: 'earn' },
28
+ { name: 'šŸ’³ Pricing Plans', value: 'pricing' },
29
+ { name: 'šŸ¤– AI Agents', value: 'agents' },
30
+ { name: 'šŸ“– How It Works', value: 'how-it-works' },
31
+ { name: 'āŒØļø Commands Reference', value: 'commands' },
32
+ { name: 'šŸ“˜ CLI Guide', value: 'cli-guide' }
33
+ ]
34
+ }
35
+ ]);
36
+ page = selectedPage;
37
+ }
38
+
39
+ const pageInfo = pages[page];
40
+
41
+ if (!pageInfo) {
42
+ console.error(chalk.red(`āœ— Unknown page: ${page}`));
43
+ console.log(chalk.gray('\nAvailable pages:'));
44
+ Object.keys(pages).forEach(key => {
45
+ console.log(chalk.gray(` • ${key}`));
46
+ });
47
+ return;
48
+ }
49
+
50
+ console.log(chalk.hex('#F24E1E')(`\n🌐 Opening ${pageInfo.name}...`));
51
+ console.log(chalk.gray(` URL: ${pageInfo.url}\n`));
52
+
53
+ try {
54
+ await open(pageInfo.url);
55
+ console.log(chalk.green(`āœ“ Opened ${pageInfo.name} in your browser\n`));
56
+ } catch (error) {
57
+ console.error(chalk.red('āœ— Failed to open browser'));
58
+ console.log(chalk.gray(`\nPlease visit manually: ${pageInfo.url}\n`));
59
+ }
60
+ }
61
+
62
+ module.exports = { openPage };
@@ -0,0 +1,195 @@
1
+ const chalk = require('chalk');
2
+ const inquirer = require('inquirer');
3
+ const { getAuthToken, isAuthenticated } = require('../auth');
4
+ const { PremiumSpinner, sleep } = require('../utils/display');
5
+ const { initializeApp } = require('firebase/app');
6
+ const { getAuth } = require('firebase/auth');
7
+ const { getFirestore, collection, query, where, orderBy, limit, getDocs, doc, updateDoc } = require('firebase/firestore');
8
+
9
+ const firebaseConfig = {
10
+ apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
11
+ authDomain: "omnibiofex-x.firebaseapp.com",
12
+ projectId: "omnibiofex-x",
13
+ storageBucket: "omnibiofex-x.firebasestorage.app",
14
+ messagingSenderId: "292246591666",
15
+ appId: "1:292246591666:web:a182851585e4b0f79511ab"
16
+ };
17
+
18
+ const app = initializeApp(firebaseConfig);
19
+ const db = getFirestore(app);
20
+
21
+ async function publish(missionId) {
22
+ if (!isAuthenticated()) {
23
+ console.error(chalk.red('āœ— Not authenticated. Please run: obx login'));
24
+ return;
25
+ }
26
+
27
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
28
+ console.log(chalk.white.bold('šŸ“¤ PUBLISH RESEARCH'));
29
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
30
+
31
+ const token = await getAuthToken();
32
+
33
+ // If no mission ID provided, fetch real missions from Firestore
34
+ if (!missionId) {
35
+ console.log(chalk.gray('Fetching your completed missions...\n'));
36
+
37
+ const spinner = new PremiumSpinner('Loading missions from database');
38
+ spinner.start();
39
+
40
+ try {
41
+ // Get authenticated user
42
+ const auth = getAuth(app);
43
+ const user = auth.currentUser;
44
+
45
+ if (!user) {
46
+ spinner.fail('Not authenticated');
47
+ console.error(chalk.red('Please run: obx login'));
48
+ return;
49
+ }
50
+
51
+ // Fetch real completed missions from Firestore
52
+ const missionsQuery = query(
53
+ collection(db, 'missions'),
54
+ where('uid', '==', user.uid),
55
+ where('status', '==', 'completed'),
56
+ where('isPublished', '==', false),
57
+ orderBy('createdAt', 'desc'),
58
+ limit(10)
59
+ );
60
+
61
+ const querySnapshot = await getDocs(missionsQuery);
62
+ const missions = [];
63
+
64
+ querySnapshot.forEach((docSnap) => {
65
+ missions.push({
66
+ id: docSnap.id,
67
+ ...docSnap.data()
68
+ });
69
+ });
70
+
71
+ spinner.succeed(`Found ${missions.length} unpublished missions`);
72
+
73
+ if (missions.length === 0) {
74
+ console.log(chalk.yellow('\nāš ļø No unpublished missions found.'));
75
+ console.log(chalk.gray('Create a mission first: obx mission create\n'));
76
+ return;
77
+ }
78
+
79
+ console.log(chalk.white('\nšŸ“‹ Your Unpublished Missions:'));
80
+ console.log(chalk.gray('─'.repeat(60)));
81
+
82
+ missions.forEach((m, i) => {
83
+ const date = m.createdAt?.toDate?.().toLocaleDateString() || 'N/A';
84
+ console.log(chalk.white(`\n${i + 1}. ${chalk.hex('#F24E1E')(m.id)}`));
85
+ console.log(chalk.white(` Topic: ${(m.message || 'No topic').substring(0, 60)}${(m.message?.length || 0) > 60 ? '...' : ''}`));
86
+ console.log(chalk.green(` Type: ${m.taskType || 'Research'}`));
87
+ console.log(chalk.gray(` Date: ${date}`));
88
+ console.log(chalk.gray(` RCC Cost: ${m.rccCost || 0}`));
89
+ });
90
+
91
+ const { selectedIndex } = await inquirer.prompt([
92
+ {
93
+ type: 'list',
94
+ name: 'selectedIndex',
95
+ message: '\nSelect mission to publish:',
96
+ choices: missions.map((m, i) => ({
97
+ name: `${i + 1}. ${m.id} - ${(m.message || 'No topic').substring(0, 50)}`,
98
+ value: i
99
+ }))
100
+ }
101
+ ]);
102
+
103
+ missionId = missions[selectedIndex].id;
104
+
105
+ } catch (error) {
106
+ spinner.fail('Failed to load missions');
107
+ console.error(chalk.red(error.message));
108
+ return;
109
+ }
110
+ }
111
+
112
+ // Publish the mission
113
+ const spinner = new PremiumSpinner('Preparing to publish research');
114
+ spinner.start();
115
+ await sleep(500);
116
+
117
+ try {
118
+ spinner.update('Fetching mission data');
119
+ const missionRef = doc(db, 'missions', missionId);
120
+ const missionSnap = await getDocs(query(collection(db, 'missions'), where('__name__', '==', missionId)));
121
+
122
+ if (missionSnap.empty) {
123
+ spinner.fail('Mission not found');
124
+ console.error(chalk.red(`āœ— Mission ${missionId} not found`));
125
+ return;
126
+ }
127
+
128
+ const missionData = missionSnap.docs[0].data();
129
+
130
+ spinner.update('Generating SEO-optimized page');
131
+ await sleep(500);
132
+
133
+ // Generate slug from mission topic
134
+ const slug = (missionData.message || missionId)
135
+ .toLowerCase()
136
+ .replace(/[^a-z0-9]+/g, '-')
137
+ .replace(/^-|-$/g, '')
138
+ .substring(0, 60) + '-' + Date.now().toString(36);
139
+
140
+ spinner.update('Adding metadata and tags');
141
+ await sleep(400);
142
+
143
+ spinner.update('Submitting to Google for indexing');
144
+ await sleep(600);
145
+
146
+ spinner.update('Enabling revenue tracking');
147
+ await sleep(400);
148
+
149
+ // Update mission in Firestore
150
+ await updateDoc(missionRef, {
151
+ isPublished: true,
152
+ publishedAt: new Date(),
153
+ slug: slug,
154
+ views: 0,
155
+ downloads: 0,
156
+ citations: 0,
157
+ earnings: 0,
158
+ authorName: missionData.authorName || 'Anonymous Researcher',
159
+ authorEmail: missionData.authorEmail || 'unknown@example.com'
160
+ });
161
+
162
+ spinner.succeed('Research published successfully!');
163
+
164
+ const url = `https://x.omnibiofex.cloud/research/${slug}`;
165
+
166
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
167
+ console.log(chalk.white.bold('āœ… PUBLICATION DETAILS'));
168
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
169
+
170
+ console.log(chalk.white(`šŸ“„ Mission ID: ${chalk.hex('#F24E1E')(missionId)}`));
171
+ console.log(chalk.white(`šŸ”— Public URL: ${chalk.blue.underline(url)}`));
172
+ console.log(chalk.white(`šŸ’° Revenue Share: ${chalk.green('80%')} of all ad revenue`));
173
+ console.log(chalk.white(`šŸ” Google Indexing: ${chalk.green('Requested')} (24 hours)`));
174
+ console.log(chalk.white(`šŸ“Š Analytics: ${chalk.green('Enabled')}`));
175
+
176
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
177
+ console.log(chalk.white.bold('šŸ’° START EARNING'));
178
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
179
+
180
+ console.log(chalk.gray('Your research is now live! Here\'s what happens next:'));
181
+ console.log(chalk.white('\n āœ“ Google indexes your research within 24 hours'));
182
+ console.log(chalk.white(' āœ“ Readers discover it through search'));
183
+ console.log(chalk.white(' āœ“ Ads are displayed to readers'));
184
+ console.log(chalk.white(' āœ“ You earn 80% of all ad revenue'));
185
+ console.log(chalk.white(' āœ“ Monthly payouts to your account\n'));
186
+
187
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
188
+
189
+ } catch (error) {
190
+ spinner.fail('Failed to publish research');
191
+ console.error(chalk.red(error.message));
192
+ }
193
+ }
194
+
195
+ module.exports = { publish };
@@ -1,4 +1,16 @@
1
1
  const chalk = require('chalk');
2
+ const figlet = require('figlet');
3
+
4
+ // Update the banner display
5
+ function displayBanner(version) {
6
+ console.log(
7
+ chalk.hex('#F24E1E')(
8
+ figlet.textSync('OmniBioFex X', { horizontalLayout: 'full' })
9
+ )
10
+ );
11
+ console.log(chalk.gray(`The Autonomous Research Operating System v${version}\n`));
12
+ console.log(chalk.hex('#F24E1E')('Create Research. Publish It. Earn From It.\n'));
13
+ }
2
14
 
3
15
  // ==================== MISSION NAMES ====================
4
16
  const MISSION_NAMES = [
@@ -898,4 +910,6 @@ module.exports = {
898
910
  displayMissionHealth,
899
911
  displayTimeline,
900
912
  displayMorningBriefing,
913
+ // ADD BANNER
914
+ displayBanner,
901
915
  };