agentgui 1.0.489 → 1.0.490

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": "agentgui",
3
- "version": "1.0.489",
3
+ "version": "1.0.490",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -32,6 +32,7 @@
32
32
  "form-data": "^4.0.5",
33
33
  "fsbrowse": "^0.2.18",
34
34
  "google-auth-library": "^10.5.0",
35
+ "node-pty": "^1.0.0",
35
36
  "onnxruntime-node": "1.21.0",
36
37
  "opencode-ai": "^1.2.15",
37
38
  "puppeteer-core": "^24.37.5",
package/server.js CHANGED
@@ -4090,33 +4090,79 @@ wsRouter.onLegacy((data, ws) => {
4090
4090
  if (ws.terminalProc) {
4091
4091
  try { ws.terminalProc.kill(); } catch(e) {}
4092
4092
  }
4093
- const { spawn } = require('child_process');
4094
- const shell = process.env.SHELL || '/bin/bash';
4095
- const cwd = data.cwd || process.env.STARTUP_CWD || process.env.HOME || '/';
4096
- const proc = spawn(shell, [], { cwd, env: { ...process.env, TERM: 'xterm-256color', COLORTERM: 'truecolor' }, stdio: ['pipe', 'pipe', 'pipe'] });
4097
- ws.terminalProc = proc;
4098
- proc.stdout.on('data', (chunk) => {
4099
- if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
4100
- });
4101
- proc.stderr.on('data', (chunk) => {
4102
- if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
4103
- });
4104
- proc.on('exit', (code) => {
4105
- if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code }));
4106
- ws.terminalProc = null;
4107
- });
4108
- proc.on('error', (err) => {
4109
- console.error('[TERMINAL] Spawn error (contained):', err.message);
4110
- if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code: 1, error: err.message }));
4111
- ws.terminalProc = null;
4112
- });
4113
- proc.stdin.on('error', () => {});
4114
- proc.stdout.on('error', () => {});
4115
- proc.stderr.on('error', () => {});
4116
- ws.send(JSON.stringify({ type: 'terminal_started', timestamp: Date.now() }));
4093
+ try {
4094
+ const pty = require('node-pty');
4095
+ const shell = process.env.SHELL || '/bin/bash';
4096
+ const cwd = data.cwd || process.env.STARTUP_CWD || process.env.HOME || '/';
4097
+ const proc = pty.spawn(shell, [], {
4098
+ name: 'xterm-256color',
4099
+ cols: data.cols || 80,
4100
+ rows: data.rows || 24,
4101
+ cwd: cwd,
4102
+ env: { ...process.env, TERM: 'xterm-256color', COLORTERM: 'truecolor' }
4103
+ });
4104
+ ws.terminalProc = proc;
4105
+ ws.terminalPty = true;
4106
+ proc.on('data', (chunk) => {
4107
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
4108
+ });
4109
+ proc.on('exit', (code) => {
4110
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code }));
4111
+ ws.terminalProc = null;
4112
+ });
4113
+ proc.on('error', (err) => {
4114
+ console.error('[TERMINAL] PTY error (contained):', err.message);
4115
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code: 1, error: err.message }));
4116
+ ws.terminalProc = null;
4117
+ });
4118
+ ws.send(JSON.stringify({ type: 'terminal_started', timestamp: Date.now() }));
4119
+ } catch (e) {
4120
+ console.error('[TERMINAL] Failed to spawn PTY, falling back to pipes:', e.message);
4121
+ const { spawn } = require('child_process');
4122
+ const shell = process.env.SHELL || '/bin/bash';
4123
+ const cwd = data.cwd || process.env.STARTUP_CWD || process.env.HOME || '/';
4124
+ const proc = spawn(shell, ['-i'], { cwd, env: { ...process.env, TERM: 'xterm-256color', COLORTERM: 'truecolor' }, stdio: ['pipe', 'pipe', 'pipe'] });
4125
+ ws.terminalProc = proc;
4126
+ ws.terminalPty = false;
4127
+ proc.stdout.on('data', (chunk) => {
4128
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
4129
+ });
4130
+ proc.stderr.on('data', (chunk) => {
4131
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
4132
+ });
4133
+ proc.on('exit', (code) => {
4134
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code }));
4135
+ ws.terminalProc = null;
4136
+ });
4137
+ proc.on('error', (err) => {
4138
+ console.error('[TERMINAL] Spawn error (contained):', err.message);
4139
+ if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code: 1, error: err.message }));
4140
+ ws.terminalProc = null;
4141
+ });
4142
+ proc.stdin.on('error', () => {});
4143
+ proc.stdout.on('error', () => {});
4144
+ proc.stderr.on('error', () => {});
4145
+ ws.send(JSON.stringify({ type: 'terminal_started', timestamp: Date.now() }));
4146
+ }
4117
4147
  } else if (data.type === 'terminal_input') {
4118
- if (ws.terminalProc && ws.terminalProc.stdin.writable) {
4119
- try { ws.terminalProc.stdin.write(Buffer.from(data.data, 'base64')); } catch (e) {}
4148
+ if (ws.terminalProc) {
4149
+ try {
4150
+ const input = Buffer.from(data.data, 'base64');
4151
+ if (ws.terminalPty) {
4152
+ ws.terminalProc.write(input);
4153
+ } else if (ws.terminalProc.stdin && ws.terminalProc.stdin.writable) {
4154
+ ws.terminalProc.stdin.write(input);
4155
+ }
4156
+ } catch (e) {}
4157
+ }
4158
+ } else if (data.type === 'terminal_resize') {
4159
+ if (ws.terminalProc && ws.terminalPty) {
4160
+ try {
4161
+ const { cols, rows } = data;
4162
+ if (cols && rows && typeof ws.terminalProc.resize === 'function') {
4163
+ ws.terminalProc.resize(cols, rows);
4164
+ }
4165
+ } catch (e) {}
4120
4166
  }
4121
4167
  } else if (data.type === 'terminal_stop') {
4122
4168
  if (ws.terminalProc) {
@@ -42,9 +42,29 @@
42
42
  }
43
43
  });
