omnibiofex 2.8.3 ā 2.8.5
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 +20 -8
- package/package.json +1 -1
- package/src/auth.js +62 -1
- package/src/commands/account.js +2 -11
- package/src/commands/data.js +109 -209
- package/src/commands/earnings.js +2 -21
- package/src/commands/morning.js +131 -74
- package/src/commands/publish.js +3 -22
- package/src/commands/timeline.js +64 -125
- package/src/firebase.js +4 -74
package/bin/obx
CHANGED
|
@@ -105,8 +105,17 @@ program
|
|
|
105
105
|
.argument('<topic>', 'Research topic')
|
|
106
106
|
.action(hypothesis);
|
|
107
107
|
|
|
108
|
+
// ==================== TIMELINE COMMAND ====================
|
|
109
|
+
const { timeline } = require('../src/commands/timeline');
|
|
110
|
+
|
|
111
|
+
program
|
|
112
|
+
.command('timeline')
|
|
113
|
+
.description('š
Generate visual research timeline')
|
|
114
|
+
.argument('<topic>', 'Research topic')
|
|
115
|
+
.action(timeline);
|
|
116
|
+
|
|
108
117
|
// ==================== DATA COMMANDS ====================
|
|
109
|
-
const { dataset, code
|
|
118
|
+
const { dataset, code } = require('../src/commands/data');
|
|
110
119
|
|
|
111
120
|
program
|
|
112
121
|
.command('dataset')
|
|
@@ -120,12 +129,6 @@ program
|
|
|
120
129
|
.argument('[directory]', 'Directory path', '.')
|
|
121
130
|
.action(code);
|
|
122
131
|
|
|
123
|
-
program
|
|
124
|
-
.command('medical')
|
|
125
|
-
.description('Analyze medical imaging')
|
|
126
|
-
.argument('<file>', 'DICOM/image file path')
|
|
127
|
-
.action(medical);
|
|
128
|
-
|
|
129
132
|
// ==================== PUBLISH & EARN COMMANDS ====================
|
|
130
133
|
const { publish } = require('../src/commands/publish');
|
|
131
134
|
const { earnings } = require('../src/commands/earnings');
|
|
@@ -141,6 +144,14 @@ program
|
|
|
141
144
|
.description('š° View your earnings dashboard')
|
|
142
145
|
.action(earnings);
|
|
143
146
|
|
|
147
|
+
// ==================== MORNING COMMAND ====================
|
|
148
|
+
const { morning } = require('../src/commands/morning');
|
|
149
|
+
|
|
150
|
+
program
|
|
151
|
+
.command('morning')
|
|
152
|
+
.description('āļø Get daily research briefing')
|
|
153
|
+
.action(morning);
|
|
154
|
+
|
|
144
155
|
// ==================== OPEN COMMANDS ====================
|
|
145
156
|
const { openPage } = require('../src/commands/open');
|
|
146
157
|
|
|
@@ -150,7 +161,6 @@ program
|
|
|
150
161
|
.argument('[page]', 'Page to open (dashboard, earn, pricing, agents, etc.)')
|
|
151
162
|
.action(openPage);
|
|
152
163
|
|
|
153
|
-
// Shortcut commands
|
|
154
164
|
program
|
|
155
165
|
.command('dashboard')
|
|
156
166
|
.description('š Open web dashboard')
|
|
@@ -194,9 +204,11 @@ program.parse(process.argv);
|
|
|
194
204
|
if (!process.argv.slice(2).length) {
|
|
195
205
|
console.log(chalk.hex('#F24E1E')('\nš QUICK START:\n'));
|
|
196
206
|
console.log(chalk.white(' obx login # Authenticate'));
|
|
207
|
+
console.log(chalk.white(' obx morning # Daily briefing'));
|
|
197
208
|
console.log(chalk.white(' obx mission create # Create research'));
|
|
198
209
|
console.log(chalk.white(' obx publish <mission-id> # Publish & earn'));
|
|
199
210
|
console.log(chalk.white(' obx earnings # View earnings'));
|
|
211
|
+
console.log(chalk.white(' obx timeline <topic> # Generate timeline'));
|
|
200
212
|
console.log(chalk.white(' obx open # Open web pages\n'));
|
|
201
213
|
console.log(chalk.gray(' Run "obx --help" for all commands\n'));
|
|
202
214
|
}
|
package/package.json
CHANGED
package/src/auth.js
CHANGED
|
@@ -351,4 +351,65 @@ async function getAuthToken() {
|
|
|
351
351
|
return token;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
|
|
354
|
+
// ==================== USER EXTRACTION FUNCTIONS ====================
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Decode base64url to string (handles JWT format)
|
|
358
|
+
*/
|
|
359
|
+
function base64UrlDecode(str) {
|
|
360
|
+
let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
361
|
+
while (base64.length % 4) {
|
|
362
|
+
base64 += '=';
|
|
363
|
+
}
|
|
364
|
+
return Buffer.from(base64, 'base64').toString('utf8');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Decode JWT token to extract user info
|
|
369
|
+
*/
|
|
370
|
+
function decodeToken() {
|
|
371
|
+
const token = config.get('authToken'); // fixed key name
|
|
372
|
+
if (!token) return null;
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
const parts = token.split('.');
|
|
376
|
+
if (parts.length !== 3) return null;
|
|
377
|
+
|
|
378
|
+
const payload = parts[1];
|
|
379
|
+
const decoded = base64UrlDecode(payload);
|
|
380
|
+
const data = JSON.parse(decoded);
|
|
381
|
+
|
|
382
|
+
return {
|
|
383
|
+
uid: data.user_id || data.sub,
|
|
384
|
+
email: data.email,
|
|
385
|
+
exp: data.exp
|
|
386
|
+
};
|
|
387
|
+
} catch (error) {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Get current user UID from stored token
|
|
394
|
+
*/
|
|
395
|
+
function getCurrentUserUid() {
|
|
396
|
+
const decoded = decodeToken();
|
|
397
|
+
return decoded ? decoded.uid : null;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Get current user email from stored token
|
|
402
|
+
*/
|
|
403
|
+
function getCurrentUserEmail() {
|
|
404
|
+
const decoded = decodeToken();
|
|
405
|
+
return decoded ? decoded.email : null;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
module.exports = {
|
|
409
|
+
login,
|
|
410
|
+
logout,
|
|
411
|
+
getAuthToken,
|
|
412
|
+
isAuthenticated,
|
|
413
|
+
getCurrentUserUid,
|
|
414
|
+
getCurrentUserEmail
|
|
415
|
+
};
|
package/src/commands/account.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const open = require('open');
|
|
3
|
-
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
-
const { db
|
|
3
|
+
const { getAuthToken, isAuthenticated, getCurrentUserUid, getCurrentUserEmail } = require('../auth');
|
|
4
|
+
const { db } = require('../firebase');
|
|
5
5
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
6
6
|
const { collection, query, where, getDocs } = require('firebase/firestore');
|
|
7
7
|
|
|
@@ -33,15 +33,6 @@ async function credits() {
|
|
|
33
33
|
console.log(chalk.white(` Current Balance: ${chalk.green(balance.toLocaleString() + ' RCC')}`));
|
|
34
34
|
console.log(chalk.white(` Status: ${balance > 100 ? chalk.green('ā Healthy') : chalk.yellow('ā Low')}`));
|
|
35
35
|
|
|
36
|
-
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
37
|
-
console.log(chalk.white.bold('š WHAT YOU CAN DO'));
|
|
38
|
-
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
39
|
-
|
|
40
|
-
console.log(chalk.white(` š Literature Reviews: ${chalk.green(Math.floor(balance / 100))}`));
|
|
41
|
-
console.log(chalk.white(` š Paper Analyses: ${chalk.green(Math.floor(balance / 40))}`));
|
|
42
|
-
console.log(chalk.white(` š Quick Searches: ${chalk.green(Math.floor(balance / 10))}`));
|
|
43
|
-
console.log(chalk.white(` š§Ŗ Gap Discoveries: ${chalk.green(Math.floor(balance / 120))}`));
|
|
44
|
-
|
|
45
36
|
if (balance < 500) {
|
|
46
37
|
console.log(chalk.yellow('\n ā ļø Your fuel is running low!'));
|
|
47
38
|
console.log(chalk.gray(' Run "obx buy" to purchase more credits\n'));
|
package/src/commands/data.js
CHANGED
|
@@ -1,38 +1,8 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const fs = require('fs');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const { createMission } = require('../api');
|
|
6
|
-
const { isAuthenticated } = require('../auth');
|
|
7
|
-
const {
|
|
8
|
-
generateMissionName,
|
|
9
|
-
displayMissionDashboard,
|
|
10
|
-
displayResearchScore,
|
|
11
|
-
displayArtifacts,
|
|
12
|
-
generateResearchScore,
|
|
13
|
-
generateArtifacts,
|
|
14
|
-
typeAIResponse,
|
|
15
|
-
PremiumSpinner,
|
|
16
|
-
sleep,
|
|
17
|
-
animateResearchSources
|
|
18
|
-
} = require('../utils/display');
|
|
19
|
-
|
|
20
|
-
const REPORTS_DIR = path.join(os.homedir(), 'obx-reports');
|
|
21
|
-
if (!fs.existsSync(REPORTS_DIR)) {
|
|
22
|
-
fs.mkdirSync(REPORTS_DIR, { recursive: true });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function saveReport(topic, content, missionName) {
|
|
26
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
27
|
-
const sanitizedTopic = topic.replace(/[^a-z0-9]/gi, '_').substring(0, 50);
|
|
28
|
-
const filename = `${missionName.replace(/\s+/g, '_')}_${timestamp}.md`;
|
|
29
|
-
const filepath = path.join(REPORTS_DIR, filename);
|
|
30
|
-
|
|
31
|
-
fs.writeFileSync(filepath, content, 'utf8');
|
|
32
|
-
return filepath;
|
|
33
|
-
}
|
|
3
|
+
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
+
const { PremiumSpinner, sleep, typeAIResponse } = require('../utils/display');
|
|
34
5
|
|
|
35
|
-
// ==================== DATASET ANALYSIS ====================
|
|
36
6
|
async function dataset(file) {
|
|
37
7
|
if (!isAuthenticated()) {
|
|
38
8
|
console.error(chalk.red('ā Not authenticated. Please run: obx login'));
|
|
@@ -44,69 +14,72 @@ async function dataset(file) {
|
|
|
44
14
|
return;
|
|
45
15
|
}
|
|
46
16
|
|
|
47
|
-
const missionName = generateMissionName();
|
|
48
|
-
|
|
49
17
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
50
|
-
console.log(chalk.white.bold(
|
|
51
|
-
console.log(chalk.hex('#F24E1E')('
|
|
52
|
-
console.log(chalk.gray(`File: ${file}`));
|
|
53
|
-
console.log(chalk.gray(`Type: Dataset Analysis (40-150 RCC)\n`));
|
|
18
|
+
console.log(chalk.white.bold('š DATASET ANALYSIS'));
|
|
19
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
54
20
|
|
|
55
|
-
|
|
21
|
+
console.log(chalk.white(` š File: ${chalk.hex('#F24E1E')(file)}`));
|
|
22
|
+
|
|
23
|
+
const spinner = new PremiumSpinner('⨠Mission Genesis - Analyzing dataset');
|
|
56
24
|
spinner.start();
|
|
25
|
+
await sleep(500);
|
|
57
26
|
|
|
58
27
|
try {
|
|
59
|
-
|
|
28
|
+
const token = await getAuthToken();
|
|
29
|
+
const fileContent = fs.readFileSync(file, 'utf8').substring(0, 5000);
|
|
30
|
+
|
|
31
|
+
spinner.update('š Analyzing dataset');
|
|
60
32
|
await sleep(600);
|
|
61
|
-
|
|
62
|
-
spinner.update('Detecting patterns');
|
|
33
|
+
|
|
34
|
+
spinner.update('š Detecting patterns');
|
|
63
35
|
await sleep(600);
|
|
64
|
-
|
|
65
|
-
spinner.update('Calculating statistics');
|
|
36
|
+
|
|
37
|
+
spinner.update('š Calculating statistics');
|
|
66
38
|
await sleep(600);
|
|
67
|
-
|
|
68
|
-
// Read file content (first 5000 chars for large files)
|
|
69
|
-
const fileContent = fs.readFileSync(file, 'utf8').substring(0, 5000);
|
|
70
|
-
|
|
71
|
-
const result = await createMission(
|
|
72
|
-
`Analyze this dataset and provide:\n1. Statistical summary (mean, median, std dev, min, max)\n2. Pattern detection\n3. Anomaly identification\n4. Data quality assessment\n5. Visualization recommendations\n\nDataset content:\n${fileContent}`,
|
|
73
|
-
'DATASET_ANALYSIS'
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
spinner.succeed('Dataset analysis complete');
|
|
77
|
-
|
|
78
|
-
console.log(chalk.gray(`\nš Model: ${result.model}`));
|
|
79
|
-
console.log(chalk.gray(`š° RCC Cost: ${result.rccCost}`));
|
|
80
|
-
console.log(chalk.gray(`š³ Remaining Balance: ${result.rccBalance} RCC\n`));
|
|
81
39
|
|
|
82
|
-
|
|
83
|
-
await
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
40
|
+
spinner.update('ā ļø Checking for anomalies');
|
|
41
|
+
await sleep(400);
|
|
42
|
+
|
|
43
|
+
const response = await fetch('https://obxvisionassistant-yyedhmslhq-uc.a.run.app', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'Authorization': `Bearer ${token}`
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
taskType: 'DATASET_ANALYSIS',
|
|
51
|
+
message: fileContent,
|
|
52
|
+
model: 'deep'
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const errorData = await response.json();
|
|
58
|
+
throw new Error(errorData.error || 'Failed to analyze dataset');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const data = await response.json();
|
|
97
62
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
63
|
+
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'));
|
|
102
70
|
|
|
71
|
+
console.log(chalk.green(' ā Statistical Summary'));
|
|
72
|
+
console.log(chalk.green(' ā Pattern Report'));
|
|
73
|
+
console.log(chalk.green(' ā Anomaly Detection'));
|
|
74
|
+
|
|
75
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
76
|
+
|
|
103
77
|
} catch (error) {
|
|
104
78
|
spinner.fail('Failed to analyze dataset');
|
|
105
|
-
console.error(chalk.red(error.
|
|
79
|
+
console.error(chalk.red(error.message));
|
|
106
80
|
}
|
|
107
81
|
}
|
|
108
82
|
|
|
109
|
-
// ==================== CODE REVIEW ====================
|
|
110
83
|
async function code(directory = '.') {
|
|
111
84
|
if (!isAuthenticated()) {
|
|
112
85
|
console.error(chalk.red('ā Not authenticated. Please run: obx login'));
|
|
@@ -118,153 +91,80 @@ async function code(directory = '.') {
|
|
|
118
91
|
return;
|
|
119
92
|
}
|
|
120
93
|
|
|
121
|
-
const missionName = generateMissionName();
|
|
122
|
-
|
|
123
94
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
124
|
-
console.log(chalk.white.bold(
|
|
125
|
-
console.log(chalk.hex('#F24E1E')('
|
|
126
|
-
|
|
127
|
-
console.log(chalk.
|
|
95
|
+
console.log(chalk.white.bold('š» CODE REVIEW'));
|
|
96
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
97
|
+
|
|
98
|
+
console.log(chalk.white(` š Directory: ${chalk.hex('#F24E1E')(directory)}`));
|
|
128
99
|
|
|
129
|
-
const spinner = new PremiumSpinner('
|
|
100
|
+
const spinner = new PremiumSpinner('⨠Mission Aurora - Reviewing code');
|
|
130
101
|
spinner.start();
|
|
102
|
+
await sleep(500);
|
|
131
103
|
|
|
132
104
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
spinner.update('Security audit');
|
|
137
|
-
await sleep(800);
|
|
138
|
-
|
|
139
|
-
spinner.update('Performance review');
|
|
105
|
+
const token = await getAuthToken();
|
|
106
|
+
|
|
107
|
+
spinner.update('š Scanning repository');
|
|
140
108
|
await sleep(600);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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)
|
|
148
120
|
let codeContent = '';
|
|
149
|
-
|
|
121
|
+
const files = fs.readdirSync(directory);
|
|
122
|
+
for (const file of files.slice(0, 10)) {
|
|
150
123
|
const filePath = path.join(directory, file);
|
|
151
|
-
if (fs.statSync(filePath).isFile()) {
|
|
152
|
-
codeContent += `\n
|
|
153
|
-
codeContent += fs.readFileSync(filePath, 'utf8').substring(0,
|
|
124
|
+
if (fs.statSync(filePath).isFile() && file.match(/\.(js|ts|py|java|cpp|go|rs)$/)) {
|
|
125
|
+
codeContent += `\n// File: ${file}\n`;
|
|
126
|
+
codeContent += fs.readFileSync(filePath, 'utf8').substring(0, 1000);
|
|
154
127
|
}
|
|
155
128
|
}
|
|
156
|
-
|
|
157
|
-
const result = await createMission(
|
|
158
|
-
`Review this code repository and provide:\n1. Architecture analysis\n2. Security vulnerabilities\n3. Performance issues\n4. Code quality assessment\n5. Optimization suggestions\n6. Best practices recommendations\n\nCode:\n${codeContent}`,
|
|
159
|
-
'CODE_REVIEW'
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
spinner.succeed('Code review complete');
|
|
163
|
-
|
|
164
|
-
console.log(chalk.gray(`\nš Model: ${result.model}`));
|
|
165
|
-
console.log(chalk.gray(`š° RCC Cost: ${result.rccCost}`));
|
|
166
|
-
console.log(chalk.gray(`š³ Remaining Balance: ${result.rccBalance} RCC\n`));
|
|
167
|
-
|
|
168
|
-
// Display the review with typing animation
|
|
169
|
-
await typeAIResponse(result.response);
|
|
170
|
-
|
|
171
|
-
// Research score
|
|
172
|
-
const score = generateResearchScore(result.response);
|
|
173
|
-
await displayResearchScore(score);
|
|
174
|
-
|
|
175
|
-
// Artifacts
|
|
176
|
-
const artifacts = [
|
|
177
|
-
{ icon: 'šļø', name: 'Architecture Report' },
|
|
178
|
-
{ icon: 'š', name: 'Security Audit' },
|
|
179
|
-
{ icon: 'ā”', name: 'Performance Analysis' },
|
|
180
|
-
{ icon: 'š”', name: 'Optimization Suggestions' }
|
|
181
|
-
];
|
|
182
|
-
await displayArtifacts(artifacts);
|
|
183
|
-
|
|
184
|
-
// Save report
|
|
185
|
-
const filepath = saveReport(directory, result.response, missionName);
|
|
186
|
-
console.log(chalk.green(`ā Report saved to: ${filepath}`));
|
|
187
|
-
console.log(chalk.gray('\nView with: cat ' + filepath + '\n'));
|
|
188
|
-
|
|
189
|
-
} catch (error) {
|
|
190
|
-
spinner.fail('Failed to review code');
|
|
191
|
-
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
129
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
130
|
+
const response = await fetch('https://obxvisionassistant-yyedhmslhq-uc.a.run.app', {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: {
|
|
133
|
+
'Content-Type': 'application/json',
|
|
134
|
+
'Authorization': `Bearer ${token}`
|
|
135
|
+
},
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
taskType: 'CODE_REVIEW',
|
|
138
|
+
message: codeContent,
|
|
139
|
+
model: 'deep'
|
|
140
|
+
})
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
const errorData = await response.json();
|
|
145
|
+
throw new Error(errorData.error || 'Failed to review code');
|
|
146
|
+
}
|
|
206
147
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
console.log(chalk.white.bold(`⨠${missionName}`));
|
|
211
|
-
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
212
|
-
console.log(chalk.gray(`File: ${file}`));
|
|
213
|
-
console.log(chalk.gray(`Type: Medical Imaging Analysis (30-120 RCC)\n`));
|
|
148
|
+
const data = await response.json();
|
|
149
|
+
|
|
150
|
+
spinner.succeed('ā Code review complete (40-300 RCC)');
|
|
214
151
|
|
|
215
|
-
|
|
216
|
-
spinner.start();
|
|
152
|
+
await typeAIResponse(data.response || 'Review data not available.');
|
|
217
153
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
spinner.update('Detecting anomalies');
|
|
223
|
-
await sleep(800);
|
|
224
|
-
|
|
225
|
-
spinner.update('Comparing with reference database');
|
|
226
|
-
await sleep(600);
|
|
154
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
155
|
+
console.log(chalk.white.bold('š¦ ARTIFACTS GENERATED'));
|
|
156
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
227
157
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
`Analyze this medical imaging file and provide a comprehensive research-oriented analysis:\n\nFile: ${path.basename(file)}\nFormat: ${fileExt}\nSize: ${stats.size} bytes\n\nPlease provide:\n1. Image type identification (X-ray, MRI, CT, Ultrasound, etc.)\n2. Anatomical region identification\n3. Pattern detection and findings\n4. Potential anomalies or areas of interest\n5. Comparative analysis with typical presentations\n6. Research implications and suggested further investigation\n7. Confidence level and limitations\n\nNote: This is for research purposes only, not clinical diagnosis.`,
|
|
234
|
-
'MEDICAL_ANALYSIS'
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
spinner.succeed('Medical analysis complete');
|
|
238
|
-
|
|
239
|
-
console.log(chalk.gray(`\nš Model: ${result.model}`));
|
|
240
|
-
console.log(chalk.gray(`š° RCC Cost: ${result.rccCost}`));
|
|
241
|
-
console.log(chalk.gray(`š³ Remaining Balance: ${result.rccBalance} RCC\n`));
|
|
158
|
+
console.log(chalk.green(' ā Architecture Report'));
|
|
159
|
+
console.log(chalk.green(' ā Security Audit'));
|
|
160
|
+
console.log(chalk.green(' ā Optimization Suggestions'));
|
|
161
|
+
|
|
162
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
242
163
|
|
|
243
|
-
// š„ THIS WAS MISSING - Display the analysis with typing animation
|
|
244
|
-
await typeAIResponse(result.response);
|
|
245
|
-
|
|
246
|
-
// Research score
|
|
247
|
-
const score = generateResearchScore(result.response);
|
|
248
|
-
await displayResearchScore(score);
|
|
249
|
-
|
|
250
|
-
// Artifacts
|
|
251
|
-
const artifacts = [
|
|
252
|
-
{ icon: 'š„', name: 'Pattern Detection Report' },
|
|
253
|
-
{ icon: 'š', name: 'Anomaly Analysis' },
|
|
254
|
-
{ icon: 'š', name: 'Comparative Analysis' },
|
|
255
|
-
{ icon: 'š', name: 'Research Implications' }
|
|
256
|
-
];
|
|
257
|
-
await displayArtifacts(artifacts);
|
|
258
|
-
|
|
259
|
-
// Save report
|
|
260
|
-
const filepath = saveReport(file, result.response, missionName);
|
|
261
|
-
console.log(chalk.green(`ā Report saved to: ${filepath}`));
|
|
262
|
-
console.log(chalk.gray('\nView with: cat ' + filepath + '\n'));
|
|
263
|
-
|
|
264
164
|
} catch (error) {
|
|
265
|
-
spinner.fail('Failed to
|
|
266
|
-
console.error(chalk.red(error.
|
|
165
|
+
spinner.fail('Failed to review code');
|
|
166
|
+
console.error(chalk.red(error.message));
|
|
267
167
|
}
|
|
268
168
|
}
|
|
269
169
|
|
|
270
|
-
module.exports = { dataset, code
|
|
170
|
+
module.exports = { dataset, code };
|
package/src/commands/earnings.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const { isAuthenticated } = require('../auth');
|
|
3
|
-
const { db
|
|
2
|
+
const { isAuthenticated, getCurrentUserUid, getCurrentUserEmail } = require('../auth');
|
|
3
|
+
const { db } = require('../firebase');
|
|
4
4
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
5
5
|
const { collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
|
|
6
6
|
|
|
@@ -10,7 +10,6 @@ async function earnings() {
|
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
// Get user UID from stored token (NOT from auth.currentUser)
|
|
14
13
|
const uid = getCurrentUserUid();
|
|
15
14
|
const email = getCurrentUserEmail();
|
|
16
15
|
|
|
@@ -24,7 +23,6 @@ async function earnings() {
|
|
|
24
23
|
spinner.start();
|
|
25
24
|
|
|
26
25
|
try {
|
|
27
|
-
// Fetch real published missions with earnings data
|
|
28
26
|
const publishedQuery = query(
|
|
29
27
|
collection(db, 'missions'),
|
|
30
28
|
where('uid', '==', uid),
|
|
@@ -45,13 +43,11 @@ async function earnings() {
|
|
|
45
43
|
|
|
46
44
|
spinner.succeed('Earnings data loaded');
|
|
47
45
|
|
|
48
|
-
// Calculate real earnings from actual data
|
|
49
46
|
const totalViews = publishedMissions.reduce((sum, m) => sum + (m.views || 0), 0);
|
|
50
47
|
const totalDownloads = publishedMissions.reduce((sum, m) => sum + (m.downloads || 0), 0);
|
|
51
48
|
const totalCitations = publishedMissions.reduce((sum, m) => sum + (m.citations || 0), 0);
|
|
52
49
|
const totalEarnings = publishedMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
|
|
53
50
|
|
|
54
|
-
// Calculate monthly breakdown
|
|
55
51
|
const now = new Date();
|
|
56
52
|
const thisMonth = now.getMonth();
|
|
57
53
|
const thisYear = now.getFullYear();
|
|
@@ -77,7 +73,6 @@ async function earnings() {
|
|
|
77
73
|
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
78
74
|
|
|
79
75
|
console.log(chalk.gray(` š¤ User: ${chalk.white(email || 'Unknown')}`));
|
|
80
|
-
console.log(chalk.gray(` š UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
81
76
|
|
|
82
77
|
console.log(chalk.white.bold('\n\nš OVERVIEW'));
|
|
83
78
|
console.log(chalk.gray('ā'.repeat(60)));
|
|
@@ -98,12 +93,6 @@ async function earnings() {
|
|
|
98
93
|
console.log(chalk.white(` šµ Average Per View: ${chalk.green('ā¹' + averagePerView.toFixed(3))}`));
|
|
99
94
|
}
|
|
100
95
|
|
|
101
|
-
console.log(chalk.white.bold('\n\nš³ PAYOUT DETAILS'));
|
|
102
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
103
|
-
console.log(chalk.white(`\n š Revenue Share: ${chalk.green('80%')}`));
|
|
104
|
-
console.log(chalk.white(` š
Next Payout: ${chalk.green('1st of next month')}`));
|
|
105
|
-
console.log(chalk.white(` š³ Payout Method: ${chalk.green('Bank Transfer / UPI')}`));
|
|
106
|
-
|
|
107
96
|
if (publishedMissions.length > 0) {
|
|
108
97
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
109
98
|
console.log(chalk.white.bold('š YOUR PUBLISHED RESEARCH'));
|
|
@@ -124,14 +113,6 @@ async function earnings() {
|
|
|
124
113
|
|
|
125
114
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
126
115
|
|
|
127
|
-
console.log(chalk.white.bold('š” TIPS TO INCREASE EARNINGS'));
|
|
128
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
129
|
-
console.log(chalk.white('\n ā Publish more research to increase views'));
|
|
130
|
-
console.log(chalk.white(' ā Share your research on social media'));
|
|
131
|
-
console.log(chalk.white(' ā Use relevant tags for better discoverability'));
|
|
132
|
-
console.log(chalk.white(' ā Create high-quality, comprehensive research'));
|
|
133
|
-
console.log(chalk.white(' ā Update research regularly with new findings\n'));
|
|
134
|
-
|
|
135
116
|
} catch (error) {
|
|
136
117
|
spinner.fail('Failed to fetch earnings data');
|
|
137
118
|
console.error(chalk.red(error.message));
|
package/src/commands/morning.js
CHANGED
|
@@ -1,94 +1,151 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const {
|
|
3
|
-
const {
|
|
4
|
-
const
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
PremiumSpinner,
|
|
8
|
-
sleep
|
|
9
|
-
} = require('../utils/display');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Fetch and display morning briefing
|
|
13
|
-
*/
|
|
2
|
+
const { isAuthenticated, getCurrentUserUid, getCurrentUserEmail } = require('../auth');
|
|
3
|
+
const { db } = require('../firebase');
|
|
4
|
+
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
5
|
+
const { collection, query, where, orderBy, limit, getDocs } = require('firebase/firestore');
|
|
6
|
+
|
|
14
7
|
async function morning() {
|
|
15
8
|
if (!isAuthenticated()) {
|
|
16
9
|
console.error(chalk.red('ā Not authenticated. Please run: obx login'));
|
|
17
10
|
return;
|
|
18
11
|
}
|
|
19
12
|
|
|
20
|
-
const
|
|
13
|
+
const uid = getCurrentUserUid();
|
|
14
|
+
const email = getCurrentUserEmail();
|
|
15
|
+
|
|
16
|
+
if (!uid) {
|
|
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 daily briefing');
|
|
21
23
|
spinner.start();
|
|
22
24
|
|
|
23
25
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
// Get today's date
|
|
27
|
+
const today = new Date();
|
|
28
|
+
const todayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
29
|
+
const yesterdayStart = new Date(todayStart);
|
|
30
|
+
yesterdayStart.setDate(yesterdayStart.getDate() - 1);
|
|
31
|
+
|
|
32
|
+
// Fetch active missions
|
|
33
|
+
const activeQuery = query(
|
|
34
|
+
collection(db, 'missions'),
|
|
35
|
+
where('uid', '==', uid),
|
|
36
|
+
where('status', 'in', ['running', 'pending'])
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const activeSnapshot = await getDocs(activeQuery);
|
|
40
|
+
const activeMissions = [];
|
|
41
|
+
activeSnapshot.forEach(doc => {
|
|
42
|
+
activeMissions.push({ id: doc.id, ...doc.data() });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Fetch recent completed missions (last 7 days)
|
|
46
|
+
const sevenDaysAgo = new Date();
|
|
47
|
+
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
34
48
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
const recentQuery = query(
|
|
50
|
+
collection(db, 'missions'),
|
|
51
|
+
where('uid', '==', uid),
|
|
52
|
+
where('status', '==', 'completed'),
|
|
53
|
+
orderBy('createdAt', 'desc'),
|
|
54
|
+
limit(10)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const recentSnapshot = await getDocs(recentQuery);
|
|
58
|
+
const recentMissions = [];
|
|
59
|
+
recentSnapshot.forEach(doc => {
|
|
60
|
+
recentMissions.push({ id: doc.id, ...doc.data() });
|
|
42
61
|
});
|
|
62
|
+
|
|
63
|
+
// Fetch published missions for earnings
|
|
64
|
+
const publishedQuery = query(
|
|
65
|
+
collection(db, 'missions'),
|
|
66
|
+
where('uid', '==', uid),
|
|
67
|
+
where('isPublished', '==', true)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const publishedSnapshot = await getDocs(publishedQuery);
|
|
71
|
+
const publishedMissions = [];
|
|
72
|
+
publishedSnapshot.forEach(doc => {
|
|
73
|
+
publishedMissions.push({ id: doc.id, ...doc.data() });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const totalViews = publishedMissions.reduce((sum, m) => sum + (m.views || 0), 0);
|
|
77
|
+
const totalEarnings = publishedMissions.reduce((sum, m) => sum + (m.earnings || 0), 0);
|
|
78
|
+
|
|
79
|
+
spinner.succeed('Daily briefing loaded');
|
|
80
|
+
|
|
81
|
+
// Display the briefing
|
|
82
|
+
const dateString = today.toLocaleDateString('en-US', {
|
|
83
|
+
weekday: 'long',
|
|
84
|
+
year: 'numeric',
|
|
85
|
+
month: 'long',
|
|
86
|
+
day: 'numeric'
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
90
|
+
console.log(chalk.white.bold('āļø GOOD MORNING, RESEARCHER!'));
|
|
91
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
43
92
|
|
|
44
|
-
|
|
45
|
-
|
|
93
|
+
console.log(chalk.gray(` š¤ ${chalk.white(email || 'Unknown')}`));
|
|
94
|
+
console.log(chalk.gray(` š
${chalk.white(dateString)}`));
|
|
95
|
+
|
|
96
|
+
// Active Missions
|
|
97
|
+
if (activeMissions.length > 0) {
|
|
98
|
+
console.log(chalk.white.bold('\n\nšÆ ACTIVE MISSIONS'));
|
|
99
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
100
|
+
|
|
101
|
+
activeMissions.forEach((m, i) => {
|
|
102
|
+
const topic = (m.message || 'No topic').substring(0, 50);
|
|
103
|
+
console.log(chalk.white(`\n ⨠${chalk.hex('#F24E1E')(m.id)}`));
|
|
104
|
+
console.log(chalk.white(` Topic: ${topic}`));
|
|
105
|
+
console.log(chalk.yellow(` Status: ${m.status}`));
|
|
106
|
+
});
|
|
46
107
|
}
|
|
108
|
+
|
|
109
|
+
// Recent Completions
|
|
110
|
+
if (recentMissions.length > 0) {
|
|
111
|
+
console.log(chalk.white.bold('\n\nā
RECENTLY COMPLETED'));
|
|
112
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
113
|
+
|
|
114
|
+
recentMissions.slice(0, 5).forEach((m, i) => {
|
|
115
|
+
const topic = (m.message || 'No topic').substring(0, 50);
|
|
116
|
+
const date = m.createdAt?.toDate?.().toLocaleDateString() || 'N/A';
|
|
117
|
+
console.log(chalk.white(`\n ${i + 1}. ${topic}`));
|
|
118
|
+
console.log(chalk.gray(` Completed: ${date}`));
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Earnings Summary
|
|
123
|
+
if (publishedMissions.length > 0) {
|
|
124
|
+
console.log(chalk.white.bold('\n\nš° EARNINGS SUMMARY'));
|
|
125
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
126
|
+
|
|
127
|
+
console.log(chalk.white(`\n š¤ Published Research: ${chalk.green(publishedMissions.length)}`));
|
|
128
|
+
console.log(chalk.white(` š Total Views: ${chalk.green(totalViews.toLocaleString())}`));
|
|
129
|
+
console.log(chalk.white(` š° Total Earnings: ${chalk.green('ā¹' + totalEarnings.toLocaleString())}`));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Recommendations
|
|
133
|
+
console.log(chalk.white.bold('\n\nš” RECOMMENDATIONS'));
|
|
134
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
47
135
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
136
|
+
console.log(chalk.white('\n āø Check active missions with "obx mission status"'));
|
|
137
|
+
console.log(chalk.white(' āø Publish completed research with "obx publish"'));
|
|
138
|
+
console.log(chalk.white(' āø View earnings with "obx earnings"'));
|
|
139
|
+
console.log(chalk.white(' āø Generate new research with "obx mission create"'));
|
|
140
|
+
|
|
141
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
142
|
+
console.log(chalk.gray('Free ⢠No RCC cost'));
|
|
143
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
144
|
+
|
|
55
145
|
} catch (error) {
|
|
56
|
-
spinner.fail('Failed to fetch
|
|
57
|
-
|
|
58
|
-
// Fallback: show local briefing
|
|
59
|
-
console.log(chalk.gray('\n Showing local briefing...\n'));
|
|
60
|
-
await displayLocalBriefing();
|
|
146
|
+
spinner.fail('Failed to fetch daily briefing');
|
|
147
|
+
console.error(chalk.red(error.message));
|
|
61
148
|
}
|
|
62
149
|
}
|
|
63
150
|
|
|
64
|
-
/**
|
|
65
|
-
* Display local briefing when API is unavailable
|
|
66
|
-
*/
|
|
67
|
-
async function displayLocalBriefing() {
|
|
68
|
-
const today = new Date().toLocaleDateString('en-US', {
|
|
69
|
-
weekday: 'long',
|
|
70
|
-
year: 'numeric',
|
|
71
|
-
month: 'long',
|
|
72
|
-
day: 'numeric'
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const briefing = {
|
|
76
|
-
date: today,
|
|
77
|
-
updates: [
|
|
78
|
-
{ type: 'info', text: 'No new updates since last check' },
|
|
79
|
-
{ type: 'info', text: 'All missions are up to date' }
|
|
80
|
-
],
|
|
81
|
-
missions: [
|
|
82
|
-
{ name: 'Mission Atlas', status: 'Complete', progress: 100 }
|
|
83
|
-
],
|
|
84
|
-
recommendations: [
|
|
85
|
-
'Run "obx morning" daily to stay updated',
|
|
86
|
-
'Check mission health with "obx mission status"',
|
|
87
|
-
'Explore new topics with "obx literature [topic]"'
|
|
88
|
-
]
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
await displayMorningBriefing(briefing);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
151
|
module.exports = { morning };
|
package/src/commands/publish.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('inquirer');
|
|
3
|
-
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
4
|
-
const { db
|
|
3
|
+
const { getAuthToken, isAuthenticated, getCurrentUserUid, getCurrentUserEmail } = require('../auth');
|
|
4
|
+
const { db } = require('../firebase');
|
|
5
5
|
const { PremiumSpinner, sleep } = require('../utils/display');
|
|
6
6
|
const { collection, query, where, orderBy, limit, getDocs, doc, updateDoc } = require('firebase/firestore');
|
|
7
7
|
|
|
@@ -11,7 +11,6 @@ async function publish(missionId) {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
// Get user UID from stored token
|
|
15
14
|
const uid = getCurrentUserUid();
|
|
16
15
|
const email = getCurrentUserEmail();
|
|
17
16
|
|
|
@@ -26,9 +25,7 @@ async function publish(missionId) {
|
|
|
26
25
|
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
27
26
|
|
|
28
27
|
console.log(chalk.gray(` š¤ User: ${chalk.white(email || 'Unknown')}`));
|
|
29
|
-
console.log(chalk.gray(` š UID: ${chalk.gray(uid.substring(0, 16))}...`));
|
|
30
28
|
|
|
31
|
-
// If no mission ID provided, fetch real missions from Firestore
|
|
32
29
|
if (!missionId) {
|
|
33
30
|
console.log(chalk.gray('\nFetching your completed missions...\n'));
|
|
34
31
|
|
|
@@ -36,7 +33,6 @@ async function publish(missionId) {
|
|
|
36
33
|
spinner.start();
|
|
37
34
|
|
|
38
35
|
try {
|
|
39
|
-
// Fetch real completed missions from Firestore
|
|
40
36
|
const missionsQuery = query(
|
|
41
37
|
collection(db, 'missions'),
|
|
42
38
|
where('uid', '==', uid),
|
|
@@ -97,7 +93,6 @@ async function publish(missionId) {
|
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
95
|
|
|
100
|
-
// Publish the mission
|
|
101
96
|
const spinner = new PremiumSpinner('Preparing to publish research');
|
|
102
97
|
spinner.start();
|
|
103
98
|
await sleep(500);
|
|
@@ -106,7 +101,6 @@ async function publish(missionId) {
|
|
|
106
101
|
spinner.update('Fetching mission data');
|
|
107
102
|
const missionRef = doc(db, 'missions', missionId);
|
|
108
103
|
|
|
109
|
-
// Get the mission document
|
|
110
104
|
const missionSnap = await getDocs(query(collection(db, 'missions'), where('__name__', '==', missionId)));
|
|
111
105
|
|
|
112
106
|
if (missionSnap.empty) {
|
|
@@ -120,7 +114,6 @@ async function publish(missionId) {
|
|
|
120
114
|
spinner.update('Generating SEO-optimized page');
|
|
121
115
|
await sleep(500);
|
|
122
116
|
|
|
123
|
-
// Generate slug from mission topic
|
|
124
117
|
const slug = (missionData.message || missionId)
|
|
125
118
|
.toLowerCase()
|
|
126
119
|
.replace(/[^a-z0-9]+/g, '-')
|
|
@@ -136,7 +129,6 @@ async function publish(missionId) {
|
|
|
136
129
|
spinner.update('Enabling revenue tracking');
|
|
137
130
|
await sleep(400);
|
|
138
131
|
|
|
139
|
-
// Update mission in Firestore
|
|
140
132
|
await updateDoc(missionRef, {
|
|
141
133
|
isPublished: true,
|
|
142
134
|
publishedAt: new Date(),
|
|
@@ -163,18 +155,7 @@ async function publish(missionId) {
|
|
|
163
155
|
console.log(chalk.white(`š Google Indexing: ${chalk.green('Requested')} (24 hours)`));
|
|
164
156
|
console.log(chalk.white(`š Analytics: ${chalk.green('Enabled')}`));
|
|
165
157
|
|
|
166
|
-
console.log(chalk.hex('#F24E1E')('\n
|
|
167
|
-
console.log(chalk.white.bold('š° START EARNING'));
|
|
168
|
-
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
169
|
-
|
|
170
|
-
console.log(chalk.gray('Your research is now live! Here\'s what happens next:'));
|
|
171
|
-
console.log(chalk.white('\n ā Google indexes your research within 24 hours'));
|
|
172
|
-
console.log(chalk.white(' ā Readers discover it through search'));
|
|
173
|
-
console.log(chalk.white(' ā Ads are displayed to readers'));
|
|
174
|
-
console.log(chalk.white(' ā You earn 80% of all ad revenue'));
|
|
175
|
-
console.log(chalk.white(' ā Monthly payouts to your account\n'));
|
|
176
|
-
|
|
177
|
-
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
158
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
178
159
|
|
|
179
160
|
} catch (error) {
|
|
180
161
|
spinner.fail('Failed to publish research');
|
package/src/commands/timeline.js
CHANGED
|
@@ -1,152 +1,91 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const {
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
generateMissionName,
|
|
6
|
-
displayTimeline,
|
|
7
|
-
PremiumSpinner,
|
|
8
|
-
sleep
|
|
9
|
-
} = require('../utils/display');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Generate research timeline for a topic
|
|
13
|
-
*/
|
|
2
|
+
const { getAuthToken, isAuthenticated } = require('../auth');
|
|
3
|
+
const { PremiumSpinner, sleep, typeAIResponse } = require('../utils/display');
|
|
4
|
+
|
|
14
5
|
async function timeline(topic) {
|
|
15
6
|
if (!isAuthenticated()) {
|
|
16
7
|
console.error(chalk.red('ā Not authenticated. Please run: obx login'));
|
|
17
8
|
return;
|
|
18
9
|
}
|
|
19
10
|
|
|
20
|
-
if (!topic
|
|
21
|
-
console.error(chalk.red('ā Please provide a research topic'));
|
|
22
|
-
console.log(chalk.gray('
|
|
11
|
+
if (!topic) {
|
|
12
|
+
console.error(chalk.red('ā Please provide a research topic.'));
|
|
13
|
+
console.log(chalk.gray('Usage: obx timeline "quantum computing"\n'));
|
|
23
14
|
return;
|
|
24
15
|
}
|
|
25
16
|
|
|
26
|
-
const missionName = generateMissionName();
|
|
27
|
-
|
|
28
17
|
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
29
|
-
console.log(chalk.white.bold(
|
|
30
|
-
console.log(chalk.hex('#F24E1E')('
|
|
31
|
-
|
|
32
|
-
console.log(chalk.
|
|
18
|
+
console.log(chalk.white.bold('š
RESEARCH TIMELINE GENERATOR'));
|
|
19
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
20
|
+
|
|
21
|
+
console.log(chalk.white(` š Topic: ${chalk.hex('#F24E1E')(topic)}`));
|
|
22
|
+
console.log(chalk.white(` š° Cost: ${chalk.green('80 RCC')}`));
|
|
33
23
|
|
|
34
|
-
const spinner = new PremiumSpinner('
|
|
24
|
+
const spinner = new PremiumSpinner('⨠Mission Polaris - Generating timeline');
|
|
35
25
|
spinner.start();
|
|
26
|
+
await sleep(500);
|
|
36
27
|
|
|
37
28
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
spinner.update('Identifying key milestones');
|
|
42
|
-
await sleep(800);
|
|
43
|
-
|
|
44
|
-
spinner.update('Building timeline graph');
|
|
29
|
+
const token = await getAuthToken();
|
|
30
|
+
|
|
31
|
+
spinner.update('š Searching historical research');
|
|
45
32
|
await sleep(600);
|
|
46
|
-
|
|
47
|
-
spinner.update('Analyzing
|
|
33
|
+
|
|
34
|
+
spinner.update('š Analyzing foundational papers');
|
|
48
35
|
await sleep(600);
|
|
49
|
-
|
|
50
|
-
// Call backend API
|
|
51
|
-
const result = await createMission(
|
|
52
|
-
`Generate a comprehensive research timeline for: ${topic}.
|
|
53
|
-
Include major papers, breakthroughs, patents, and milestones from the earliest research to present day.
|
|
54
|
-
Format as JSON array with objects containing: year, title, description, impact (High/Medium/Low), type (paper/patent/breakthrough/milestone).
|
|
55
|
-
Sort chronologically. Include 8-12 key events.`,
|
|
56
|
-
'RESEARCH_TIMELINE'
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
spinner.succeed('Timeline generated');
|
|
60
|
-
|
|
61
|
-
console.log(chalk.gray(`\nš Model: ${result.model}`));
|
|
62
|
-
console.log(chalk.gray(`š° RCC Cost: ${result.rccCost}`));
|
|
63
|
-
console.log(chalk.gray(`š³ Remaining Balance: ${result.rccBalance} RCC\n`));
|
|
64
36
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
37
|
+
spinner.update('šŗļø Mapping field evolution');
|
|
38
|
+
await sleep(600);
|
|
39
|
+
|
|
40
|
+
spinner.update('š Identifying key milestones');
|
|
41
|
+
await sleep(600);
|
|
42
|
+
|
|
43
|
+
spinner.update('āļø Compiling timeline');
|
|
44
|
+
await sleep(400);
|
|
45
|
+
|
|
46
|
+
// Call the AI backend
|
|
47
|
+
const response = await fetch('https://obxvisionassistant-yyedhmslhq-uc.a.run.app', {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
'Authorization': `Bearer ${token}`
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
taskType: 'RESEARCH_TIMELINE',
|
|
55
|
+
message: topic,
|
|
56
|
+
model: 'deep'
|
|
57
|
+
})
|
|
86
58
|
});
|
|
59
|
+
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const errorData = await response.json();
|
|
62
|
+
throw new Error(errorData.error || 'Failed to generate timeline');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const data = await response.json();
|
|
87
66
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
console.log(chalk.
|
|
92
|
-
console.log(chalk.
|
|
67
|
+
spinner.succeed('ā Timeline generated (80 RCC)');
|
|
68
|
+
|
|
69
|
+
// Display the timeline
|
|
70
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
71
|
+
console.log(chalk.white.bold(`š
Research Timeline: ${topic}`));
|
|
72
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
73
|
+
|
|
74
|
+
await typeAIResponse(data.response || 'Timeline data not available.');
|
|
75
|
+
|
|
76
|
+
console.log(chalk.hex('#F24E1E')('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
77
|
+
console.log(chalk.white.bold('šÆ YOUR RESEARCH'));
|
|
78
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
93
79
|
|
|
80
|
+
console.log(chalk.green(` ⨠Your research continues from here`));
|
|
81
|
+
console.log(chalk.gray(' Add your contribution to this evolving field.\n'));
|
|
82
|
+
|
|
83
|
+
console.log(chalk.hex('#F24E1E')('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
84
|
+
|
|
94
85
|
} catch (error) {
|
|
95
86
|
spinner.fail('Failed to generate timeline');
|
|
96
|
-
console.error(chalk.red(error.
|
|
87
|
+
console.error(chalk.red(error.message));
|
|
97
88
|
}
|
|
98
89
|
}
|
|
99
90
|
|
|
100
|
-
/**
|
|
101
|
-
* Generate sample timeline when API doesn't return structured data
|
|
102
|
-
*/
|
|
103
|
-
function generateSampleTimeline(topic) {
|
|
104
|
-
const currentYear = new Date().getFullYear();
|
|
105
|
-
|
|
106
|
-
return [
|
|
107
|
-
{
|
|
108
|
-
year: currentYear - 30,
|
|
109
|
-
title: `Foundational Research on ${topic}`,
|
|
110
|
-
description: 'Early theoretical work and initial experiments',
|
|
111
|
-
impact: 'High',
|
|
112
|
-
type: 'paper'
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
year: currentYear - 20,
|
|
116
|
-
title: 'First Major Breakthrough',
|
|
117
|
-
description: 'Key discovery that shaped the field',
|
|
118
|
-
impact: 'High',
|
|
119
|
-
type: 'breakthrough'
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
year: currentYear - 15,
|
|
123
|
-
title: 'Commercial Applications Begin',
|
|
124
|
-
description: 'First industry implementations',
|
|
125
|
-
impact: 'Medium',
|
|
126
|
-
type: 'milestone'
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
year: currentYear - 10,
|
|
130
|
-
title: 'Patent Landscape Expands',
|
|
131
|
-
description: 'Significant patent filings by major companies',
|
|
132
|
-
impact: 'Medium',
|
|
133
|
-
type: 'patent'
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
year: currentYear - 5,
|
|
137
|
-
title: 'State-of-the-Art Advances',
|
|
138
|
-
description: 'Modern techniques and methodologies',
|
|
139
|
-
impact: 'High',
|
|
140
|
-
type: 'paper'
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
year: currentYear - 2,
|
|
144
|
-
title: 'Recent Breakthrough',
|
|
145
|
-
description: 'Latest major advancement in the field',
|
|
146
|
-
impact: 'High',
|
|
147
|
-
type: 'breakthrough'
|
|
148
|
-
}
|
|
149
|
-
];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
91
|
module.exports = { timeline };
|
package/src/firebase.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const { initializeApp, getApps } = require('firebase/app');
|
|
2
2
|
const { getAuth } = require('firebase/auth');
|
|
3
3
|
const { getFirestore } = require('firebase/firestore');
|
|
4
|
-
const Conf = require('conf');
|
|
5
4
|
|
|
6
5
|
const firebaseConfig = {
|
|
7
6
|
apiKey: "AIzaSyDlgXId4pLlYqm-MDuhfz3dLH24KBRHkw8",
|
|
@@ -23,82 +22,13 @@ if (getApps().length === 0) {
|
|
|
23
22
|
const auth = getAuth(app);
|
|
24
23
|
const db = getFirestore(app);
|
|
25
24
|
|
|
26
|
-
//
|
|
27
|
-
const
|
|
28
|
-
projectName: 'omnibiofex',
|
|
29
|
-
schema: {
|
|
30
|
-
token: { type: 'string' },
|
|
31
|
-
refreshToken: { type: 'string' },
|
|
32
|
-
expiresAt: { type: 'number' }
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Decode JWT token to extract user info
|
|
38
|
-
* @returns {Object|null} - { uid, email } or null if no token
|
|
39
|
-
*/
|
|
40
|
-
function decodeToken() {
|
|
41
|
-
const token = tokenStore.get('token');
|
|
42
|
-
if (!token) return null;
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
// JWT format: header.payload.signature
|
|
46
|
-
const parts = token.split('.');
|
|
47
|
-
if (parts.length !== 3) return null;
|
|
48
|
-
|
|
49
|
-
// Decode payload (base64url)
|
|
50
|
-
const payload = parts[1];
|
|
51
|
-
const decoded = Buffer.from(payload, 'base64').toString('utf8');
|
|
52
|
-
const data = JSON.parse(decoded);
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
uid: data.user_id || data.sub,
|
|
56
|
-
email: data.email,
|
|
57
|
-
exp: data.exp
|
|
58
|
-
};
|
|
59
|
-
} catch (error) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Get current user UID from stored token
|
|
66
|
-
* @returns {string|null} - User UID or null
|
|
67
|
-
*/
|
|
68
|
-
function getCurrentUserUid() {
|
|
69
|
-
const decoded = decodeToken();
|
|
70
|
-
return decoded ? decoded.uid : null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get current user email from stored token
|
|
75
|
-
* @returns {string|null} - User email or null
|
|
76
|
-
*/
|
|
77
|
-
function getCurrentUserEmail() {
|
|
78
|
-
const decoded = decodeToken();
|
|
79
|
-
return decoded ? decoded.email : null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Check if token is valid (not expired)
|
|
84
|
-
* @returns {boolean}
|
|
85
|
-
*/
|
|
86
|
-
function isTokenValid() {
|
|
87
|
-
const decoded = decodeToken();
|
|
88
|
-
if (!decoded || !decoded.exp) return false;
|
|
89
|
-
|
|
90
|
-
// JWT exp is in seconds, Date.now() is in milliseconds
|
|
91
|
-
const now = Math.floor(Date.now() / 1000);
|
|
92
|
-
return decoded.exp > now;
|
|
93
|
-
}
|
|
25
|
+
// Re-export user functions from auth.js (single source of truth)
|
|
26
|
+
const { getCurrentUserUid, getCurrentUserEmail } = require('./auth');
|
|
94
27
|
|
|
95
28
|
module.exports = {
|
|
96
29
|
app,
|
|
97
30
|
auth,
|
|
98
|
-
db,
|
|
99
|
-
tokenStore,
|
|
100
|
-
decodeToken,
|
|
31
|
+
db,
|
|
101
32
|
getCurrentUserUid,
|
|
102
|
-
getCurrentUserEmail
|
|
103
|
-
isTokenValid
|
|
33
|
+
getCurrentUserEmail
|
|
104
34
|
};
|