agentgui 1.0.335 → 1.0.337
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 +1 -1
- package/server.js +30 -0
- package/static/index.html +53 -48
- package/static/js/terminal.js +105 -0
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -3419,6 +3419,35 @@ wss.on('connection', (ws, req) => {
|
|
|
3419
3419
|
requestId: data.requestId,
|
|
3420
3420
|
timestamp: Date.now()
|
|
3421
3421
|
}));
|
|
3422
|
+
} else if (data.type === 'terminal_start') {
|
|
3423
|
+
if (ws.terminalProc) {
|
|
3424
|
+
try { ws.terminalProc.kill(); } catch(e) {}
|
|
3425
|
+
}
|
|
3426
|
+
const { spawn } = require('child_process');
|
|
3427
|
+
const shell = process.env.SHELL || '/bin/bash';
|
|
3428
|
+
const cwd = data.cwd || process.env.STARTUP_CWD || process.env.HOME || '/';
|
|
3429
|
+
const proc = spawn(shell, [], { cwd, env: { ...process.env, TERM: 'xterm-256color', COLORTERM: 'truecolor' }, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
3430
|
+
ws.terminalProc = proc;
|
|
3431
|
+
proc.stdout.on('data', (chunk) => {
|
|
3432
|
+
if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
|
|
3433
|
+
});
|
|
3434
|
+
proc.stderr.on('data', (chunk) => {
|
|
3435
|
+
if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_output', data: chunk.toString('base64'), encoding: 'base64' }));
|
|
3436
|
+
});
|
|
3437
|
+
proc.on('exit', (code) => {
|
|
3438
|
+
if (ws.readyState === 1) ws.send(JSON.stringify({ type: 'terminal_exit', code }));
|
|
3439
|
+
ws.terminalProc = null;
|
|
3440
|
+
});
|
|
3441
|
+
ws.send(JSON.stringify({ type: 'terminal_started', timestamp: Date.now() }));
|
|
3442
|
+
} else if (data.type === 'terminal_input') {
|
|
3443
|
+
if (ws.terminalProc && ws.terminalProc.stdin.writable) {
|
|
3444
|
+
ws.terminalProc.stdin.write(Buffer.from(data.data, 'base64'));
|
|
3445
|
+
}
|
|
3446
|
+
} else if (data.type === 'terminal_stop') {
|
|
3447
|
+
if (ws.terminalProc) {
|
|
3448
|
+
try { ws.terminalProc.kill(); } catch(e) {}
|
|
3449
|
+
ws.terminalProc = null;
|
|
3450
|
+
}
|
|
3422
3451
|
}
|
|
3423
3452
|
} catch (e) {
|
|
3424
3453
|
console.error('WebSocket message parse error:', e.message);
|
|
@@ -3432,6 +3461,7 @@ wss.on('connection', (ws, req) => {
|
|
|
3432
3461
|
|
|
3433
3462
|
ws.on('pong', () => { ws.isAlive = true; });
|
|
3434
3463
|
ws.on('close', () => {
|
|
3464
|
+
if (ws.terminalProc) { try { ws.terminalProc.kill(); } catch(e) {} ws.terminalProc = null; }
|
|
3435
3465
|
syncClients.delete(ws);
|
|
3436
3466
|
for (const sub of ws.subscriptions) {
|
|
3437
3467
|
const idx = subscriptionIndex.get(sub);
|
package/static/index.html
CHANGED
|
@@ -63,7 +63,6 @@
|
|
|
63
63
|
.app-shell {
|
|
64
64
|
display: flex;
|
|
65
65
|
height: 100dvh;
|
|
66
|
-
height: 100vh;
|
|
67
66
|
overflow: hidden;
|
|
68
67
|
padding-top: env(safe-area-inset-top);
|
|
69
68
|
padding-bottom: env(safe-area-inset-bottom);
|
|
@@ -496,7 +495,7 @@
|
|
|
496
495
|
.terminal-container {
|
|
497
496
|
flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #1e1e1e;
|
|
498
497
|
}
|
|
499
|
-
.terminal-output { flex: 1; overflow: hidden; }
|
|
498
|
+
.terminal-output { flex: 1; overflow: hidden; position: relative; }
|
|
500
499
|
|
|
501
500
|
.models-container {
|
|
502
501
|
flex: 1; display: flex; flex-direction: column; overflow-y: auto;
|
|
@@ -835,6 +834,9 @@
|
|
|
835
834
|
font-size: 0.8rem;
|
|
836
835
|
cursor: pointer;
|
|
837
836
|
flex-shrink: 0;
|
|
837
|
+
width: auto;
|
|
838
|
+
min-width: 80px;
|
|
839
|
+
max-width: 200px;
|
|
838
840
|
}
|
|
839
841
|
|
|
840
842
|
.agent-selector:disabled, .model-selector:disabled {
|
|
@@ -852,7 +854,9 @@
|
|
|
852
854
|
font-size: 0.8rem;
|
|
853
855
|
cursor: pointer;
|
|
854
856
|
flex-shrink: 0;
|
|
855
|
-
|
|
857
|
+
width: auto;
|
|
858
|
+
min-width: 80px;
|
|
859
|
+
max-width: 220px;
|
|
856
860
|
}
|
|
857
861
|
|
|
858
862
|
.model-selector:empty, .model-selector[data-empty="true"] {
|
|
@@ -2051,24 +2055,24 @@
|
|
|
2051
2055
|
.tool-color-default > .folded-tool-body { border-top-color: #a5f3fc; }
|
|
2052
2056
|
html.dark .tool-color-default > .folded-tool-body { border-top-color: #164e63; }
|
|
2053
2057
|
|
|
2054
|
-
.block-type-tool_result { background: #
|
|
2055
|
-
html.dark .block-type-tool_result { background: #
|
|
2056
|
-
.block-type-tool_result .tool-result-status { background: #
|
|
2057
|
-
html.dark .block-type-tool_result .tool-result-status { background: #
|
|
2058
|
+
.block-type-tool_result { background: #f3f4f6; }
|
|
2059
|
+
html.dark .block-type-tool_result { background: #1f2937; }
|
|
2060
|
+
.block-type-tool_result .tool-result-status { background: #e5e7eb; }
|
|
2061
|
+
html.dark .block-type-tool_result .tool-result-status { background: #374151; }
|
|
2058
2062
|
.block-type-tool_result .folded-tool-icon { color: #16a34a; }
|
|
2059
2063
|
html.dark .block-type-tool_result .folded-tool-icon { color: #4ade80; }
|
|
2060
|
-
.block-type-tool_result .folded-tool-name { color: #
|
|
2061
|
-
html.dark .block-type-tool_result .folded-tool-name { color: #
|
|
2062
|
-
.block-type-tool_result > .folded-tool-body { border-top-color: #
|
|
2063
|
-
html.dark .block-type-tool_result > .folded-tool-body { border-top-color: #
|
|
2064
|
-
.block-type-tool_result.tool-result-error { background: #
|
|
2065
|
-
html.dark .block-type-tool_result.tool-result-error { background: #
|
|
2066
|
-
.block-type-tool_result.tool-result-error .tool-result-status { background: #
|
|
2067
|
-
html.dark .block-type-tool_result.tool-result-error .tool-result-status { background: #
|
|
2064
|
+
.block-type-tool_result .folded-tool-name { color: #374151; }
|
|
2065
|
+
html.dark .block-type-tool_result .folded-tool-name { color: #d1d5db; }
|
|
2066
|
+
.block-type-tool_result > .folded-tool-body { border-top-color: #d1d5db; }
|
|
2067
|
+
html.dark .block-type-tool_result > .folded-tool-body { border-top-color: #4b5563; }
|
|
2068
|
+
.block-type-tool_result.tool-result-error { background: #f3f4f6; }
|
|
2069
|
+
html.dark .block-type-tool_result.tool-result-error { background: #1f2937; }
|
|
2070
|
+
.block-type-tool_result.tool-result-error .tool-result-status { background: #e5e7eb; }
|
|
2071
|
+
html.dark .block-type-tool_result.tool-result-error .tool-result-status { background: #374151; }
|
|
2068
2072
|
.block-type-tool_result.tool-result-error .folded-tool-icon { color: #dc2626; }
|
|
2069
2073
|
html.dark .block-type-tool_result.tool-result-error .folded-tool-icon { color: #f87171; }
|
|
2070
|
-
.block-type-tool_result.tool-result-error .folded-tool-name { color: #
|
|
2071
|
-
html.dark .block-type-tool_result.tool-result-error .folded-tool-name { color: #
|
|
2074
|
+
.block-type-tool_result.tool-result-error .folded-tool-name { color: #374151; }
|
|
2075
|
+
html.dark .block-type-tool_result.tool-result-error .folded-tool-name { color: #d1d5db; }
|
|
2072
2076
|
|
|
2073
2077
|
.block-type-code { background: #1e293b; }
|
|
2074
2078
|
html.dark .block-type-code { background: #0f172a; }
|
|
@@ -2176,51 +2180,51 @@
|
|
|
2176
2180
|
|
|
2177
2181
|
/* --- Tool result success styling in body --- */
|
|
2178
2182
|
.tool-result-success .tool-result-status {
|
|
2179
|
-
background: #
|
|
2183
|
+
background: #e5e7eb;
|
|
2180
2184
|
padding: 0.4rem 0.75rem;
|
|
2181
2185
|
}
|
|
2182
2186
|
html.dark .tool-result-success .tool-result-status {
|
|
2183
|
-
background: #
|
|
2187
|
+
background: #374151;
|
|
2184
2188
|
}
|
|
2185
2189
|
.tool-result-success .folded-tool-icon { color: #16a34a; }
|
|
2186
2190
|
html.dark .tool-result-success .folded-tool-icon { color: #4ade80; }
|
|
2187
|
-
.tool-result-success .folded-tool-name { color: #
|
|
2188
|
-
html.dark .tool-result-success .folded-tool-name { color: #
|
|
2191
|
+
.tool-result-success .folded-tool-name { color: #374151; font-weight: 600; }
|
|
2192
|
+
html.dark .tool-result-success .folded-tool-name { color: #d1d5db; }
|
|
2189
2193
|
|
|
2190
2194
|
/* --- Tool_use parent: has-success / has-error indicators on header --- */
|
|
2191
|
-
.folded-tool.has-success { background: #
|
|
2192
|
-
html.dark .folded-tool.has-success { background: #
|
|
2193
|
-
.folded-tool.has-success > .folded-tool-bar { background: #
|
|
2194
|
-
html.dark .folded-tool.has-success > .folded-tool-bar { background: #
|
|
2195
|
-
.folded-tool.has-success > .folded-tool-bar:hover { background: #
|
|
2196
|
-
html.dark .folded-tool.has-success > .folded-tool-bar:hover { background: #
|
|
2195
|
+
.folded-tool.has-success { background: #f3f4f6; }
|
|
2196
|
+
html.dark .folded-tool.has-success { background: #1f2937; }
|
|
2197
|
+
.folded-tool.has-success > .folded-tool-bar { background: #e5e7eb; }
|
|
2198
|
+
html.dark .folded-tool.has-success > .folded-tool-bar { background: #374151; }
|
|
2199
|
+
.folded-tool.has-success > .folded-tool-bar:hover { background: #d1d5db; }
|
|
2200
|
+
html.dark .folded-tool.has-success > .folded-tool-bar:hover { background: #4b5563; }
|
|
2197
2201
|
.folded-tool.has-success > .folded-tool-bar::before { color: #16a34a; }
|
|
2198
2202
|
html.dark .folded-tool.has-success > .folded-tool-bar::before { color: #4ade80; }
|
|
2199
2203
|
.folded-tool.has-success .folded-tool-icon { color: #16a34a; }
|
|
2200
2204
|
html.dark .folded-tool.has-success .folded-tool-icon { color: #4ade80; }
|
|
2201
|
-
.folded-tool.has-success .folded-tool-name { color: #
|
|
2202
|
-
html.dark .folded-tool.has-success .folded-tool-name { color: #
|
|
2203
|
-
.folded-tool.has-success .folded-tool-desc { color: #
|
|
2204
|
-
html.dark .folded-tool.has-success .folded-tool-desc { color: #
|
|
2205
|
-
.folded-tool.has-success > .folded-tool-body { border-top-color: #
|
|
2206
|
-
html.dark .folded-tool.has-success > .folded-tool-body { border-top-color: #
|
|
2207
|
-
|
|
2208
|
-
.folded-tool.has-error { background: #
|
|
2209
|
-
html.dark .folded-tool.has-error { background: #
|
|
2210
|
-
.folded-tool.has-error > .folded-tool-bar { background: #
|
|
2211
|
-
html.dark .folded-tool.has-error > .folded-tool-bar { background: #
|
|
2212
|
-
.folded-tool.has-error > .folded-tool-bar:hover { background: #
|
|
2213
|
-
html.dark .folded-tool.has-error > .folded-tool-bar:hover { background: #
|
|
2205
|
+
.folded-tool.has-success .folded-tool-name { color: #374151; }
|
|
2206
|
+
html.dark .folded-tool.has-success .folded-tool-name { color: #d1d5db; }
|
|
2207
|
+
.folded-tool.has-success .folded-tool-desc { color: #6b7280; }
|
|
2208
|
+
html.dark .folded-tool.has-success .folded-tool-desc { color: #9ca3af; }
|
|
2209
|
+
.folded-tool.has-success > .folded-tool-body { border-top-color: #d1d5db; }
|
|
2210
|
+
html.dark .folded-tool.has-success > .folded-tool-body { border-top-color: #4b5563; }
|
|
2211
|
+
|
|
2212
|
+
.folded-tool.has-error { background: #f3f4f6; }
|
|
2213
|
+
html.dark .folded-tool.has-error { background: #1f2937; }
|
|
2214
|
+
.folded-tool.has-error > .folded-tool-bar { background: #e5e7eb; }
|
|
2215
|
+
html.dark .folded-tool.has-error > .folded-tool-bar { background: #374151; }
|
|
2216
|
+
.folded-tool.has-error > .folded-tool-bar:hover { background: #d1d5db; }
|
|
2217
|
+
html.dark .folded-tool.has-error > .folded-tool-bar:hover { background: #4b5563; }
|
|
2214
2218
|
.folded-tool.has-error > .folded-tool-bar::before { color: #ef4444; }
|
|
2215
2219
|
html.dark .folded-tool.has-error > .folded-tool-bar::before { color: #f87171; }
|
|
2216
2220
|
.folded-tool.has-error .folded-tool-icon { color: #ef4444; }
|
|
2217
2221
|
html.dark .folded-tool.has-error .folded-tool-icon { color: #f87171; }
|
|
2218
|
-
.folded-tool.has-error .folded-tool-name { color: #
|
|
2219
|
-
html.dark .folded-tool.has-error .folded-tool-name { color: #
|
|
2220
|
-
.folded-tool.has-error .folded-tool-desc { color: #
|
|
2221
|
-
html.dark .folded-tool.has-error .folded-tool-desc { color: #
|
|
2222
|
-
.folded-tool.has-error > .folded-tool-body { border-top-color: #
|
|
2223
|
-
html.dark .folded-tool.has-error > .folded-tool-body { border-top-color: #
|
|
2222
|
+
.folded-tool.has-error .folded-tool-name { color: #374151; }
|
|
2223
|
+
html.dark .folded-tool.has-error .folded-tool-name { color: #d1d5db; }
|
|
2224
|
+
.folded-tool.has-error .folded-tool-desc { color: #6b7280; }
|
|
2225
|
+
html.dark .folded-tool.has-error .folded-tool-desc { color: #9ca3af; }
|
|
2226
|
+
.folded-tool.has-error > .folded-tool-body { border-top-color: #d1d5db; }
|
|
2227
|
+
html.dark .folded-tool.has-error > .folded-tool-body { border-top-color: #4b5563; }
|
|
2224
2228
|
|
|
2225
2229
|
/* --- Success/Error status icons in header --- */
|
|
2226
2230
|
.folded-tool.has-success > .folded-tool-bar .folded-tool-icon::after,
|
|
@@ -3042,12 +3046,12 @@
|
|
|
3042
3046
|
</div>
|
|
3043
3047
|
|
|
3044
3048
|
<!-- View toggle bar (hidden by default) -->
|
|
3045
|
-
<div class="view-toggle-bar" id="viewToggleBar"
|
|
3049
|
+
<div class="view-toggle-bar" id="viewToggleBar">
|
|
3046
3050
|
<button class="view-toggle-btn active" data-view="chat">Chat</button>
|
|
3047
3051
|
<button class="view-toggle-btn" data-view="files">Files</button>
|
|
3048
3052
|
<button class="view-toggle-btn" data-view="voice" style="display:none;">Voice</button>
|
|
3049
3053
|
<button class="view-toggle-btn" data-view="models">Models</button>
|
|
3050
|
-
<button class="view-toggle-btn" data-view="terminal" id="terminalTabBtn"
|
|
3054
|
+
<button class="view-toggle-btn" data-view="terminal" id="terminalTabBtn">Terminal</button>
|
|
3051
3055
|
</div>
|
|
3052
3056
|
|
|
3053
3057
|
<!-- Messages scroll area -->
|
|
@@ -3189,6 +3193,7 @@
|
|
|
3189
3193
|
<script defer src="/gm/js/client.js"></script>
|
|
3190
3194
|
<script type="module" src="/gm/js/voice.js"></script>
|
|
3191
3195
|
<script defer src="/gm/js/features.js"></script>
|
|
3196
|
+
<script defer src="/gm/js/terminal.js"></script>
|
|
3192
3197
|
<script defer src="/gm/js/script-runner.js"></script>
|
|
3193
3198
|
<script defer src="/gm/js/agent-auth.js"></script>
|
|
3194
3199
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
var ws = null;
|
|
3
|
+
var term = null;
|
|
4
|
+
var fitAddon = null;
|
|
5
|
+
var termActive = false;
|
|
6
|
+
var BASE = window.__BASE_URL || '';
|
|
7
|
+
|
|
8
|
+
function getWsUrl() {
|
|
9
|
+
var proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
10
|
+
return proto + '//' + location.host + BASE + '/sync';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function ensureTerm() {
|
|
14
|
+
var output = document.getElementById('terminalOutput');
|
|
15
|
+
if (!output) return false;
|
|
16
|
+
if (term) return true;
|
|
17
|
+
if (!window.Terminal || !window.FitAddon) return false;
|
|
18
|
+
|
|
19
|
+
term = new Terminal({
|
|
20
|
+
cursorBlink: true,
|
|
21
|
+
fontSize: 14,
|
|
22
|
+
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
|
23
|
+
theme: {
|
|
24
|
+
background: '#0d1117',
|
|
25
|
+
foreground: '#e6edf3',
|
|
26
|
+
cursor: '#e6edf3',
|
|
27
|
+
selectionBackground: '#3b4455'
|
|
28
|
+
},
|
|
29
|
+
convertEol: false,
|
|
30
|
+
scrollback: 5000
|
|
31
|
+
});
|
|
32
|
+
fitAddon = new FitAddon.FitAddon();
|
|
33
|
+
term.loadAddon(fitAddon);
|
|
34
|
+
output.innerHTML = '';
|
|
35
|
+
term.open(output);
|
|
36
|
+
fitAddon.fit();
|
|
37
|
+
|
|
38
|
+
term.onData(function(data) {
|
|
39
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
40
|
+
var encoded = btoa(unescape(encodeURIComponent(data)));
|
|
41
|
+
ws.send(JSON.stringify({ type: 'terminal_input', data: encoded }));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
window.addEventListener('resize', function() {
|
|
46
|
+
if (fitAddon) try { fitAddon.fit(); } catch(_) {}
|
|
47
|
+
});
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function connectAndStart() {
|
|
52
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
53
|
+
ws.send(JSON.stringify({ type: 'terminal_start', cwd: window.__STARTUP_CWD || undefined }));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
ws = new WebSocket(getWsUrl());
|
|
57
|
+
ws.onopen = function() {
|
|
58
|
+
ws.send(JSON.stringify({ type: 'terminal_start', cwd: window.__STARTUP_CWD || undefined }));
|
|
59
|
+
};
|
|
60
|
+
ws.onmessage = function(e) {
|
|
61
|
+
try {
|
|
62
|
+
var msg = JSON.parse(e.data);
|
|
63
|
+
if (msg.type === 'terminal_output' && term) {
|
|
64
|
+
var raw = msg.encoding === 'base64'
|
|
65
|
+
? decodeURIComponent(escape(atob(msg.data)))
|
|
66
|
+
: msg.data;
|
|
67
|
+
term.write(raw);
|
|
68
|
+
} else if (msg.type === 'terminal_exit' && term) {
|
|
69
|
+
term.write('\r\n[Process exited with code ' + msg.code + ']\r\n');
|
|
70
|
+
if (termActive) setTimeout(connectAndStart, 2000);
|
|
71
|
+
}
|
|
72
|
+
} catch(_) {}
|
|
73
|
+
};
|
|
74
|
+
ws.onclose = function() {
|
|
75
|
+
if (termActive) setTimeout(connectAndStart, 2000);
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function startTerminal() {
|
|
80
|
+
if (!ensureTerm()) {
|
|
81
|
+
setTimeout(startTerminal, 200);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
termActive = true;
|
|
85
|
+
connectAndStart();
|
|
86
|
+
setTimeout(function() { if (fitAddon) try { fitAddon.fit(); } catch(_) {} }, 100);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function stopTerminal() {
|
|
90
|
+
termActive = false;
|
|
91
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
92
|
+
ws.send(JSON.stringify({ type: 'terminal_stop' }));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
window.addEventListener('view-switched', function(e) {
|
|
97
|
+
if (e.detail.view === 'terminal') {
|
|
98
|
+
startTerminal();
|
|
99
|
+
} else if (termActive) {
|
|
100
|
+
stopTerminal();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
window.terminalModule = { start: startTerminal, stop: stopTerminal };
|
|
105
|
+
})();
|