omnibiofex 2.8.5 → 4.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.
- package/bin/obx +30 -158
- package/package.json +13 -28
- package/src/auth.js +181 -381
- package/src/commands/account.js +35 -88
- package/src/commands/data.js +40 -114
- package/src/commands/debug.js +28 -25
- package/src/commands/earnings.js +31 -86
- package/src/commands/mission.js +194 -98
- package/src/commands/morning.js +39 -107
- package/src/commands/open.js +26 -36
- package/src/commands/publish.js +81 -126
- package/src/commands/research.js +148 -281
- package/src/commands/timeline.js +15 -54
- package/src/firebase.js +4 -14
- package/src/user.js +94 -0
- package/src/utils/display.js +27 -856
- package/src/api.js +0 -72
- package/src/config.js +0 -16
package/src/commands/account.js
CHANGED
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const open = require('open');
|
|
3
|
-
const { getAuthToken, isAuthenticated
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
const
|
|
3
|
+
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
+
const { PremiumSpinner } = require('../utils/display');
|
|
5
|
+
|
|
6
|
+
const GET_USER_DATA_URL = 'https://getuserdata-yyedhmslhq-uc.a.run.app';
|
|
7
7
|
|
|
8
8
|
async function credits() {
|
|
9
|
-
if (!isAuthenticated()) {
|
|
10
|
-
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
9
|
+
if (!isAuthenticated()) { console.error(chalk.red('✗ Not authenticated')); process.exit(1); return; }
|
|
13
10
|
|
|
14
11
|
const spinner = new PremiumSpinner('Fetching your credit balance');
|
|
15
12
|
spinner.start();
|
|
16
13
|
|
|
17
14
|
try {
|
|
18
15
|
const token = await getAuthToken();
|
|
19
|
-
|
|
20
16
|
const response = await fetch('https://getusercredits-yyedhmslhq-uc.a.run.app', {
|
|
21
17
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
22
18
|
});
|
|
23
|
-
|
|
19
|
+
if (!response.ok) throw new Error(`API returned ${response.status}`);
|
|
24
20
|
const data = await response.json();
|
|
25
21
|
const balance = data.tokens || 0;
|
|
26
22
|
|
|
27
23
|
spinner.succeed('Credits loaded');
|
|
28
|
-
|
|
29
24
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
30
25
|
console.log(chalk.white.bold('💰 RESEARCH FUEL (RCC)'));
|
|
31
26
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
32
|
-
|
|
33
27
|
console.log(chalk.white(` Current Balance: ${chalk.green(balance.toLocaleString() + ' RCC')}`));
|
|
34
28
|
console.log(chalk.white(` Status: ${balance > 100 ? chalk.green('✓ Healthy') : chalk.yellow('⚠ Low')}`));
|
|
35
29
|
|
|
@@ -37,100 +31,54 @@ async function credits() {
|
|
|
37
31
|
console.log(chalk.yellow('\n ⚠️ Your fuel is running low!'));
|
|
38
32
|
console.log(chalk.gray(' Run "obx buy" to purchase more credits\n'));
|
|
39
33
|
}
|
|
40
|
-
|
|
41
34
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
|
42
|
-
|
|
35
|
+
process.exit(0);
|
|
43
36
|
} catch (error) {
|
|
44
37
|
spinner.fail('Failed to fetch credits');
|
|
45
38
|
console.error(chalk.red(error.message));
|
|
39
|
+
process.exit(1);
|
|
46
40
|
}
|
|
47
41
|
}
|
|
48
42
|
|
|
49
43
|
async function usage() {
|
|
50
|
-
if (!isAuthenticated()) {
|
|
51
|
-
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Get user UID from stored token
|
|
56
|
-
const uid = getCurrentUserUid();
|
|
57
|
-
const email = getCurrentUserEmail();
|
|
58
|
-
|
|
59
|
-
if (!uid) {
|
|
60
|
-
console.error(chalk.red('✗ Could not extract user ID from token.'));
|
|
61
|
-
console.error(chalk.gray('Please run: obx login'));
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
44
|
+
if (!isAuthenticated()) { console.error(chalk.red('✗ Not authenticated')); process.exit(1); return; }
|
|
64
45
|
|
|
65
46
|
const spinner = new PremiumSpinner('Fetching usage statistics');
|
|
66
47
|
spinner.start();
|
|
67
48
|
|
|
68
49
|
try {
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
where('uid', '==', uid)
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const allMissionsSnapshot = await getDocs(allMissionsQuery);
|
|
76
|
-
const allMissions = [];
|
|
77
|
-
|
|
78
|
-
allMissionsSnapshot.forEach((docSnap) => {
|
|
79
|
-
allMissions.push({
|
|
80
|
-
id: docSnap.id,
|
|
81
|
-
...docSnap.data()
|
|
82
|
-
});
|
|
50
|
+
const token = await getAuthToken();
|
|
51
|
+
const response = await fetch(GET_USER_DATA_URL, {
|
|
52
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
83
53
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const totalMissions = allMissions.length;
|
|
87
|
-
const completedMissions = allMissions.filter(m => m.status === 'completed').length;
|
|
88
|
-
const activeMissions = allMissions.filter(m => m.status === 'running' || m.status === 'pending').length;
|
|
89
|
-
const publishedMissions = allMissions.filter(m => m.isPublished === true).length;
|
|
90
|
-
const totalRCCSpent = allMissions.reduce((sum, m) => sum + (m.rccCost || 0), 0);
|
|
91
|
-
|
|
92
|
-
// Fetch published missions for earnings
|
|
93
|
-
const publishedQuery = query(
|
|
94
|
-
collection(db, 'missions'),
|
|
95
|
-
where('uid', '==', uid),
|
|
96
|
-
where('isPublished', '==', true)
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const publishedSnapshot = await getDocs(publishedQuery);
|
|
100
|
-
const publishedMissionsData = [];
|
|
54
|
+
if (!response.ok) throw new Error(`Backend error: ${response.status}`);
|
|
55
|
+
const userData = await response.json();
|
|
101
56
|
|
|
102
|
-
publishedSnapshot.forEach((docSnap) => {
|
|
103
|
-
publishedMissionsData.push({
|
|
104
|
-
id: docSnap.id,
|
|
105
|
-
...docSnap.data()
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const totalViews = publishedMissionsData.reduce((sum, m) => sum + (m.views || 0), 0);
|
|
110
|
-
const totalEarnings = publishedMissionsData.reduce((sum, m) => sum + (m.earnings || 0), 0);
|
|
111
|
-
|
|
112
57
|
spinner.succeed('Usage statistics loaded');
|
|
113
|
-
|
|
58
|
+
|
|
114
59
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
115
60
|
console.log(chalk.white.bold('📊 USAGE STATISTICS'));
|
|
116
61
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
117
|
-
|
|
118
|
-
console.log(chalk.gray(`
|
|
119
|
-
console.log(chalk.
|
|
120
|
-
|
|
121
|
-
console.log(chalk.white(
|
|
122
|
-
console.log(chalk.white(`
|
|
123
|
-
console.log(chalk.white(`
|
|
124
|
-
console.log(chalk.white(`
|
|
125
|
-
console.log(chalk.white(`
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
62
|
+
console.log(chalk.gray(` 👤 User: ${chalk.white(userData.user.name || userData.user.email)}`));
|
|
63
|
+
console.log(chalk.gray(` 🆔 UID: ${chalk.gray(userData.uid.substring(0, 16))}...`));
|
|
64
|
+
console.log(chalk.white(`\n 🎯 Total Missions: ${chalk.green(userData.stats.totalMissions)}`));
|
|
65
|
+
console.log(chalk.white(` ✅ Completed: ${chalk.green(userData.stats.completed)}`));
|
|
66
|
+
console.log(chalk.white(` ⏳ Active: ${chalk.yellow(userData.stats.active)}`));
|
|
67
|
+
console.log(chalk.white(` ⛽ RCC Spent: ${chalk.green(userData.stats.totalRCC.toLocaleString())}`));
|
|
68
|
+
console.log(chalk.white(` 📤 Published: ${chalk.green(userData.stats.published)}`));
|
|
69
|
+
console.log(chalk.white(` 👁 Total Views: ${chalk.green(userData.stats.totalViews.toLocaleString())}`));
|
|
70
|
+
console.log(chalk.white(` 💰 Total Earnings: ${chalk.green('₹' + userData.stats.totalEarnings.toLocaleString())}`));
|
|
71
|
+
|
|
72
|
+
if (userData.stats.totalMissions === 0) {
|
|
73
|
+
console.log(chalk.yellow('\n ℹ️ No missions yet. Create your first:'));
|
|
74
|
+
console.log(chalk.gray(' obx mission create\n'));
|
|
75
|
+
}
|
|
129
76
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
|
130
|
-
|
|
77
|
+
process.exit(0);
|
|
131
78
|
} catch (error) {
|
|
132
79
|
spinner.fail('Failed to fetch usage statistics');
|
|
133
80
|
console.error(chalk.red(error.message));
|
|
81
|
+
process.exit(1);
|
|
134
82
|
}
|
|
135
83
|
}
|
|
136
84
|
|
|
@@ -138,17 +86,16 @@ async function buy() {
|
|
|
138
86
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
139
87
|
console.log(chalk.white.bold('💳 PURCHASE RESEARCH FUEL'));
|
|
140
88
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
141
|
-
|
|
142
|
-
console.log(chalk.gray('Opening pricing page in your browser...\n'));
|
|
89
|
+
console.log(chalk.gray('Opening pricing page...\n'));
|
|
143
90
|
|
|
144
91
|
try {
|
|
145
92
|
await open('https://x.omnibiofex.cloud/pricing');
|
|
146
93
|
console.log(chalk.green('✓ Opened pricing page\n'));
|
|
147
|
-
|
|
148
|
-
console.log(chalk.gray('All plans include 80%+ revenue share on published research.\n'));
|
|
94
|
+
process.exit(0);
|
|
149
95
|
} catch (error) {
|
|
150
96
|
console.error(chalk.red('✗ Failed to open browser'));
|
|
151
|
-
console.log(chalk.gray('\
|
|
97
|
+
console.log(chalk.gray('\nVisit: https://x.omnibiofex.cloud/pricing\n'));
|
|
98
|
+
process.exit(1);
|
|
152
99
|
}
|
|
153
100
|
}
|
|
154
101
|
|
package/src/commands/data.js
CHANGED
|
@@ -1,169 +1,95 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
3
4
|
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
-
const { PremiumSpinner,
|
|
5
|
+
const { PremiumSpinner, typeAIResponse } = require('../utils/display');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
if (!isAuthenticated()) {
|
|
8
|
-
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
7
|
+
const BACKEND_URL = 'https://obxvisionassistant-yyedhmslhq-uc.a.run.app';
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
9
|
+
async function dataset(file) {
|
|
10
|
+
if (!isAuthenticated()) { console.error(chalk.red('✗ Not authenticated')); process.exit(1); return; }
|
|
11
|
+
if (!fs.existsSync(file)) { console.error(chalk.red(`✗ File not found: ${file}`)); process.exit(1); return; }
|
|
16
12
|
|
|
17
13
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
18
14
|
console.log(chalk.white.bold('📊 DATASET ANALYSIS'));
|
|
19
15
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
20
|
-
|
|
21
16
|
console.log(chalk.white(` 📄 File: ${chalk.hex('#F24E1E')(file)}`));
|
|
22
17
|
|
|
23
|
-
const spinner = new PremiumSpinner('✨
|
|
18
|
+
const spinner = new PremiumSpinner('✨ Analyzing dataset');
|
|
24
19
|
spinner.start();
|
|
25
|
-
await sleep(500);
|
|
26
20
|
|
|
27
21
|
try {
|
|
28
22
|
const token = await getAuthToken();
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
spinner.update(
|
|
32
|
-
await sleep(600);
|
|
33
|
-
|
|
34
|
-
spinner.update('🔍 Detecting patterns');
|
|
35
|
-
await sleep(600);
|
|
36
|
-
|
|
37
|
-
spinner.update('📈 Calculating statistics');
|
|
38
|
-
await sleep(600);
|
|
39
|
-
|
|
40
|
-
spinner.update('⚠️ Checking for anomalies');
|
|
41
|
-
await sleep(400);
|
|
23
|
+
const content = fs.readFileSync(file, 'utf8').substring(0, 5000);
|
|
24
|
+
const steps = ['📊 Analyzing...', '🔍 Detecting patterns...', '📈 Calculating statistics...', '⚠️ Checking anomalies...'];
|
|
25
|
+
for (const s of steps) { spinner.update(s); await new Promise(r => setTimeout(r, 600)); }
|
|
42
26
|
|
|
43
|
-
const response = await fetch(
|
|
27
|
+
const response = await fetch(BACKEND_URL, {
|
|
44
28
|
method: 'POST',
|
|
45
|
-
headers: {
|
|
46
|
-
|
|
47
|
-
'Authorization': `Bearer ${token}`
|
|
48
|
-
},
|
|
49
|
-
body: JSON.stringify({
|
|
50
|
-
taskType: 'DATASET_ANALYSIS',
|
|
51
|
-
message: fileContent,
|
|
52
|
-
model: 'deep'
|
|
53
|
-
})
|
|
29
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
|
|
30
|
+
body: JSON.stringify({ taskType: 'DATASET_SMALL', message: content, model: 'deep' })
|
|
54
31
|
});
|
|
55
|
-
|
|
56
|
-
if (!response.ok) {
|
|
57
|
-
const errorData = await response.json();
|
|
58
|
-
throw new Error(errorData.error || 'Failed to analyze dataset');
|
|
59
|
-
}
|
|
60
|
-
|
|
32
|
+
if (!response.ok) throw new Error(`Backend error: ${response.status}`);
|
|
61
33
|
const data = await response.json();
|
|
62
34
|
|
|
63
35
|
spinner.succeed('✓ Dataset analysis complete (40-150 RCC)');
|
|
64
|
-
|
|
65
|
-
await typeAIResponse(data.response || 'Analysis data not available.');
|
|
66
|
-
|
|
67
|
-
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
68
|
-
console.log(chalk.white.bold('📦 ARTIFACTS GENERATED'));
|
|
69
|
-
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
70
|
-
|
|
71
|
-
console.log(chalk.green(' ✓ Statistical Summary'));
|
|
36
|
+
console.log(chalk.green('\n ✓ Statistical Summary'));
|
|
72
37
|
console.log(chalk.green(' ✓ Pattern Report'));
|
|
73
|
-
console.log(chalk.green(' ✓ Anomaly Detection'));
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
38
|
+
console.log(chalk.green(' ✓ Anomaly Detection\n'));
|
|
39
|
+
await typeAIResponse(data.response || 'Analysis not available.');
|
|
40
|
+
process.exit(0);
|
|
77
41
|
} catch (error) {
|
|
78
|
-
spinner.fail('Failed
|
|
42
|
+
spinner.fail('Failed');
|
|
79
43
|
console.error(chalk.red(error.message));
|
|
44
|
+
process.exit(1);
|
|
80
45
|
}
|
|
81
46
|
}
|
|
82
47
|
|
|
83
48
|
async function code(directory = '.') {
|
|
84
|
-
if (!isAuthenticated()) {
|
|
85
|
-
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!fs.existsSync(directory)) {
|
|
90
|
-
console.error(chalk.red(`✗ Directory not found: ${directory}`));
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
49
|
+
if (!isAuthenticated()) { console.error(chalk.red('✗ Not authenticated')); process.exit(1); return; }
|
|
50
|
+
if (!fs.existsSync(directory)) { console.error(chalk.red(`✗ Not found: ${directory}`)); process.exit(1); return; }
|
|
93
51
|
|
|
94
52
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
95
53
|
console.log(chalk.white.bold('💻 CODE REVIEW'));
|
|
96
54
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
97
|
-
|
|
98
55
|
console.log(chalk.white(` 📂 Directory: ${chalk.hex('#F24E1E')(directory)}`));
|
|
99
56
|
|
|
100
|
-
const spinner = new PremiumSpinner('✨
|
|
57
|
+
const spinner = new PremiumSpinner('✨ Reviewing code');
|
|
101
58
|
spinner.start();
|
|
102
|
-
await sleep(500);
|
|
103
59
|
|
|
104
60
|
try {
|
|
105
61
|
const token = await getAuthToken();
|
|
106
|
-
|
|
107
|
-
spinner.update('📂 Scanning repository');
|
|
108
|
-
await sleep(600);
|
|
109
|
-
|
|
110
|
-
spinner.update('🔍 Analyzing architecture');
|
|
111
|
-
await sleep(600);
|
|
112
|
-
|
|
113
|
-
spinner.update('🔐 Security audit');
|
|
114
|
-
await sleep(600);
|
|
115
|
-
|
|
116
|
-
spinner.update('⚡ Performance review');
|
|
117
|
-
await sleep(400);
|
|
118
|
-
|
|
119
|
-
// Read code files (limit to 5000 chars)
|
|
120
62
|
let codeContent = '';
|
|
121
63
|
const files = fs.readdirSync(directory);
|
|
122
64
|
for (const file of files.slice(0, 10)) {
|
|
123
65
|
const filePath = path.join(directory, file);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
66
|
+
try {
|
|
67
|
+
if (fs.statSync(filePath).isFile() && file.match(/\.(js|ts|py|java|cpp|go|rs)$/)) {
|
|
68
|
+
codeContent += `\n// File: ${file}\n` + fs.readFileSync(filePath, 'utf8').substring(0, 1000);
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {}
|
|
128
71
|
}
|
|
72
|
+
const steps = ['📂 Scanning...', '🔍 Analyzing...', '🔐 Security audit...', '⚡ Performance...'];
|
|
73
|
+
for (const s of steps) { spinner.update(s); await new Promise(r => setTimeout(r, 600)); }
|
|
129
74
|
|
|
130
|
-
const response = await fetch(
|
|
75
|
+
const response = await fetch(BACKEND_URL, {
|
|
131
76
|
method: 'POST',
|
|
132
|
-
headers: {
|
|
133
|
-
|
|
134
|
-
'Authorization': `Bearer ${token}`
|
|
135
|
-
},
|
|
136
|
-
body: JSON.stringify({
|
|
137
|
-
taskType: 'CODE_REVIEW',
|
|
138
|
-
message: codeContent,
|
|
139
|
-
model: 'deep'
|
|
140
|
-
})
|
|
77
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
|
|
78
|
+
body: JSON.stringify({ taskType: 'CODE_REVIEW_SMALL', message: codeContent, model: 'deep' })
|
|
141
79
|
});
|
|
142
|
-
|
|
143
|
-
if (!response.ok) {
|
|
144
|
-
const errorData = await response.json();
|
|
145
|
-
throw new Error(errorData.error || 'Failed to review code');
|
|
146
|
-
}
|
|
147
|
-
|
|
80
|
+
if (!response.ok) throw new Error(`Backend error: ${response.status}`);
|
|
148
81
|
const data = await response.json();
|
|
149
82
|
|
|
150
83
|
spinner.succeed('✓ Code review complete (40-300 RCC)');
|
|
151
|
-
|
|
152
|
-
await typeAIResponse(data.response || 'Review data not available.');
|
|
153
|
-
|
|
154
|
-
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
155
|
-
console.log(chalk.white.bold('📦 ARTIFACTS GENERATED'));
|
|
156
|
-
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
157
|
-
|
|
158
|
-
console.log(chalk.green(' ✓ Architecture Report'));
|
|
84
|
+
console.log(chalk.green('\n ✓ Architecture Report'));
|
|
159
85
|
console.log(chalk.green(' ✓ Security Audit'));
|
|
160
|
-
console.log(chalk.green(' ✓ Optimization Suggestions'));
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
86
|
+
console.log(chalk.green(' ✓ Optimization Suggestions\n'));
|
|
87
|
+
await typeAIResponse(data.response || 'Review not available.');
|
|
88
|
+
process.exit(0);
|
|
164
89
|
} catch (error) {
|
|
165
|
-
spinner.fail('Failed
|
|
90
|
+
spinner.fail('Failed');
|
|
166
91
|
console.error(chalk.red(error.message));
|
|
92
|
+
process.exit(1);
|
|
167
93
|
}
|
|
168
94
|
}
|
|
169
95
|
|
package/src/commands/debug.js
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const
|
|
2
|
+
const user = require('../user');
|
|
3
3
|
const { isAuthenticated } = require('../auth');
|
|
4
4
|
|
|
5
5
|
async function debug() {
|
|
6
|
-
console.log(chalk.hex('#F24E1E')('\n
|
|
7
|
-
|
|
8
|
-
console.log(chalk.
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
7
|
+
console.log(chalk.white.bold('🔍 DEBUG INFORMATION'));
|
|
8
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
9
|
+
|
|
10
|
+
const authenticated = isAuthenticated();
|
|
11
|
+
console.log(chalk.white(` Authentication: ${authenticated ? chalk.green('✓ Logged in (Google)') : chalk.red('✗ Not logged in')}`));
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
console.log(chalk.gray(' Contains +:'), token.includes('+') ? chalk.yellow('Yes') : chalk.green('No'));
|
|
19
|
-
console.log(chalk.gray(' Valid JWT format:'), token.startsWith('eyJ') ? chalk.green('Yes') : chalk.red('No'));
|
|
13
|
+
if (authenticated) {
|
|
14
|
+
const email = user.getCurrentUserEmail();
|
|
15
|
+
const uid = user.getCurrentUserUid();
|
|
16
|
+
const name = user.getCurrentUserName();
|
|
17
|
+
const token = user.getToken();
|
|
18
|
+
const expired = user.isTokenExpired();
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
console.log(chalk.white(`\n 👤 Name: ${chalk.green(name || 'Unknown')}`));
|
|
21
|
+
console.log(chalk.white(` 📧 Email: ${chalk.green(email || 'Unknown')}`));
|
|
22
|
+
console.log(chalk.white(` 🆔 UID: ${chalk.gray(uid || 'Unknown')}`));
|
|
23
|
+
console.log(chalk.white(` 🔑 Token Length: ${chalk.gray(token ? token.length + ' chars' : 'N/A')}`));
|
|
24
|
+
console.log(chalk.white(` ⏰ Token Expired: ${expired ? chalk.red('Yes') : chalk.green('No')}`));
|
|
25
|
+
|
|
26
|
+
if (token) {
|
|
27
|
+
const decoded = user.decodeToken();
|
|
28
|
+
if (decoded) {
|
|
29
|
+
const expDate = new Date(decoded.exp * 1000);
|
|
30
|
+
console.log(chalk.white(` 📅 Token Expires: ${chalk.gray(expDate.toLocaleString())}`));
|
|
31
|
+
}
|
|
26
32
|
}
|
|
27
33
|
} else {
|
|
28
|
-
console.log(chalk.yellow('\
|
|
34
|
+
console.log(chalk.yellow('\n Please run: obx login\n'));
|
|
29
35
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.log(chalk.gray(' Windows: %APPDATA%\\omnibiofex\\config.json'));
|
|
33
|
-
console.log(chalk.gray(' macOS: ~/Library/Preferences/omnibiofex-nodejs/config.json'));
|
|
34
|
-
console.log(chalk.gray(' Linux: ~/.config/omnibiofex-nodejs/config.json'));
|
|
36
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
|
37
|
+
process.exit(0);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
module.exports = { debug };
|
package/src/commands/earnings.js
CHANGED
|
@@ -1,121 +1,66 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const {
|
|
3
|
-
const {
|
|
4
|
-
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
5
|
-
const { collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
|
|
2
|
+
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
3
|
+
const { PremiumSpinner } = require('../utils/display');
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
if (!isAuthenticated()) {
|
|
9
|
-
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
5
|
+
const GET_USER_DATA_URL = 'https://getuserdata-yyedhmslhq-uc.a.run.app';
|
|
12
6
|
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
async function earnings() {
|
|
8
|
+
if (!isAuthenticated()) { console.error(chalk.red('✗ Not authenticated')); process.exit(1); return; }
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
console.error(chalk.red('✗ Could not extract user ID from token.'));
|
|
18
|
-
console.error(chalk.gray('Please run: obx login'));
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const spinner = new PremiumSpinner('Fetching your earnings data');
|
|
10
|
+
const spinner = new PremiumSpinner('Fetching earnings data');
|
|
23
11
|
spinner.start();
|
|
24
12
|
|
|
25
13
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
where('isPublished', '==', true),
|
|
30
|
-
orderBy('publishedAt', 'desc'),
|
|
31
|
-
limit(100)
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const querySnapshot = await getDocs(publishedQuery);
|
|
35
|
-
const publishedMissions = [];
|
|
36
|
-
|
|
37
|
-
querySnapshot.forEach((docSnap) => {
|
|
38
|
-
publishedMissions.push({
|
|
39
|
-
id: docSnap.id,
|
|
40
|
-
...docSnap.data()
|
|
41
|
-
});
|
|
14
|
+
const token = await getAuthToken();
|
|
15
|
+
const response = await fetch(GET_USER_DATA_URL, {
|
|
16
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
42
17
|
});
|
|
43
|
-
|
|
18
|
+
if (!response.ok) throw new Error(`Backend error: ${response.status}`);
|
|
19
|
+
const userData = await response.json();
|
|
20
|
+
|
|
44
21
|
spinner.succeed('Earnings data loaded');
|
|
45
|
-
|
|
46
|
-
const totalViews = publishedMissions.reduce((sum, m) => sum + (m.views || 0), 0);
|
|
47
|
-
const totalDownloads = publishedMissions.reduce((sum, m) => sum + (m.downloads || 0), 0);
|
|
48
|
-
const totalCitations = publishedMissions.reduce((sum, m) => sum + (m.citations || 0), 0);
|
|
49
|
-
const totalEarnings = publishedMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
|
|
50
22
|
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
const thisYear = now.getFullYear();
|
|
54
|
-
const lastMonth = thisMonth === 0 ? 11 : thisMonth - 1;
|
|
55
|
-
const lastMonthYear = thisMonth === 0 ? thisYear - 1 : thisYear;
|
|
56
|
-
|
|
57
|
-
const thisMonthMissions = publishedMissions.filter(m => {
|
|
58
|
-
const publishedDate = m.publishedAt?.toDate?.();
|
|
59
|
-
return publishedDate && publishedDate.getMonth() === thisMonth && publishedDate.getFullYear() === thisYear;
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const lastMonthMissions = publishedMissions.filter(m => {
|
|
63
|
-
const publishedDate = m.publishedAt?.toDate?.();
|
|
64
|
-
return publishedDate && publishedDate.getMonth() === lastMonth && publishedDate.getFullYear() === lastMonthYear;
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const thisMonthEarnings = thisMonthMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
|
|
68
|
-
const thisMonthViews = thisMonthMissions.reduce((sum, m) => sum + (m.views || 0), 0);
|
|
69
|
-
const lastMonthEarnings = lastMonthMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
|
|
70
|
-
|
|
23
|
+
const published = userData.missions.filter(m => m.isPublished === true);
|
|
24
|
+
|
|
71
25
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
72
26
|
console.log(chalk.white.bold('💰 EARNINGS DASHBOARD'));
|
|
73
27
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
28
|
+
console.log(chalk.gray(` 👤 User: ${chalk.white(userData.user.name || userData.user.email)}`));
|
|
74
29
|
|
|
75
|
-
console.log(chalk.gray(` 👤 User: ${chalk.white(email || 'Unknown')}`));
|
|
76
|
-
|
|
77
30
|
console.log(chalk.white.bold('\n\n📊 OVERVIEW'));
|
|
78
31
|
console.log(chalk.gray('─'.repeat(60)));
|
|
79
|
-
console.log(chalk.white(`\n 💰 Total Earnings: ${chalk.green('₹' + totalEarnings.toLocaleString())}`));
|
|
80
|
-
console.log(chalk.white(`
|
|
81
|
-
|
|
82
|
-
console.log(chalk.white(` 📄 Published Research: ${chalk.green(publishedMissions.length)}`));
|
|
83
|
-
|
|
32
|
+
console.log(chalk.white(`\n 💰 Total Earnings: ${chalk.green('₹' + userData.stats.totalEarnings.toLocaleString())}`));
|
|
33
|
+
console.log(chalk.white(` 📄 Published Research: ${chalk.green(published.length)}`));
|
|
34
|
+
|
|
84
35
|
console.log(chalk.white.bold('\n\n📈 TRAFFIC METRICS'));
|
|
85
36
|
console.log(chalk.gray('─'.repeat(60)));
|
|
86
|
-
console.log(chalk.white(`\n 👁 Total Views: ${chalk.green(totalViews.toLocaleString())}`));
|
|
87
|
-
console.log(chalk.white(`
|
|
88
|
-
console.log(chalk.white(`
|
|
89
|
-
console.log(chalk.white(` 📚 Total Citations: ${chalk.green(totalCitations.toLocaleString())}`));
|
|
37
|
+
console.log(chalk.white(`\n 👁 Total Views: ${chalk.green(userData.stats.totalViews.toLocaleString())}`));
|
|
38
|
+
console.log(chalk.white(` 💾 Total Downloads: ${chalk.green(userData.stats.totalDownloads.toLocaleString())}`));
|
|
39
|
+
console.log(chalk.white(` 📚 Total Citations: ${chalk.green(userData.stats.totalCitations.toLocaleString())}`));
|
|
90
40
|
|
|
91
|
-
if (
|
|
92
|
-
const averagePerView = totalEarnings / totalViews;
|
|
93
|
-
console.log(chalk.white(` 💵 Average Per View: ${chalk.green('₹' + averagePerView.toFixed(3))}`));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (publishedMissions.length > 0) {
|
|
41
|
+
if (published.length > 0) {
|
|
97
42
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
98
43
|
console.log(chalk.white.bold('📊 YOUR PUBLISHED RESEARCH'));
|
|
99
44
|
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
45
|
+
|
|
46
|
+
published.slice(0, 10).forEach((m, i) => {
|
|
47
|
+
const date = m.publishedAt ? new Date(m.publishedAt).toLocaleDateString() : 'N/A';
|
|
103
48
|
console.log(chalk.white(`\n ${i + 1}. ${chalk.hex('#F24E1E')(m.id)}`));
|
|
104
|
-
console.log(chalk.white(` Topic: ${(m.message || '
|
|
49
|
+
console.log(chalk.white(` Topic: ${(m.message || '').substring(0, 50)}`));
|
|
105
50
|
console.log(chalk.white(` 👁 Views: ${chalk.green((m.views || 0).toLocaleString())}`));
|
|
106
51
|
console.log(chalk.white(` 💰 Earnings: ${chalk.green('₹' + (m.earnings || 0).toLocaleString())}`));
|
|
107
|
-
console.log(chalk.gray(` 📅 Published: ${
|
|
52
|
+
console.log(chalk.gray(` 📅 Published: ${date}`));
|
|
108
53
|
});
|
|
109
54
|
} else {
|
|
110
55
|
console.log(chalk.yellow('\n\n ⚠️ No published research yet.'));
|
|
111
|
-
console.log(chalk.gray(' Run "obx publish" to publish your first research
|
|
56
|
+
console.log(chalk.gray(' Run "obx publish" to publish your first research.\n'));
|
|
112
57
|
}
|
|
113
|
-
|
|
114
58
|
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
|
115
|
-
|
|
59
|
+
process.exit(0);
|
|
116
60
|
} catch (error) {
|
|
117
|
-
spinner.fail('Failed to fetch earnings
|
|
61
|
+
spinner.fail('Failed to fetch earnings');
|
|
118
62
|
console.error(chalk.red(error.message));
|
|
63
|
+
process.exit(1);
|
|
119
64
|
}
|
|
120
65
|
}
|
|
121
66
|
|