44
44
 
45
+ term.onResize(function(size) {
46
+ if (ws && ws.readyState === WebSocket.OPEN) {
47
+ ws.send(JSON.stringify({ type: 'terminal_resize', cols: size.cols, rows: size.rows }));
48
+ }
49
+ });
50
+
51
+ var resizeTimer;
45
52
  window.addEventListener('resize', function() {
46
- if (fitAddon) try { fitAddon.fit(); } catch(_) {}
53
+ if (fitAddon) {
54
+ try { fitAddon.fit(); } catch(_) {}
55
+ clearTimeout(resizeTimer);
56
+ resizeTimer = setTimeout(function() {
57
+ if (term && ws && ws.readyState === WebSocket.OPEN) {
58
+ ws.send(JSON.stringify({ type: 'terminal_resize', cols: term.cols, rows: term.rows }));
59
+ }
60
+ }, 200);
61
+ }
47
62
  });
63
+
64
+ output.addEventListener('click', function() {
65
+ if (term && term.focus) term.focus();
66
+ });
67
+
48
68
  return true;
49
69
  }
50
70
 
@@ -52,18 +72,22 @@
52
72
  console.log('Terminal: Connecting to WebSocket');
53
73
  if (ws && ws.readyState === WebSocket.OPEN) {
54
74
  console.log('Terminal: Sending terminal_start command');
55
- ws.send(JSON.stringify({ type: 'terminal_start', cwd: window.__STARTUP_CWD || undefined }));
75
+ var dims = term ? { cols: term.cols, rows: term.rows } : { cols: 80, rows: 24 };
76
+ ws.send(JSON.stringify({ type: 'terminal_start', cwd: window.__STARTUP_CWD || undefined, cols: dims.cols, rows: dims.rows }));
77
+ setTimeout(function() { if (term && term.focus) term.focus(); }, 100);
56
78
  return;
57
79
  }
58
80
  if (ws && ws.readyState === WebSocket.CONNECTING) {
59
81
  console.log('Terminal: WebSocket already connecting');
60
82
  return;
61
83
  }
62
-
84
+
63
85
  ws = new WebSocket(getWsUrl());
64
86
  ws.onopen = function() {
65
87
  console.log('Terminal: WebSocket connected, starting terminal');
66
- ws.send(JSON.stringify({ type: 'terminal_start', cwd: window.__STARTUP_CWD || undefined }));
88
+ var dims = term ? { cols: term.cols, rows: term.rows } : { cols: 80, rows: 24 };
89
+ ws.send(JSON.stringify({ type: 'terminal_start', cwd: window.__STARTUP_CWD || undefined, cols: dims.cols, rows: dims.rows }));
90
+ setTimeout(function() { if (term && term.focus) term.focus(); }, 100);
67
91
  };
68
92
  ws.onmessage = function(e) {
69
93
  try {