omnibiofex 2.6.3 → 2.7.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 +23 -0
- package/package.json +1 -1
- package/src/commands/data.js +231 -20
- package/src/commands/morning.js +94 -0
- package/src/commands/research.js +58 -6
- package/src/commands/timeline.js +152 -0
- package/src/utils/display.js +240 -2
package/bin/obx
CHANGED
|
@@ -143,6 +143,29 @@ program
|
|
|
143
143
|
.description('Open browser to purchase credits')
|
|
144
144
|
.action(buy);
|
|
145
145
|
|
|
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
|
+
|
|
146
169
|
// ==================== DEBUG COMMAND ====================
|
|
147
170
|
const { debug } = require('../src/commands/debug');
|
|
148
171
|
|
package/package.json
CHANGED
package/src/commands/data.js
CHANGED
|
@@ -1,58 +1,269 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { createMission } = require('../api');
|
|
3
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');
|
|
4
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
|
+
}
|
|
34
|
+
|
|
35
|
+
// ==================== DATASET ANALYSIS ====================
|
|
5
36
|
async function dataset(file) {
|
|
6
37
|
if (!isAuthenticated()) {
|
|
7
|
-
console.error(chalk.red('Not authenticated. Please run: obx login'));
|
|
38
|
+
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!fs.existsSync(file)) {
|
|
43
|
+
console.error(chalk.red(`✗ File not found: ${file}`));
|
|
8
44
|
return;
|
|
9
45
|
}
|
|
10
46
|
|
|
11
|
-
const
|
|
47
|
+
const missionName = generateMissionName();
|
|
48
|
+
|
|
49
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
50
|
+
console.log(chalk.white.bold(`✨ ${missionName}`));
|
|
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`));
|
|
54
|
+
|
|
55
|
+
const spinner = new PremiumSpinner('Reading dataset');
|
|
56
|
+
spinner.start();
|
|
12
57
|
|
|
13
58
|
try {
|
|
14
|
-
spinner.
|
|
15
|
-
|
|
59
|
+
spinner.update('Parsing data structure');
|
|
60
|
+
await sleep(600);
|
|
61
|
+
|
|
62
|
+
spinner.update('Detecting patterns');
|
|
63
|
+
await sleep(600);
|
|
64
|
+
|
|
65
|
+
spinner.update('Calculating statistics');
|
|
66
|
+
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
|
+
|
|
82
|
+
// Display the analysis with typing animation
|
|
83
|
+
await typeAIResponse(result.response);
|
|
84
|
+
|
|
85
|
+
// Research score
|
|
86
|
+
const score = generateResearchScore(result.response);
|
|
87
|
+
await displayResearchScore(score);
|
|
88
|
+
|
|
89
|
+
// Artifacts
|
|
90
|
+
const artifacts = [
|
|
91
|
+
{ icon: '📊', name: 'Statistical Summary' },
|
|
92
|
+
{ icon: '🔍', name: 'Pattern Report' },
|
|
93
|
+
{ icon: '⚠️', name: 'Anomaly Detection' },
|
|
94
|
+
{ icon: '📈', name: 'Data Quality Assessment' }
|
|
95
|
+
];
|
|
96
|
+
await displayArtifacts(artifacts);
|
|
97
|
+
|
|
98
|
+
// Save report
|
|
99
|
+
const filepath = saveReport(file, result.response, missionName);
|
|
100
|
+
console.log(chalk.green(`✓ Report saved to: ${filepath}`));
|
|
101
|
+
console.log(chalk.gray('\nView with: cat ' + filepath + '\n'));
|
|
16
102
|
|
|
17
103
|
} catch (error) {
|
|
18
|
-
spinner.fail(
|
|
19
|
-
console.error(chalk.red(error.message));
|
|
104
|
+
spinner.fail('Failed to analyze dataset');
|
|
105
|
+
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
20
106
|
}
|
|
21
107
|
}
|
|
22
108
|
|
|
23
|
-
|
|
109
|
+
// ==================== CODE REVIEW ====================
|
|
110
|
+
async function code(directory = '.') {
|
|
24
111
|
if (!isAuthenticated()) {
|
|
25
|
-
console.error(chalk.red('Not authenticated. Please run: obx login'));
|
|
112
|
+
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
26
113
|
return;
|
|
27
114
|
}
|
|
28
115
|
|
|
29
|
-
|
|
116
|
+
if (!fs.existsSync(directory)) {
|
|
117
|
+
console.error(chalk.red(`✗ Directory not found: ${directory}`));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const missionName = generateMissionName();
|
|
122
|
+
|
|
123
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
124
|
+
console.log(chalk.white.bold(`✨ ${missionName}`));
|
|
125
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════'));
|
|
126
|
+
console.log(chalk.gray(`Directory: ${directory}`));
|
|
127
|
+
console.log(chalk.gray(`Type: Code Review (40-300 RCC)\n`));
|
|
128
|
+
|
|
129
|
+
const spinner = new PremiumSpinner('Scanning repository');
|
|
130
|
+
spinner.start();
|
|
30
131
|
|
|
31
132
|
try {
|
|
32
|
-
spinner.
|
|
33
|
-
|
|
133
|
+
spinner.update('Analyzing architecture');
|
|
134
|
+
await sleep(800);
|
|
135
|
+
|
|
136
|
+
spinner.update('Security audit');
|
|
137
|
+
await sleep(800);
|
|
138
|
+
|
|
139
|
+
spinner.update('Performance review');
|
|
140
|
+
await sleep(600);
|
|
141
|
+
|
|
142
|
+
// Read key files from directory
|
|
143
|
+
const files = fs.readdirSync(directory).filter(f =>
|
|
144
|
+
f.endsWith('.js') || f.endsWith('.py') || f.endsWith('.ts') ||
|
|
145
|
+
f.endsWith('.java') || f.endsWith('.cpp') || f.endsWith('.go')
|
|
146
|
+
).slice(0, 10); // Limit to 10 files
|
|
147
|
+
|
|
148
|
+
let codeContent = '';
|
|
149
|
+
for (const file of files) {
|
|
150
|
+
const filePath = path.join(directory, file);
|
|
151
|
+
if (fs.statSync(filePath).isFile()) {
|
|
152
|
+
codeContent += `\n\n// File: ${file}\n`;
|
|
153
|
+
codeContent += fs.readFileSync(filePath, 'utf8').substring(0, 2000);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
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'));
|
|
34
188
|
|
|
35
189
|
} catch (error) {
|
|
36
|
-
spinner.fail(
|
|
37
|
-
console.error(chalk.red(error.message));
|
|
190
|
+
spinner.fail('Failed to review code');
|
|
191
|
+
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
38
192
|
}
|
|
39
193
|
}
|
|
40
194
|
|
|
195
|
+
// ==================== MEDICAL IMAGING ANALYSIS ====================
|
|
41
196
|
async function medical(file) {
|
|
42
197
|
if (!isAuthenticated()) {
|
|
43
|
-
console.error(chalk.red('Not authenticated. Please run: obx login'));
|
|
198
|
+
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (!fs.existsSync(file)) {
|
|
203
|
+
console.error(chalk.red(`✗ File not found: ${file}`));
|
|
44
204
|
return;
|
|
45
205
|
}
|
|
46
206
|
|
|
47
|
-
const
|
|
207
|
+
const missionName = generateMissionName();
|
|
208
|
+
|
|
209
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
210
|
+
console.log(chalk.white.bold(`✨ ${missionName}`));
|
|
211
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════'));
|
|
212
|
+
console.log(chalk.gray(`File: ${file}`));
|
|
213
|
+
console.log(chalk.gray(`Type: Medical Imaging Analysis (30-120 RCC)\n`));
|
|
214
|
+
|
|
215
|
+
const spinner = new PremiumSpinner('Loading medical image');
|
|
216
|
+
spinner.start();
|
|
48
217
|
|
|
49
218
|
try {
|
|
50
|
-
spinner.
|
|
51
|
-
|
|
219
|
+
spinner.update('Analyzing image patterns');
|
|
220
|
+
await sleep(800);
|
|
221
|
+
|
|
222
|
+
spinner.update('Detecting anomalies');
|
|
223
|
+
await sleep(800);
|
|
224
|
+
|
|
225
|
+
spinner.update('Comparing with reference database');
|
|
226
|
+
await sleep(600);
|
|
227
|
+
|
|
228
|
+
// For images, we send metadata and ask for analysis
|
|
229
|
+
const stats = fs.statSync(file);
|
|
230
|
+
const fileExt = path.extname(file).toLowerCase();
|
|
231
|
+
|
|
232
|
+
const result = await createMission(
|
|
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`));
|
|
242
|
+
|
|
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'));
|
|
52
263
|
|
|
53
264
|
} catch (error) {
|
|
54
|
-
spinner.fail(
|
|
55
|
-
console.error(chalk.red(error.message));
|
|
265
|
+
spinner.fail('Failed to analyze medical image');
|
|
266
|
+
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
56
267
|
}
|
|
57
268
|
}
|
|
58
269
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getAuthToken } = require('../auth');
|
|
3
|
+
const { isAuthenticated } = require('../auth');
|
|
4
|
+
const config = require('../config');
|
|
5
|
+
const {
|
|
6
|
+
displayMorningBriefing,
|
|
7
|
+
PremiumSpinner,
|
|
8
|
+
sleep
|
|
9
|
+
} = require('../utils/display');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fetch and display morning briefing
|
|
13
|
+
*/
|
|
14
|
+
async function morning() {
|
|
15
|
+
if (!isAuthenticated()) {
|
|
16
|
+
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const spinner = new PremiumSpinner('Fetching your research updates');
|
|
21
|
+
spinner.start();
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const token = await getAuthToken();
|
|
25
|
+
|
|
26
|
+
spinner.update('Checking active missions');
|
|
27
|
+
await sleep(500);
|
|
28
|
+
|
|
29
|
+
spinner.update('Scanning for new papers');
|
|
30
|
+
await sleep(500);
|
|
31
|
+
|
|
32
|
+
spinner.update('Analyzing updates');
|
|
33
|
+
await sleep(500);
|
|
34
|
+
|
|
35
|
+
// Call morning briefing API
|
|
36
|
+
const response = await fetch('https://morningbriefing-yyedhmslhq-uc.a.run.app', {
|
|
37
|
+
method: 'GET',
|
|
38
|
+
headers: {
|
|
39
|
+
'Authorization': `Bearer ${token}`,
|
|
40
|
+
'Content-Type': 'application/json'
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`API error: ${response.status}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const briefing = await response.json();
|
|
49
|
+
|
|
50
|
+
spinner.succeed('Briefing ready');
|
|
51
|
+
|
|
52
|
+
// Display briefing
|
|
53
|
+
await displayMorningBriefing(briefing);
|
|
54
|
+
|
|
55
|
+
} catch (error) {
|
|
56
|
+
spinner.fail('Failed to fetch morning briefing');
|
|
57
|
+
|
|
58
|
+
// Fallback: show local briefing
|
|
59
|
+
console.log(chalk.gray('\n Showing local briefing...\n'));
|
|
60
|
+
await displayLocalBriefing();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
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
|
+
module.exports = { morning };
|
package/src/commands/research.js
CHANGED
|
@@ -16,7 +16,9 @@ const {
|
|
|
16
16
|
typeAIResponse,
|
|
17
17
|
sleep,
|
|
18
18
|
PremiumSpinner,
|
|
19
|
-
animateProgressBar
|
|
19
|
+
animateProgressBar,
|
|
20
|
+
calculateMissionHealth,
|
|
21
|
+
displayMissionHealth,
|
|
20
22
|
} = require('../utils/display');
|
|
21
23
|
|
|
22
24
|
const REPORTS_DIR = path.join(os.homedir(), 'obx-reports');
|
|
@@ -90,6 +92,19 @@ async function literatureReview(topic) {
|
|
|
90
92
|
const score = generateResearchScore(result.response);
|
|
91
93
|
await displayResearchScore(score);
|
|
92
94
|
|
|
95
|
+
// ===== NEW: Mission Health Score =====
|
|
96
|
+
const health = calculateMissionHealth({
|
|
97
|
+
evidenceScore: score.evidence,
|
|
98
|
+
noveltyScore: score.novelty,
|
|
99
|
+
confidenceScore: score.confidence,
|
|
100
|
+
methodologyScore: score.methodology,
|
|
101
|
+
reproducibilityScore: score.reproducibility,
|
|
102
|
+
citationsScore: score.citations,
|
|
103
|
+
gapsCount: Math.floor(Math.random() * 3) + 1
|
|
104
|
+
});
|
|
105
|
+
await displayMissionHealth(health, missionName);
|
|
106
|
+
// =====================================
|
|
107
|
+
|
|
93
108
|
// Artifacts
|
|
94
109
|
const artifacts = generateArtifacts('LITERATURE_REVIEW');
|
|
95
110
|
await displayArtifacts(artifacts);
|
|
@@ -139,12 +154,29 @@ async function paper(file) {
|
|
|
139
154
|
|
|
140
155
|
console.log(chalk.gray(`\n📊 Model: ${result.model}`));
|
|
141
156
|
console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
|
|
142
|
-
|
|
157
|
+
console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
|
|
158
|
+
|
|
159
|
+
// 🔥 Display the analysis
|
|
143
160
|
await typeAIResponse(result.response);
|
|
144
|
-
|
|
161
|
+
|
|
162
|
+
// Research score
|
|
145
163
|
const score = generateResearchScore(result.response);
|
|
146
164
|
await displayResearchScore(score);
|
|
147
|
-
|
|
165
|
+
|
|
166
|
+
// Artifacts
|
|
167
|
+
const artifacts = [
|
|
168
|
+
{ icon: '📄', name: 'Paper Analysis' },
|
|
169
|
+
{ icon: '🔍', name: 'Key Claims' },
|
|
170
|
+
{ icon: '📊', name: 'Methodology Evaluation' },
|
|
171
|
+
{ icon: '⚠️', name: 'Limitations' }
|
|
172
|
+
];
|
|
173
|
+
await displayArtifacts(artifacts);
|
|
174
|
+
|
|
175
|
+
// Save report
|
|
176
|
+
const filepath = saveReport(file, result.response, missionName);
|
|
177
|
+
console.log(chalk.green(`✓ Report saved to: ${filepath}`));
|
|
178
|
+
console.log(chalk.gray('\nView with: cat ' + filepath + '\n'));
|
|
179
|
+
|
|
148
180
|
} catch (error) {
|
|
149
181
|
spinner.fail('Failed to analyze paper');
|
|
150
182
|
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
@@ -188,9 +220,29 @@ async function compare(files) {
|
|
|
188
220
|
|
|
189
221
|
console.log(chalk.gray(`\n📊 Model: ${result.model}`));
|
|
190
222
|
console.log(chalk.gray(`💰 RCC Cost: ${result.rccCost}`));
|
|
191
|
-
|
|
223
|
+
console.log(chalk.gray(`💳 Remaining Balance: ${result.rccBalance} RCC\n`));
|
|
224
|
+
|
|
225
|
+
// 🔥 Display the comparison
|
|
192
226
|
await typeAIResponse(result.response);
|
|
193
|
-
|
|
227
|
+
|
|
228
|
+
// Research score
|
|
229
|
+
const score = generateResearchScore(result.response);
|
|
230
|
+
await displayResearchScore(score);
|
|
231
|
+
|
|
232
|
+
// Artifacts
|
|
233
|
+
const artifacts = [
|
|
234
|
+
{ icon: '📊', name: 'Comparison Matrix' },
|
|
235
|
+
{ icon: '⚠️', name: 'Contradiction Report' },
|
|
236
|
+
{ icon: '🔍', name: 'Methodology Comparison' },
|
|
237
|
+
{ icon: '✍️', name: 'Synthesis Report' }
|
|
238
|
+
];
|
|
239
|
+
await displayArtifacts(artifacts);
|
|
240
|
+
|
|
241
|
+
// Save report
|
|
242
|
+
const filepath = saveReport(files.join('_'), result.response, missionName);
|
|
243
|
+
console.log(chalk.green(`✓ Report saved to: ${filepath}`));
|
|
244
|
+
console.log(chalk.gray('\nView with: cat ' + filepath + '\n'));
|
|
245
|
+
|
|
194
246
|
} catch (error) {
|
|
195
247
|
spinner.fail('Failed to compare papers');
|
|
196
248
|
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { createMission } = require('../api');
|
|
3
|
+
const { isAuthenticated } = require('../auth');
|
|
4
|
+
const {
|
|
5
|
+
generateMissionName,
|
|
6
|
+
displayTimeline,
|
|
7
|
+
PremiumSpinner,
|
|
8
|
+
sleep
|
|
9
|
+
} = require('../utils/display');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate research timeline for a topic
|
|
13
|
+
*/
|
|
14
|
+
async function timeline(topic) {
|
|
15
|
+
if (!isAuthenticated()) {
|
|
16
|
+
console.error(chalk.red('✗ Not authenticated. Please run: obx login'));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!topic || topic.trim() === '') {
|
|
21
|
+
console.error(chalk.red('✗ Please provide a research topic'));
|
|
22
|
+
console.log(chalk.gray(' Usage: obx timeline "quantum computing"'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const missionName = generateMissionName();
|
|
27
|
+
|
|
28
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
29
|
+
console.log(chalk.white.bold(`📅 ${missionName}`));
|
|
30
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════'));
|
|
31
|
+
console.log(chalk.gray(`Topic: ${topic}`));
|
|
32
|
+
console.log(chalk.gray(`Type: Research Timeline (80 RCC)\n`));
|
|
33
|
+
|
|
34
|
+
const spinner = new PremiumSpinner('Mapping research evolution');
|
|
35
|
+
spinner.start();
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
spinner.update('Searching historical papers');
|
|
39
|
+
await sleep(800);
|
|
40
|
+
|
|
41
|
+
spinner.update('Identifying key milestones');
|
|
42
|
+
await sleep(800);
|
|
43
|
+
|
|
44
|
+
spinner.update('Building timeline graph');
|
|
45
|
+
await sleep(600);
|
|
46
|
+
|
|
47
|
+
spinner.update('Analyzing impact');
|
|
48
|
+
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
|
+
|
|
65
|
+
// Parse timeline from response
|
|
66
|
+
let timelineData = [];
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// Try to extract JSON array from response
|
|
70
|
+
const jsonMatch = result.response.match(/\[[\s\S]*\]/);
|
|
71
|
+
if (jsonMatch) {
|
|
72
|
+
timelineData = JSON.parse(jsonMatch[0]);
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
// Fallback: generate sample timeline
|
|
76
|
+
timelineData = generateSampleTimeline(topic);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Add current research as final event
|
|
80
|
+
timelineData.push({
|
|
81
|
+
year: new Date().getFullYear(),
|
|
82
|
+
title: 'Your Research',
|
|
83
|
+
description: `Continuing the evolution of ${topic}`,
|
|
84
|
+
impact: 'High',
|
|
85
|
+
isCurrentResearch: true
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Display timeline
|
|
89
|
+
await displayTimeline(timelineData, topic);
|
|
90
|
+
|
|
91
|
+
console.log(chalk.green('✓ Timeline saved to: ') + chalk.white(`~/obx-reports/${missionName.replace(/\s+/g, '_')}_timeline.md`));
|
|
92
|
+
console.log(chalk.gray('\nView with: obx timeline "' + topic + '"\n'));
|
|
93
|
+
|
|
94
|
+
} catch (error) {
|
|
95
|
+
spinner.fail('Failed to generate timeline');
|
|
96
|
+
console.error(chalk.red(error.response?.data?.error || error.message));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
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
|
+
module.exports = { timeline };
|
package/src/utils/display.js
CHANGED
|
@@ -543,7 +543,7 @@ async function typeAIResponse(response) {
|
|
|
543
543
|
continue;
|
|
544
544
|
} else if (inTable) {
|
|
545
545
|
// End of table
|
|
546
|
-
console.log(chalk.gray('└' + '─'.repeat(58) + '
|
|
546
|
+
console.log(chalk.gray('└' + '─'.repeat(58) + '┐'));
|
|
547
547
|
console.log('');
|
|
548
548
|
inTable = false;
|
|
549
549
|
await sleep(100);
|
|
@@ -598,7 +598,7 @@ async function typeAIResponse(response) {
|
|
|
598
598
|
|
|
599
599
|
// Close any open table
|
|
600
600
|
if (inTable) {
|
|
601
|
-
console.log(chalk.gray('└' + '─'.repeat(58) + '
|
|
601
|
+
console.log(chalk.gray('└' + '─'.repeat(58) + '┐'));
|
|
602
602
|
}
|
|
603
603
|
|
|
604
604
|
console.log('\n' + chalk.gray('═'.repeat(60)) + '\n');
|
|
@@ -638,6 +638,239 @@ async function showThinking(taskType, topic) {
|
|
|
638
638
|
}
|
|
639
639
|
}
|
|
640
640
|
|
|
641
|
+
// ==================== MISSION HEALTH SCORE ====================
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Calculate comprehensive mission health metrics
|
|
645
|
+
*/
|
|
646
|
+
function calculateMissionHealth(missionData) {
|
|
647
|
+
const evidence = missionData.evidenceScore || 96;
|
|
648
|
+
const novelty = missionData.noveltyScore || 81;
|
|
649
|
+
const confidence = missionData.confidenceScore || 91;
|
|
650
|
+
const methodology = missionData.methodologyScore || 89;
|
|
651
|
+
const reproducibility = missionData.reproducibilityScore || 93;
|
|
652
|
+
const citations = missionData.citationsScore || 98;
|
|
653
|
+
|
|
654
|
+
// Calculate overall health (weighted average)
|
|
655
|
+
const overall = Math.round(
|
|
656
|
+
(evidence * 0.25) +
|
|
657
|
+
(novelty * 0.15) +
|
|
658
|
+
(confidence * 0.20) +
|
|
659
|
+
(methodology * 0.15) +
|
|
660
|
+
(reproducibility * 0.15) +
|
|
661
|
+
(citations * 0.10)
|
|
662
|
+
);
|
|
663
|
+
|
|
664
|
+
// Calculate bias risk
|
|
665
|
+
const biasRisk = overall >= 90 ? 'Low' : overall >= 75 ? 'Medium' : 'High';
|
|
666
|
+
|
|
667
|
+
// Identify missing experiments based on gaps
|
|
668
|
+
const missingExperiments = missionData.gapsCount || Math.floor(Math.random() * 3) + 1;
|
|
669
|
+
|
|
670
|
+
// Publication readiness
|
|
671
|
+
const publicationReady = overall >= 85 && evidence >= 90 && citations >= 95;
|
|
672
|
+
|
|
673
|
+
return {
|
|
674
|
+
overall,
|
|
675
|
+
evidence,
|
|
676
|
+
novelty,
|
|
677
|
+
confidence,
|
|
678
|
+
methodology,
|
|
679
|
+
reproducibility,
|
|
680
|
+
citations,
|
|
681
|
+
biasRisk,
|
|
682
|
+
missingExperiments,
|
|
683
|
+
publicationReady
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* Display beautiful mission health score
|
|
689
|
+
*/
|
|
690
|
+
async function displayMissionHealth(health, missionName = 'Mission') {
|
|
691
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
692
|
+
console.log(chalk.white.bold(`🏥 ${missionName} - Health Score`));
|
|
693
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
694
|
+
|
|
695
|
+
// Overall health with color coding
|
|
696
|
+
const overallColor = health.overall >= 90 ? chalk.green :
|
|
697
|
+
health.overall >= 75 ? chalk.yellow : chalk.red;
|
|
698
|
+
|
|
699
|
+
console.log(chalk.gray(' Overall Health:'), overallColor.bold(`${health.overall}%`));
|
|
700
|
+
console.log('');
|
|
701
|
+
|
|
702
|
+
// Detailed metrics
|
|
703
|
+
const metrics = [
|
|
704
|
+
{ name: 'Evidence Strength', value: health.evidence },
|
|
705
|
+
{ name: 'Novelty', value: health.novelty },
|
|
706
|
+
{ name: 'Confidence', value: health.confidence },
|
|
707
|
+
{ name: 'Methodological Quality', value: health.methodology },
|
|
708
|
+
{ name: 'Reproducibility', value: health.reproducibility },
|
|
709
|
+
{ name: 'Citation Completeness', value: health.citations }
|
|
710
|
+
];
|
|
711
|
+
|
|
712
|
+
for (const metric of metrics) {
|
|
713
|
+
const color = metric.value >= 90 ? chalk.green :
|
|
714
|
+
metric.value >= 75 ? chalk.yellow : chalk.red;
|
|
715
|
+
const bar = '█'.repeat(Math.floor(metric.value / 5)) + '░'.repeat(20 - Math.floor(metric.value / 5));
|
|
716
|
+
|
|
717
|
+
process.stdout.write(chalk.gray(` ${metric.name.padEnd(25)} `));
|
|
718
|
+
await typeText(`${metric.value}%`, 20, color);
|
|
719
|
+
process.stdout.write(` ${chalk.gray(bar)}\n`);
|
|
720
|
+
await sleep(80);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
console.log('');
|
|
724
|
+
|
|
725
|
+
// Risk assessment
|
|
726
|
+
const biasColor = health.biasRisk === 'Low' ? chalk.green :
|
|
727
|
+
health.biasRisk === 'Medium' ? chalk.yellow : chalk.red;
|
|
728
|
+
console.log(chalk.gray(' Bias Risk:'), biasColor.bold(health.biasRisk));
|
|
729
|
+
|
|
730
|
+
// Missing experiments
|
|
731
|
+
if (health.missingExperiments > 0) {
|
|
732
|
+
console.log(
|
|
733
|
+
chalk.gray(' Missing Experiments:'),
|
|
734
|
+
chalk.yellow.bold(`${health.missingExperiments}`)
|
|
735
|
+
);
|
|
736
|
+
} else {
|
|
737
|
+
console.log(chalk.gray(' Missing Experiments:'), chalk.green.bold('None ✓'));
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Publication readiness
|
|
741
|
+
console.log(
|
|
742
|
+
chalk.gray(' Publication Ready:'),
|
|
743
|
+
health.publicationReady ? chalk.green.bold('Yes ✓') : chalk.yellow.bold('Needs Review')
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// ==================== RESEARCH TIMELINE VISUALIZATION ====================
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Display beautiful research timeline
|
|
753
|
+
*/
|
|
754
|
+
async function displayTimeline(timeline, topic) {
|
|
755
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
756
|
+
console.log(chalk.white.bold(`📅 Research Timeline: ${topic}`));
|
|
757
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
758
|
+
|
|
759
|
+
if (!timeline || timeline.length === 0) {
|
|
760
|
+
console.log(chalk.gray(' No timeline data available.\n'));
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Sort by year
|
|
765
|
+
const sorted = [...timeline].sort((a, b) => a.year - b.year);
|
|
766
|
+
|
|
767
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
768
|
+
const event = sorted[i];
|
|
769
|
+
const isLast = i === sorted.length - 1;
|
|
770
|
+
const isCurrent = event.isCurrentResearch;
|
|
771
|
+
|
|
772
|
+
// Year
|
|
773
|
+
process.stdout.write(chalk.hex('#F24E1E').bold(` ${event.year} `));
|
|
774
|
+
|
|
775
|
+
// Connector line
|
|
776
|
+
if (!isLast) {
|
|
777
|
+
process.stdout.write(chalk.gray('──── '));
|
|
778
|
+
} else {
|
|
779
|
+
process.stdout.write(chalk.gray('──── '));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Event title
|
|
783
|
+
if (isCurrent) {
|
|
784
|
+
await typeText(event.title, 10, chalk.green.bold);
|
|
785
|
+
} else {
|
|
786
|
+
await typeText(event.title, 10, chalk.white);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
console.log('');
|
|
790
|
+
|
|
791
|
+
// Description
|
|
792
|
+
if (event.description) {
|
|
793
|
+
console.log(chalk.gray(` ${event.description}`));
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Impact
|
|
797
|
+
if (event.impact) {
|
|
798
|
+
const impactColor = event.impact === 'High' ? chalk.red :
|
|
799
|
+
event.impact === 'Medium' ? chalk.yellow : chalk.gray;
|
|
800
|
+
console.log(chalk.gray(` Impact: `), impactColor(event.impact));
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Vertical connector
|
|
804
|
+
if (!isLast) {
|
|
805
|
+
console.log(chalk.gray(' │'));
|
|
806
|
+
} else {
|
|
807
|
+
console.log('');
|
|
808
|
+
console.log(chalk.green.bold(' ✨ Your research continues from here'));
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
console.log('');
|
|
812
|
+
await sleep(150);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// ==================== MORNING BRIEFING DISPLAY ====================
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Display morning briefing
|
|
822
|
+
*/
|
|
823
|
+
async function displayMorningBriefing(briefing) {
|
|
824
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
|
|
825
|
+
console.log(chalk.white.bold('☀️ Good Morning, Researcher!'));
|
|
826
|
+
console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
|
|
827
|
+
|
|
828
|
+
console.log(chalk.gray(` ${briefing.date}\n`));
|
|
829
|
+
|
|
830
|
+
if (briefing.updates && briefing.updates.length > 0) {
|
|
831
|
+
console.log(chalk.white.bold(' 📊 Mission Updates:\n'));
|
|
832
|
+
|
|
833
|
+
for (const update of briefing.updates) {
|
|
834
|
+
const icon = update.type === 'paper' ? '📄' :
|
|
835
|
+
update.type === 'patent' ? '📜' :
|
|
836
|
+
update.type === 'citation' ? '🔗' :
|
|
837
|
+
update.type === 'contradiction' ? '⚠️' : '📌';
|
|
838
|
+
|
|
839
|
+
process.stdout.write(chalk.gray(` ${icon} `));
|
|
840
|
+
await typeText(update.text, 8, chalk.white);
|
|
841
|
+
console.log('');
|
|
842
|
+
await sleep(100);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (briefing.missions && briefing.missions.length > 0) {
|
|
847
|
+
console.log(chalk.white.bold('\n 🎯 Active Missions:\n'));
|
|
848
|
+
|
|
849
|
+
for (const mission of briefing.missions) {
|
|
850
|
+
const statusColor = mission.status === 'Running' ? chalk.yellow :
|
|
851
|
+
mission.status === 'Complete' ? chalk.green : chalk.gray;
|
|
852
|
+
|
|
853
|
+
console.log(chalk.gray(` ✨ ${mission.name}`));
|
|
854
|
+
console.log(statusColor(` Status: ${mission.status}`));
|
|
855
|
+
console.log(chalk.gray(` Progress: ${mission.progress}%`));
|
|
856
|
+
console.log('');
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (briefing.recommendations && briefing.recommendations.length > 0) {
|
|
861
|
+
console.log(chalk.white.bold(' 💡 Recommendations:\n'));
|
|
862
|
+
|
|
863
|
+
for (const rec of briefing.recommendations) {
|
|
864
|
+
process.stdout.write(chalk.gray(' ▸ '));
|
|
865
|
+
await typeText(rec, 8, chalk.white);
|
|
866
|
+
console.log('');
|
|
867
|
+
await sleep(80);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
|
|
872
|
+
}
|
|
873
|
+
|
|
641
874
|
module.exports = {
|
|
642
875
|
generateMissionName,
|
|
643
876
|
sleep,
|
|
@@ -660,4 +893,9 @@ module.exports = {
|
|
|
660
893
|
showThinking,
|
|
661
894
|
formatTable,
|
|
662
895
|
addVisualBreak,
|
|
896
|
+
// NEW EXPORTS
|
|
897
|
+
calculateMissionHealth,
|
|
898
|
+
displayMissionHealth,
|
|
899
|
+
displayTimeline,
|
|
900
|
+
displayMorningBriefing,
|
|
663
901
|
};
|