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