devbonzai 2.2.307 → 2.2.308

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/cli.js CHANGED
@@ -71,7 +71,15 @@ async function main() {
71
71
  const utilsSrc = path.join(__dirname, 'templates', 'utils');
72
72
  const utilsDest = path.join(bonzaiDir, 'utils');
73
73
  copyDirectory(utilsSrc, utilsDest);
74
-
74
+
75
+ // Copy terminal-test.html
76
+ console.log('📝 Copying terminal-test.html...');
77
+ const terminalTestSrc = path.join(__dirname, 'templates', 'terminal-test.html');
78
+ const terminalTestDest = path.join(bonzaiDir, 'terminal-test.html');
79
+ if (fs.existsSync(terminalTestSrc)) {
80
+ fs.copyFileSync(terminalTestSrc, terminalTestDest);
81
+ }
82
+
75
83
  // Write .ignore file in bonzai directory
76
84
  const ignoreTargetPath = path.join(bonzaiDir, '.ignore');
77
85
 
@@ -109,6 +117,8 @@ async function main() {
109
117
  packageJson.dependencies.express = "^4.18.2";
110
118
  packageJson.dependencies.cors = "^2.8.5";
111
119
  packageJson.dependencies["@babel/parser"] = "^7.23.0";
120
+ packageJson.dependencies.ws = "^8.16.0";
121
+ packageJson.dependencies["node-pty"] = "^1.1.0";
112
122
 
113
123
  // Add script to run receiver
114
124
  if (!packageJson.scripts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devbonzai",
3
- "version": "2.2.307",
3
+ "version": "2.2.308",
4
4
  "description": "Quickly set up a local file server in any repository for browser-based file access",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -22,8 +22,10 @@
22
22
  "author": "",
23
23
  "license": "ISC",
24
24
  "dependencies": {
25
- "express": "^4.18.2",
25
+ "@babel/parser": "^7.23.0",
26
26
  "cors": "^2.8.5",
27
- "@babel/parser": "^7.23.0"
27
+ "express": "^4.18.2",
28
+ "node-pty": "^1.1.0",
29
+ "ws": "^8.16.0"
28
30
  }
29
31
  }
@@ -8,7 +8,8 @@ function indexHandler(req, res) {
8
8
  'POST /delete': 'Delete file or directory (body: {path})',
9
9
  'POST /open-cursor': 'Open Cursor (body: {path, line?})',
10
10
  'POST /shutdown': 'Gracefully shutdown the server',
11
- 'POST /scan_code_quality': 'Scan code quality (body: {projectPath})'
11
+ 'POST /scan_code_quality': 'Scan code quality (body: {projectPath})',
12
+ 'WS /terminal': 'Interactive terminal via WebSocket'
12
13
  },
13
14
  example: 'Try: /list or /read?path=README.md'
14
15
  });
@@ -0,0 +1,106 @@
1
+ const pty = require('node-pty');
2
+
3
+ // Store active terminal sessions
4
+ const terminals = new Map();
5
+
6
+ // Get default shell based on platform
7
+ function getDefaultShell() {
8
+ if (process.platform === 'win32') {
9
+ return process.env.COMSPEC || 'powershell.exe';
10
+ }
11
+ return process.env.SHELL || '/bin/bash';
12
+ }
13
+
14
+ // Create a new terminal session
15
+ function createTerminal(sessionId, cols = 80, rows = 24) {
16
+ const shell = getDefaultShell();
17
+
18
+ const ptyProcess = pty.spawn(shell, [], {
19
+ name: 'xterm-256color',
20
+ cols,
21
+ rows,
22
+ cwd: process.env.HOME || process.cwd(),
23
+ env: { ...process.env, TERM: 'xterm-256color' }
24
+ });
25
+
26
+ terminals.set(sessionId, {
27
+ pty: ptyProcess,
28
+ buffer: ''
29
+ });
30
+
31
+ return ptyProcess;
32
+ }
33
+
34
+ // HTTP handler for terminal info
35
+ function terminalHandler(req, res) {
36
+ res.json({
37
+ message: 'Terminal WebSocket API',
38
+ usage: {
39
+ websocket: 'ws://localhost:3001/terminal',
40
+ events: {
41
+ 'input': 'Send terminal input (data: string)',
42
+ 'resize': 'Resize terminal (cols: number, rows: number)',
43
+ 'output': 'Receive terminal output'
44
+ }
45
+ }
46
+ });
47
+ }
48
+
49
+ // WebSocket handler for terminal sessions
50
+ function setupTerminalWebSocket(wss) {
51
+ wss.on('connection', (ws) => {
52
+ const sessionId = Date.now().toString();
53
+ let ptyProcess;
54
+
55
+ try {
56
+ ptyProcess = createTerminal(sessionId);
57
+ console.log(`Terminal session ${sessionId} started`);
58
+ } catch (err) {
59
+ console.error('Failed to create terminal:', err.message);
60
+ ws.send(JSON.stringify({ type: 'error', message: 'Failed to create terminal: ' + err.message }));
61
+ ws.close();
62
+ return;
63
+ }
64
+
65
+ // Send terminal output to WebSocket client
66
+ ptyProcess.onData((data) => {
67
+ try {
68
+ ws.send(JSON.stringify({ type: 'output', data }));
69
+ } catch (e) {
70
+ // Client disconnected
71
+ }
72
+ });
73
+
74
+ ptyProcess.onExit(({ exitCode }) => {
75
+ ws.send(JSON.stringify({ type: 'exit', exitCode }));
76
+ ws.close();
77
+ });
78
+
79
+ // Handle incoming messages from client
80
+ ws.on('message', (message) => {
81
+ try {
82
+ const msg = JSON.parse(message);
83
+
84
+ switch (msg.type) {
85
+ case 'input':
86
+ ptyProcess.write(msg.data);
87
+ break;
88
+ case 'resize':
89
+ ptyProcess.resize(msg.cols, msg.rows);
90
+ break;
91
+ }
92
+ } catch (e) {
93
+ console.error('Terminal message error:', e);
94
+ }
95
+ });
96
+
97
+ // Cleanup on disconnect
98
+ ws.on('close', () => {
99
+ console.log(`Terminal session ${sessionId} closed`);
100
+ ptyProcess.kill();
101
+ terminals.delete(sessionId);
102
+ });
103
+ });
104
+ }
105
+
106
+ module.exports = { terminalHandler, setupTerminalWebSocket };
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const express = require('./node_modules/express');
4
- const cors = require('./node_modules/cors');
3
+ const express = require('express');
4
+ const cors = require('cors');
5
+ const http = require('http');
6
+ const { WebSocketServer } = require('ws');
5
7
 
