omnibiofex 4.0.0 → 4.2.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 CHANGED
@@ -46,6 +46,21 @@ program.command('hypothesis').description('Generate hypotheses').argument('<topi
46
46
  const { timeline } = require('../src/commands/timeline');
47
47
  program.command('timeline').description('Research timeline').argument('<topic>').action(timeline);
48
48
 
49
+ // ==================== DIAGRAM COMMAND ====================
50
+ const { diagram } = require('../src/commands/diagram');
51
+
52
+ program
53
+ .command('diagram')
54
+ .description('šŸ“Š Generate ASCII research ecosystem diagrams')
55
+ .argument('<topic>', 'Research topic')
56
+ .option('--style <style>', 'Diagram style: minimal, detailed, flowchart, network', 'detailed')
57
+ .option('--save', 'Save diagram to file')
58
+ .option('--publish', 'Save and prepare for publishing')
59
+ .action(async (topic, options) => {
60
+ await diagram(topic, options);
61
+ });
62
+
63
+ // ==================== DATA COMMANDS ====================
49
64
  const { dataset, code } = require('../src/commands/data');
50
65
  program.command('dataset').description('Analyze dataset').argument('<file>').action(dataset);
51
66
  program.command('code').description('Review code').argument('[directory]', '.').action(code);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnibiofex",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "OmniBioFex X - The Autonomous Research Operating System",
5
5
  "main": "bin/obx",
6
6
  "bin": {
@@ -0,0 +1,305 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { getAuthToken, isAuthenticated } = require('../auth');
6
+ const { PremiumSpinner, sleep } = require('../utils/display');
7
+
8
+ const BACKEND_URL = 'https://obxvisionassistant-yyedhmslhq-uc.a.run.app';
9
+ const DIAGRAMS_DIR = path.join(os.homedir(), 'obx-diagrams');
10
+
11
+ // Ensure diagrams directory exists
12
+ if (!fs.existsSync(DIAGRAMS_DIR)) {
13
+ fs.mkdirSync(DIAGRAMS_DIR, { recursive: true });
14
+ }
15
+
16
+ // Diagram styles with costs
17
+ const STYLES = {
18
+ minimal: { name: 'Minimal', cost: 50, description: 'Clean, simple flowchart' },
19
+ detailed: { name: 'Detailed', cost: 80, description: 'Comprehensive ecosystem' },
20
+ flowchart: { name: 'Flowchart', cost: 60, description: 'Step-by-step process' },
21
+ network: { name: 'Network', cost: 70, description: 'Interconnected nodes' }
22
+ };
23
+
24
+ // Generate ASCII banner
25
+ function banner(title, width = 80) {
26
+ const top = `ā•”${'═'.repeat(width)}ā•—`;
27
+ const bottom = `ā•š${'═'.repeat(width)}ā•`;
28
+ const padding = Math.max(0, width - title.length - 2);
29
+ const leftPad = Math.floor(padding / 2);
30
+ const rightPad = padding - leftPad;
31
+ const content = `ā•‘ ${' '.repeat(leftPad)}${title}${' '.repeat(rightPad)} ā•‘`;
32
+ return `${top}\n${content}\n${bottom}`;
33
+ }
34
+
35
+ // Generate node box
36
+ function node(text, width = 20) {
37
+ const safeText = text.substring(0, width - 2);
38
+ const padding = Math.max(0, width - safeText.length - 2);
39
+ const leftPad = Math.floor(padding / 2);
40
+ const rightPad = padding - leftPad;
41
+ const top = `ā”Œ${'─'.repeat(width)}┐`;
42
+ const bottom = `ā””${'─'.repeat(width)}ā”˜`;
43
+ const content = `│ ${' '.repeat(leftPad)}${safeText}${' '.repeat(rightPad)} │`;
44
+ return `${top}\n${content}\n${bottom}`;
45
+ }
46
+
47
+ // Generate arrow
48
+ function arrow(direction = 'down') {
49
+ switch (direction) {
50
+ case 'down': return '│\nā–¼';
51
+ case 'right': return '───▶';
52
+ case 'left': return '◀───';
53
+ case 'up': return 'ā–²\n│';
54
+ default: return '│\nā–¼';
55
+ }
56
+ }
57
+
58
+ // Generate detailed diagram
59
+ function generateDetailedDiagram(topic, data) {
60
+ const width = 80;
61
+ let diagram = banner(`${topic.toUpperCase()} RESEARCH ECOSYSTEM`, width) + '\n\n';
62
+
63
+ // Problem identification
64
+ diagram += `${' '.repeat(25)}${node('Research Problem', 25)}\n`;
65
+ diagram += `${' '.repeat(37)}${arrow('down')}\n\n`;
66
+
67
+ // Three input sources
68
+ const sources = data.components?.slice(0, 3) || ['Literature', 'Data', 'Theory'];
69
+ diagram += `${' '.repeat(5)}${node(sources[0] || 'Literature', 18)} ${node(sources[1] || 'Data', 18)} ${node(sources[2] || 'Theory', 18)}\n`;
70
+ diagram += `${' '.repeat(14)}\\ | /\n`;
71
+ diagram += `${' '.repeat(15)}\\ | /\n`;
72
+ diagram += `${' '.repeat(16)}\\ | /\n`;
73
+ diagram += `${' '.repeat(17)}ā–¼ ā–¼ ā–¼\n`;
74
+ diagram += `${' '.repeat(15)}${node('Integration Layer', 30)}\n`;
75
+ diagram += `${' '.repeat(29)}${arrow('down')}\n`;
76
+
77
+ // Analysis phase
78
+ diagram += `${' '.repeat(20)}${node('Analysis Phase', 25)}\n`;
79
+ diagram += `${' '.repeat(32)}${arrow('down')}\n\n`;
80
+
81
+ // Four analysis types
82
+ const methods = data.methods?.slice(0, 4) || ['Statistical', 'Qualitative', 'Comparative', 'Predictive'];
83
+ diagram += `${node(methods[0], 14)} ${node(methods[1], 14)} ${node(methods[2], 14)} ${node(methods[3], 14)}\n`;
84
+ diagram += `${' '.repeat(7)}\\ | | /\n`;
85
+ diagram += `${' '.repeat(8)}\\ | | /\n`;
86
+ diagram += `${' '.repeat(9)}\\ | | /\n`;
87
+ diagram += `${' '.repeat(10)}ā–¼ ā–¼ ā–¼ ā–¼\n`;
88
+ diagram += `${' '.repeat(15)}${node('Synthesis & Insights', 35)}\n`;
89
+ diagram += `${' '.repeat(32)}${arrow('down')}\n`;
90
+
91
+ // Output phase
92
+ diagram += `${' '.repeat(20)}${node('Output Phase', 25)}\n`;
93
+ diagram += `${' '.repeat(32)}${arrow('down')}\n\n`;
94
+
95
+ // Three outputs
96
+ const outputs = data.outputs?.slice(0, 3) || ['Publication', 'Implementation', 'Future Work'];
97
+ diagram += `${node(outputs[0], 18)} ${node(outputs[1], 18)} ${node(outputs[2], 18)}\n`;
98
+
99
+ return diagram;
100
+ }
101
+
102
+ // Generate minimal diagram
103
+ function generateMinimalDiagram(topic, data) {
104
+ const width = 60;
105
+ let diagram = banner(topic.toUpperCase(), width) + '\n\n';
106
+
107
+ diagram += `${' '.repeat(20)}${node('Problem', 20)}\n`;
108
+ diagram += `${' '.repeat(29)}${arrow('down')}\n`;
109
+ diagram += `${' '.repeat(10)}${node('Research', 20)}\n`;
110
+ diagram += `${' '.repeat(19)}${arrow('down')}\n`;
111
+ diagram += `${' '.repeat(10)}${node('Analysis', 20)}\n`;
112
+ diagram += `${' '.repeat(19)}${arrow('down')}\n`;
113
+ diagram += `${' '.repeat(10)}${node('Solution', 20)}\n`;
114
+
115
+ return diagram;
116
+ }
117
+
118
+ // Generate flowchart diagram
119
+ function generateFlowchartDiagram(topic, data) {
120
+ const width = 60;
121
+ const steps = data.steps?.length > 0 ? data.steps : ['Research', 'Analysis', 'Implementation'];
122
+ let diagram = banner(`${topic.toUpperCase()} WORKFLOW`, width) + '\n\n';
123
+
124
+ steps.forEach((step, i) => {
125
+ const stepText = `Step ${i + 1}: ${step}`;
126
+ diagram += `${' '.repeat(15)}${node(stepText, 45)}\n`;
127
+ if (i < steps.length - 1) {
128
+ diagram += `${' '.repeat(37)}${arrow('down')}\n`;
129
+ }
130
+ });
131
+
132
+ diagram += `\n${' '.repeat(25)}${node('āœ“ Complete', 20)}\n`;
133
+ return diagram;
134
+ }
135
+
136
+ // Generate network diagram
137
+ function generateNetworkDiagram(topic, data) {
138
+ const width = 70;
139
+ const nodes = data.nodes?.slice(0, 3) || ['Component A', 'Component B', 'Component C'];
140
+ let diagram = banner(`${topic.toUpperCase()} NETWORK`, width) + '\n\n';
141
+
142
+ diagram += `${' '.repeat(25)}${node(topic, 25)}\n`;
143
+ diagram += `${' '.repeat(37)}|\n`;
144
+ diagram += `${' '.repeat(20)}ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”\n`;
145
+ diagram += `${' '.repeat(20)}│ │ │\n`;
146
+ diagram += `${' '.repeat(20)}ā–¼ ā–¼ ā–¼\n`;
147
+ diagram += `${node(nodes[0], 18)} ${node(nodes[1], 18)} ${node(nodes[2], 18)}\n`;
148
+ diagram += `${' '.repeat(9)}│ │ │\n`;
149
+ diagram += `${' '.repeat(9)}ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜\n`;
150
+ diagram += `${' '.repeat(18)}ā–¼\n`;
151
+ diagram += `${' '.repeat(15)}${node('Integration', 25)}\n`;
152
+
153
+ return diagram;
154
+ }
155
+
156
+ // Main diagram command
157
+ async function diagram(topic, options = {}) {
158
+ if (!isAuthenticated()) {
159
+ console.error(chalk.red('āœ— Not authenticated. Please run: obx login'));
160
+ process.exit(1);
161
+ return;
162
+ }
163
+
164
+ if (!topic) {
165
+ console.error(chalk.red('āœ— Please provide a topic'));
166
+ console.log(chalk.gray('Usage: obx diagram "topic" [--style minimal|detailed|flowchart|network] [--save]'));
167
+ process.exit(1);
168
+ return;
169
+ }
170
+
171
+ const style = options.style || 'detailed';
172
+ const save = options.save || false;
173
+ const cost = STYLES[style]?.cost || 80;
174
+
175
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════'));
176
+ console.log(chalk.white.bold('šŸ“Š ASCII DIAGRAM GENERATOR'));
177
+ console.log(chalk.hex('#F24E1E')('═══════════════════════════════════════════════════════════\n'));
178
+
179
+ console.log(chalk.white(` šŸ“Œ Topic: ${chalk.hex('#F24E1E')(topic)}`));
180
+ console.log(chalk.white(` šŸŽØ Style: ${chalk.hex('#F24E1E')(STYLES[style]?.name || 'Detailed')}`));
181
+ console.log(chalk.white(` šŸ’° Cost: ${chalk.green(cost + ' RCC')}`));
182
+
183
+ const spinner = new PremiumSpinner('Generating diagram');
184
+ spinner.start();
185
+
186
+ try {
187
+ const token = await getAuthToken();
188
+
189
+ spinner.update('Analyzing topic with AI');
190
+ await sleep(500);
191
+
192
+ // āœ… FIX: Use DEEP_RESEARCH task type (already supported by backend)
193
+ const response = await fetch(BACKEND_URL, {
194
+ method: 'POST',
195
+ headers: {
196
+ 'Content-Type': 'application/json',
197
+ 'Authorization': `Bearer ${token}`
198
+ },
199
+ body: JSON.stringify({
200
+ taskType: 'DEEP_RESEARCH', // ← Use existing task type
201
+ message: `Generate a structured breakdown of "${topic}" for an ASCII diagram.
202
+
203
+ Return ONLY a valid JSON object with this exact structure (no other text):
204
+ {
205
+ "components": ["component1", "component2", "component3", "component4"],
206
+ "methods": ["method1", "method2", "method3", "method4"],
207
+ "steps": ["step1", "step2", "step3", "step4", "step5"],
208
+ "nodes": ["node1", "node2", "node3"],
209
+ "outputs": ["output1", "output2", "output3"]
210
+ }
211
+
212
+ Make the components, methods, steps, nodes, and outputs specific to "${topic}".
213
+ Return ONLY the JSON object, nothing else.`,
214
+ model: 'deep'
215
+ })
216
+ });
217
+
218
+ if (!response.ok) {
219
+ const errorText = await response.text();
220
+ throw new Error(`Backend returned ${response.status}: ${errorText.substring(0, 100)}`);
221
+ }
222
+
223
+ spinner.update('Rendering ASCII art');
224
+ await sleep(500);
225
+
226
+ const data = await response.json();
227
+
228
+ // Parse AI response - extract JSON from the response
229
+ let aiData = {
230
+ components: [],
231
+ methods: [],
232
+ steps: [],
233
+ nodes: [],
234
+ outputs: []
235
+ };
236
+
237
+ try {
238
+ // Try to find JSON in the response
239
+ const responseText = data.response || '';
240
+ const jsonMatch = responseText.match(/\{[\s\S]*\}/);
241
+
242
+ if (jsonMatch) {
243
+ aiData = JSON.parse(jsonMatch[0]);
244
+ }
245
+ } catch (e) {
246
+ console.log(chalk.yellow(' ⚠ Using default structure'));
247
+ }
248
+
249
+ // Generate diagram based on style
250
+ let asciiDiagram;
251
+ switch (style) {
252
+ case 'minimal':
253
+ asciiDiagram = generateMinimalDiagram(topic, aiData);
254
+ break;
255
+ case 'flowchart':
256
+ asciiDiagram = generateFlowchartDiagram(topic, aiData);
257
+ break;
258
+ case 'network':
259
+ asciiDiagram = generateNetworkDiagram(topic, aiData);
260
+ break;
261
+ case 'detailed':
262
+ default:
263
+ asciiDiagram = generateDetailedDiagram(topic, aiData);
264
+ break;
265
+ }
266
+
267
+ spinner.succeed('āœ“ Diagram generated');
268
+
269
+ // Display diagram
270
+ console.log('\n' + chalk.cyan(asciiDiagram) + '\n');
271
+
272
+ // Save if requested
273
+ if (save) {
274
+ const timestamp = Date.now();
275
+ const safeTopic = topic.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 50);
276
+
277
+ // Save ASCII version
278
+ const txtFilename = `${safeTopic}-${timestamp}.txt`;
279
+ const txtPath = path.join(DIAGRAMS_DIR, txtFilename);
280
+ fs.writeFileSync(txtPath, asciiDiagram, 'utf8');
281
+ console.log(chalk.green(` šŸ’¾ Saved: ${txtPath}`));
282
+
283
+ // Save Markdown version
284
+ const mdFilename = `${safeTopic}-${timestamp}.md`;
285
+ const mdPath = path.join(DIAGRAMS_DIR, mdFilename);
286
+ const mdContent = `# ${topic} Research Diagram\n\n**Style:** ${STYLES[style].name}\n**Generated:** ${new Date().toLocaleString()}\n\n\`\`\`\n${asciiDiagram}\n\`\`\`\n`;
287
+ fs.writeFileSync(mdPath, mdContent, 'utf8');
288
+ console.log(chalk.green(` šŸ’¾ Saved: ${mdPath}`));
289
+ }
290
+
291
+ console.log(chalk.hex('#F24E1E')('\n═══════════════════════════════════════════════════════════\n'));
292
+
293
+ } catch (error) {
294
+ spinner.fail('Failed to generate diagram');
295
+ console.error(chalk.red(error.message));
296
+
297
+ if (error.message.includes('402') || error.message.includes('Insufficient')) {
298
+ console.log(chalk.yellow('\n šŸ’” You need more RCC credits. Run: obx buy'));
299
+ }
300
+
301
+ process.exit(1);
302
+ }
303
+ }
304
+
305
+ module.exports = { diagram, STYLES };