neurondb 1.1.0 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neurondb",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "N-Bash — Interactive SNL terminal and remote bash executor for NeuronDB",
5
5
  "bin": {
6
6
  "neuron": "./bin/cli.js",
package/src/app.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  initScreen, appendOutput, onInput, loadHistory,
14
14
  printResult, printRemote, printInfo, printHelp,
15
15
  printSuccess, printErrorOutput, clearOutput, destroyScreen,
16
- onLogout,
16
+ onLogout, isBashMode,
17
17
  } from './ui.js';
18
18
  import {
19
19
  VERSION, POLL_INTERVAL_MS, HEARTBEAT_INTERVAL_MS,
@@ -179,6 +179,30 @@ async function handleInput(state, input) {
179
179
  return;
180
180
  }
181
181
 
182
+ // BASH mode — execute locally in terminal
183
+ if (isBashMode()) {
184
+ try {
185
+ const { promise } = executeStreaming(input, state.homeDir, {
186
+ timeoutMs: state.bashTimeout || 30000,
187
+ onLine: (line, stream) => {
188
+ if (stream === 'stderr') {
189
+ appendOutput(`{red-fg}${line}{/red-fg}`);
190
+ } else {
191
+ appendOutput(`{#888888-fg}${line}{/#888888-fg}`);
192
+ }
193
+ },
194
+ });
195
+ const result = await promise;
196
+ if (result.exit_code !== 0) {
197
+ appendOutput(`{red-fg}exit code: ${result.exit_code}{/red-fg}`);
198
+ }
199
+ appendOutput(`{#555555-fg}(${result.duration_ms}ms){/#555555-fg}`);
200
+ } catch (err) {
201
+ printErrorOutput(`Bash error: ${err.message}`);
202
+ }
203
+ return;
204
+ }
205
+
182
206
  // Execute SNL on server
183
207
  try {
184
208
  const result = await state.api.snl(input);
package/src/config.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * N-Bash Configuration Constants
3
3
  */
4
4
 
5
- export const VERSION = '1.1.0';
5
+ export const VERSION = '1.2.0';
6
6
  export const POLL_INTERVAL_MS = 1500;
7
7
  export const HEARTBEAT_INTERVAL_MS = 30000;
8
8
  export const EXEC_TIMEOUT_MS = 30000;
@@ -22,17 +22,21 @@ export const NODES = {
22
22
 
23
23
  /** Blocked commands — rejected before execution */
24
24
  export const BLOCKED_COMMANDS = [
25
+ // Dangerous system commands
25
26
  'sudo', 'su', 'chroot', 'mount', 'umount', 'mkfs', 'dd',
26
27
  'reboot', 'shutdown', 'poweroff', 'halt', 'init',
27
28
  'passwd', 'useradd', 'userdel', 'usermod', 'groupadd',
28
29
  'iptables', 'ip6tables', 'nft', 'firewall-cmd',
29
- 'systemctl', 'service', 'journalctl',
30
+ 'systemctl', 'service',
30
31
  'fdisk', 'parted', 'mkswap', 'swapon', 'swapoff',
31
- // Interactive commands that hang (no stdout, wait for input)
32
- 'top', 'htop', 'btop', 'vi', 'vim', 'nvim', 'nano', 'pico', 'emacs',
33
- 'less', 'more', 'man', 'watch', 'tail -f', 'ssh', 'telnet', 'ftp',
34
- 'python', 'python3', 'node', 'irb', 'ruby', 'lua', // REPLs without args
35
- 'mysql', 'psql', 'mongo', 'redis-cli', // DB shells without args
32
+ // Editors (need full TTY, no stdout)
33
+ 'vi', 'vim', 'nvim', 'nano', 'pico', 'emacs',
34
+ // Network tools that open connections
35
+ 'ssh', 'telnet', 'ftp',
36
+ // NOTE: top, htop, watch, tail -f, less, more, man, journalctl
37
+ // are now ALLOWED — streaming output handles them (timeout kills them)
38
+ // NOTE: python, node, ruby, lua, mysql, psql, mongo, redis-cli
39
+ // are now ALLOWED — useful for one-liners (e.g. python3 -c "print(1+1)")
36
40
  ];
37
41
 
38
42
  /** Blocked path prefixes — prevent access outside sandbox */
package/src/ui.js CHANGED
@@ -27,6 +27,7 @@ let cursorPos = 0;
27
27
  let onSubmitCallback = null;
28
28
  let onLogoutCallback = null;
29
29
  let logoutPending = false;
30
+ let bashMode = false; // false = NDB (SNL), true = BASH (direct terminal)
30
31
 
31
32
  const MIN_INPUT_HEIGHT = 3; // border top + 1 line + border bottom
32
33
  const MAX_INPUT_HEIGHT = 12; // max expansion
@@ -309,6 +310,7 @@ function handleCSI(params, final) {
309
310
  case 'D': cursorLeft(); break; // Left
310
311
  case 'H': cursorPos = 0; renderPrompt(); break; // Home
311
312
  case 'F': cursorPos = inputBuffer.length; renderPrompt(); break; // End
313
+ case 'Z': toggleBashMode(); break; // Shift+Tab — toggle NDB/BASH mode
312
314
  case '~':
313
315
  if (params === '3') deleteChar(); // Delete
314
316
  else if (params === '1') { cursorPos = 0; renderPrompt(); } // Home
@@ -319,6 +321,13 @@ function handleCSI(params, final) {
319
321
  }
320
322
  }
321
323
 
324
+ function toggleBashMode() {
325
+ bashMode = !bashMode;
326
+ const mode = bashMode ? '{green-fg}BASH{/green-fg}' : '{cyan-fg}NDB{/cyan-fg}';
327
+ log(`{yellow-fg}» Switched to ${mode}{yellow-fg} mode (Shift+Tab to toggle){/yellow-fg}`);
328
+ renderPrompt();
329
+ }
330
+
322
331
  function submitInput() {
323
332
  const input = inputBuffer.trim();
324
333
  inputBuffer = '';
@@ -439,8 +448,10 @@ function updateStatus(info) {
439
448
  function renderPrompt() {
440
449
  if (!inputBox || !screen) return;
441
450
 
442
- const prompt = '{cyan-fg}nbash>{/cyan-fg} ';
443
- const promptLen = 7; // "nbash> " visual length
451
+ const prompt = bashMode
452
+ ? '{green-fg}bash${/green-fg} '
453
+ : '{cyan-fg}nbash>{/cyan-fg} ';
454
+ const promptLen = bashMode ? 6 : 7; // "bash$ " or "nbash> " visual length
444
455
 
445
456
  // Calculate available width inside the box (minus borders and padding)
446
457
  const innerWidth = screen.cols - 4; // 2 border + 2 padding
@@ -545,6 +556,11 @@ export function onInput(callback) {
545
556
  onSubmitCallback = callback;
546
557
  }
547
558
 
559
+ /** Check if currently in BASH mode */
560
+ export function isBashMode() {
561
+ return bashMode;
562
+ }
563
+
548
564
  /** Load history from file */
549
565
  export function loadHistory(lines) {
550
566
  inputHistory = lines || [];