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 +15 -0
- package/package.json +1 -1
- package/src/commands/diagram.js +340 -0
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
|
@@ -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 };
|