6
8
  // Import handlers
7
9
  const indexHandler = require('./handlers/index');
@@ -11,8 +13,14 @@ const deleteHandler = require('./handlers/delete');
11
13
  const openCursorHandler = require('./handlers/open-cursor');
12
14
  const shutdownHandler = require('./handlers/shutdown');
13
15
  const scanCodeQualityHandler = require('./handlers/scan_code_quality');
16
+ const { terminalHandler, setupTerminalWebSocket } = require('./handlers/terminal');
14
17
 
15
18
  const app = express();
19
+ const server = http.createServer(app);
20
+
21
+ // WebSocket server for terminal
22
+ const wss = new WebSocketServer({ server, path: '/terminal' });
23
+ setupTerminalWebSocket(wss);
16
24
 
17
25
  app.use(cors());
18
26
  app.use(express.json());
@@ -25,8 +33,11 @@ app.post('/delete', deleteHandler);
25
33
  app.post('/open-cursor', openCursorHandler);
26
34
  app.post('/shutdown', shutdownHandler);
27
35
  app.post('/scan_code_quality', scanCodeQualityHandler);
36
+ app.get('/terminal', terminalHandler);
28
37
 
29
38
  const port = 3001;
30
- app.listen(port, () => {
39
+ server.listen(port, () => {
31
40
  console.log('📂 File server running on http://localhost:' + port);
41
+ console.log('🖥️ Terminal WebSocket available at ws://localhost:' + port + '/terminal');
32
42
  });
43
+
@@ -0,0 +1,104 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Terminal Test</title>
5
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ padding: 20px;
10
+ background: #1e1e1e;
11
+ font-family: sans-serif;
12
+ }
13
+ h1 {
14
+ color: #fff;
15
+ margin-bottom: 10px;
16
+ }
17
+ #status {
18
+ color: #888;
19
+ margin-bottom: 10px;
20
+ }
21
+ #terminal {
22
+ height: 400px;
23
+ }
24
+ </style>
25
+ </head>
26
+ <body>
27
+ <h1>Terminal Test</h1>
28
+ <div id="status">Connecting...</div>
29
+ <div id="terminal"></div>
30
+
31
+ <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
32
+ <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
33
+ <script>
34
+ const term = new Terminal({
35
+ cursorBlink: true,
36
+ fontSize: 14,
37
+ fontFamily: 'Menlo, Monaco, "Courier New", monospace',
38
+ theme: {
39
+ background: '#1e1e1e',
40
+ foreground: '#d4d4d4'
41
+ }
42
+ });
43
+
44
+ const fitAddon = new FitAddon.FitAddon();
45
+ term.loadAddon(fitAddon);
46
+
47
+ const terminalEl = document.getElementById('terminal');
48
+ const statusEl = document.getElementById('status');
49
+
50
+ term.open(terminalEl);
51
+ fitAddon.fit();
52
+
53
+ // Connect to WebSocket
54
+ const ws = new WebSocket('ws://localhost:3001/terminal');
55
+
56
+ ws.onopen = () => {
57
+ statusEl.textContent = 'Connected';
58
+ statusEl.style.color = '#4ec9b0';
59
+
60
+ // Send initial size
61
+ ws.send(JSON.stringify({
62
+ type: 'resize',
63
+ cols: term.cols,
64
+ rows: term.rows
65
+ }));
66
+ };
67
+
68
+ ws.onmessage = (event) => {
69
+ const msg = JSON.parse(event.data);
70
+ if (msg.type === 'output') {
71
+ term.write(msg.data);
72
+ } else if (msg.type === 'exit') {
73
+ statusEl.textContent = 'Session ended (exit code: ' + msg.exitCode + ')';
74
+ statusEl.style.color = '#f48771';
75
+ }
76
+ };
77
+
78
+ ws.onclose = () => {
79
+ statusEl.textContent = 'Disconnected';
80
+ statusEl.style.color = '#f48771';
81
+ };
82
+
83
+ ws.onerror = (err) => {
84
+ statusEl.textContent = 'Connection error';
85
+ statusEl.style.color = '#f48771';
86
+ };
87
+
88
+ // Send input to server
89
+ term.onData((data) => {
90
+ ws.send(JSON.stringify({ type: 'input', data }));
91
+ });
92
+
93
+ // Handle resize
94
+ window.addEventListener('resize', () => {
95
+ fitAddon.fit();
96
+ ws.send(JSON.stringify({
97
+ type: 'resize',
98
+ cols: term.cols,
99
+ rows: term.rows
100
+ }));
101
+ });
102
+ </script>
103
+ </body>
104
+ </html>