claude-simple 0.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/README.md +225 -0
- package/client.js +139 -0
- package/dist/addon-fit.min.js +2 -0
- package/dist/app.0.1.0.min.js +825 -0
- package/dist/highlight.min.css +10 -0
- package/dist/highlight.min.js +1244 -0
- package/dist/index.html +16 -0
- package/dist/marked.min.js +6 -0
- package/dist/style.0.1.0.min.css +1050 -0
- package/dist/xterm.min.css +209 -0
- package/dist/xterm.min.js +2 -0
- package/gateway.js +349 -0
- package/package.json +41 -0
- package/public/addon-fit.min.js +2 -0
- package/public/agent-panel.js +1079 -0
- package/public/api.js +78 -0
- package/public/app.js +95 -0
- package/public/base.css +4 -0
- package/public/cache.js +27 -0
- package/public/chat.js +1087 -0
- package/public/files.js +476 -0
- package/public/git.js +130 -0
- package/public/index.html +61 -0
- package/public/lib.js +2 -0
- package/public/router.js +71 -0
- package/public/settings.js +90 -0
- package/public/shell/boot.js +159 -0
- package/public/shell/dashboard.js +269 -0
- package/public/shell/hub.js +192 -0
- package/public/shell/layout.js +195 -0
- package/public/shell/notes.js +323 -0
- package/public/shell/session-context.js +19 -0
- package/public/shell/session-list.js +442 -0
- package/public/shell/session-nav.js +299 -0
- package/public/shell/templates.js +342 -0
- package/public/shell/util.js +63 -0
- package/public/shell.js +589 -0
- package/public/state.js +362 -0
- package/public/style.css +1048 -0
- package/public/terminal.js +177 -0
- package/public/xterm.min.css +209 -0
- package/public/xterm.min.js +2 -0
- package/server.js +12 -0
- package/src/agents/claude.js +58 -0
- package/src/agents/codex.js +284 -0
- package/src/agents/grok.js +318 -0
- package/src/agents/meta-agent.js +1952 -0
- package/src/agents/models.js +339 -0
- package/src/agents/sessions.js +1508 -0
- package/src/app.js +1282 -0
package/gateway.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* gateway.js — LEGACY Node relay (prefer Go binary in ./gateway/)
|
|
4
|
+
*
|
|
5
|
+
* cd gateway && make build && MACHINE_TOKEN=… ./dist/claude-gateway
|
|
6
|
+
*
|
|
7
|
+
* Machines (client.js) connect via WS to /machine-connect and register themselves.
|
|
8
|
+
* Browser users visit the gateway, pick a machine, and all traffic is forwarded
|
|
9
|
+
* transparently through the machine's control WebSocket.
|
|
10
|
+
*
|
|
11
|
+
* Control channel message protocol (gateway ↔ client):
|
|
12
|
+
*
|
|
13
|
+
* register: client → gateway { type:'register', machineId, meta }
|
|
14
|
+
* ping/pong: gateway ↔ client { type:'ping' } / { type:'pong' }
|
|
15
|
+
*
|
|
16
|
+
* HTTP proxy:
|
|
17
|
+
* gateway → client { type:'http-req', reqId, method, path, headers, body }
|
|
18
|
+
* client → gateway { type:'http-res', reqId, status, headers, body }
|
|
19
|
+
*
|
|
20
|
+
* WS tunnel:
|
|
21
|
+
* gateway → client { type:'ws-open', tunnelId, path, query }
|
|
22
|
+
* client → gateway { type:'ws-ready', tunnelId }
|
|
23
|
+
* client → gateway { type:'ws-error', tunnelId, message }
|
|
24
|
+
* gateway ↔ client { type:'ws-msg', tunnelId, data }
|
|
25
|
+
* gateway ↔ client { type:'ws-close', tunnelId }
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import express from 'express';
|
|
29
|
+
import http from 'http';
|
|
30
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
31
|
+
import crypto from 'crypto';
|
|
32
|
+
|
|
33
|
+
const PORT = parseInt(process.env.GATEWAY_PORT || '8080');
|
|
34
|
+
const MACHINE_TOKEN = process.env.MACHINE_TOKEN; // shared secret all clients must send
|
|
35
|
+
if (!MACHINE_TOKEN) { console.error('MACHINE_TOKEN is required'); process.exit(1); }
|
|
36
|
+
|
|
37
|
+
// ─── Machine registry ─────────────────────────────────────────────────────────
|
|
38
|
+
// machineId → { ws, meta, connectedAt, lastPong }
|
|
39
|
+
const machines = new Map();
|
|
40
|
+
|
|
41
|
+
// Pending HTTP responses: reqId → { resolve, reject, timer }
|
|
42
|
+
const pendingHttp = new Map();
|
|
43
|
+
|
|
44
|
+
// Pending WS tunnel handshakes: tunnelId → { resolve, reject, timer }
|
|
45
|
+
const pendingTunnels = new Map();
|
|
46
|
+
|
|
47
|
+
// Active WS tunnels: tunnelId → browser WebSocket
|
|
48
|
+
const activeTunnels = new Map();
|
|
49
|
+
|
|
50
|
+
function getMachine(machineId) {
|
|
51
|
+
const m = machines.get(machineId);
|
|
52
|
+
if (!m || m.ws.readyState !== WebSocket.OPEN) return null;
|
|
53
|
+
return m;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function sendToMachine(machineId, msg) {
|
|
57
|
+
const m = getMachine(machineId);
|
|
58
|
+
if (!m) throw new Error(`Machine "${machineId}" not connected`);
|
|
59
|
+
m.ws.send(JSON.stringify(msg));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ─── HTTP forwarding ──────────────────────────────────────────────────────────
|
|
63
|
+
function forwardHttp(machineId, method, path, headers, body) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const reqId = crypto.randomUUID();
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
pendingHttp.delete(reqId);
|
|
68
|
+
reject(new Error('Machine request timed out'));
|
|
69
|
+
}, 30_000);
|
|
70
|
+
pendingHttp.set(reqId, { resolve, reject, timer });
|
|
71
|
+
try {
|
|
72
|
+
sendToMachine(machineId, { type: 'http-req', reqId, method, path, headers, body });
|
|
73
|
+
} catch (e) {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
pendingHttp.delete(reqId);
|
|
76
|
+
reject(e);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─── WS tunnel handshake ──────────────────────────────────────────────────────
|
|
82
|
+
function openTunnel(machineId, tunnelId, path, query) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const timer = setTimeout(() => {
|
|
85
|
+
pendingTunnels.delete(tunnelId);
|
|
86
|
+
reject(new Error('Tunnel open timed out'));
|
|
87
|
+
}, 10_000);
|
|
88
|
+
pendingTunnels.set(tunnelId, { resolve, reject, timer });
|
|
89
|
+
try {
|
|
90
|
+
sendToMachine(machineId, { type: 'ws-open', tunnelId, path, query });
|
|
91
|
+
} catch (e) {
|
|
92
|
+
clearTimeout(timer);
|
|
93
|
+
pendingTunnels.delete(tunnelId);
|
|
94
|
+
reject(e);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─── Handle messages from a machine's control WS ─────────────────────────────
|
|
100
|
+
function handleMachineMessage(msg) {
|
|
101
|
+
if (msg.type === 'pong') return;
|
|
102
|
+
|
|
103
|
+
if (msg.type === 'http-res') {
|
|
104
|
+
const pending = pendingHttp.get(msg.reqId);
|
|
105
|
+
if (!pending) return;
|
|
106
|
+
clearTimeout(pending.timer);
|
|
107
|
+
pendingHttp.delete(msg.reqId);
|
|
108
|
+
pending.resolve(msg);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (msg.type === 'ws-ready') {
|
|
113
|
+
const pending = pendingTunnels.get(msg.tunnelId);
|
|
114
|
+
if (!pending) return;
|
|
115
|
+
clearTimeout(pending.timer);
|
|
116
|
+
pendingTunnels.delete(msg.tunnelId);
|
|
117
|
+
pending.resolve();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (msg.type === 'ws-error') {
|
|
122
|
+
const pending = pendingTunnels.get(msg.tunnelId);
|
|
123
|
+
if (pending) {
|
|
124
|
+
clearTimeout(pending.timer);
|
|
125
|
+
pendingTunnels.delete(msg.tunnelId);
|
|
126
|
+
pending.reject(new Error(msg.message || 'Tunnel error'));
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (msg.type === 'ws-msg') {
|
|
132
|
+
const browserWs = activeTunnels.get(msg.tunnelId);
|
|
133
|
+
if (browserWs?.readyState === WebSocket.OPEN) {
|
|
134
|
+
browserWs.send(msg.data);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (msg.type === 'ws-close') {
|
|
140
|
+
const browserWs = activeTunnels.get(msg.tunnelId);
|
|
141
|
+
activeTunnels.delete(msg.tunnelId);
|
|
142
|
+
if (browserWs?.readyState === WebSocket.OPEN) browserWs.close();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ─── Express app ──────────────────────────────────────────────────────────────
|
|
148
|
+
const app = express();
|
|
149
|
+
// Large enough for base64 file previews (office/pdf ≤15MB → ~20MB JSON)
|
|
150
|
+
app.use(express.json({ limit: '25mb' }));
|
|
151
|
+
|
|
152
|
+
// Machine list API (used by the frontend picker)
|
|
153
|
+
app.get('/api/machines', (req, res) => {
|
|
154
|
+
const list = [...machines.entries()].map(([id, m]) => ({
|
|
155
|
+
id,
|
|
156
|
+
...m.meta,
|
|
157
|
+
connectedAt: m.connectedAt,
|
|
158
|
+
online: m.ws.readyState === WebSocket.OPEN,
|
|
159
|
+
}));
|
|
160
|
+
res.json(list);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Machine picker page — minimal HTML, loads the real UI from the selected machine
|
|
164
|
+
app.get('/', (req, res) => {
|
|
165
|
+
if (req.query.machine) {
|
|
166
|
+
// Redirect into the machine's proxied app
|
|
167
|
+
return res.redirect(`/machine/${req.query.machine}/`);
|
|
168
|
+
}
|
|
169
|
+
res.send(`<!DOCTYPE html>
|
|
170
|
+
<html lang="en">
|
|
171
|
+
<head>
|
|
172
|
+
<meta charset="utf-8">
|
|
173
|
+
<title>Select machine</title>
|
|
174
|
+
<style>
|
|
175
|
+
body { font-family: system-ui, sans-serif; max-width: 480px; margin: 80px auto; padding: 0 16px; }
|
|
176
|
+
h1 { font-size: 1.2rem; margin-bottom: 24px; }
|
|
177
|
+
.machine { display:flex; justify-content:space-between; align-items:center;
|
|
178
|
+
border:1px solid #ddd; border-radius:8px; padding:12px 16px; margin-bottom:12px; }
|
|
179
|
+
.machine a { text-decoration:none; font-weight:600; color:#0070f3; }
|
|
180
|
+
.dot { width:8px; height:8px; border-radius:50%; background:#22c55e; }
|
|
181
|
+
.dot.offline { background:#ef4444; }
|
|
182
|
+
#empty { color:#888; }
|
|
183
|
+
</style>
|
|
184
|
+
</head>
|
|
185
|
+
<body>
|
|
186
|
+
<h1>Choose a machine</h1>
|
|
187
|
+
<div id="list"><p id="empty">Loading...</p></div>
|
|
188
|
+
<script>
|
|
189
|
+
async function load() {
|
|
190
|
+
const res = await fetch('/api/machines');
|
|
191
|
+
const machines = await res.json();
|
|
192
|
+
const el = document.getElementById('list');
|
|
193
|
+
if (!machines.length) { el.innerHTML = '<p id="empty">No machines connected.</p>'; return; }
|
|
194
|
+
el.innerHTML = machines.map(m => \`
|
|
195
|
+
<div class="machine">
|
|
196
|
+
<a href="/machine/\${m.id}/">\${m.id}</a>
|
|
197
|
+
<span>\${m.hostname || ''} · \${m.platform || ''}</span>
|
|
198
|
+
<span class="dot \${m.online ? '' : 'offline'}"></span>
|
|
199
|
+
</div>
|
|
200
|
+
\`).join('');
|
|
201
|
+
}
|
|
202
|
+
load();
|
|
203
|
+
setInterval(load, 5000);
|
|
204
|
+
</script>
|
|
205
|
+
</body>
|
|
206
|
+
</html>`);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// ─── HTTP proxy: /machine/:id/* ───────────────────────────────────────────────
|
|
210
|
+
app.all('/machine/:machineId/*', async (req, res) => {
|
|
211
|
+
const { machineId } = req.params;
|
|
212
|
+
if (!getMachine(machineId)) {
|
|
213
|
+
return res.status(503).json({ error: `Machine "${machineId}" not connected` });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Strip /machine/:id prefix so the machine sees its own paths
|
|
217
|
+
const path = req.path.replace(`/machine/${machineId}`, '') || '/';
|
|
218
|
+
const qs = req.url.includes('?') ? req.url.slice(req.url.indexOf('?')) : '';
|
|
219
|
+
|
|
220
|
+
// Pass body as string for JSON; raw otherwise
|
|
221
|
+
const body = req.method !== 'GET' && req.method !== 'HEAD'
|
|
222
|
+
? JSON.stringify(req.body)
|
|
223
|
+
: undefined;
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const result = await forwardHttp(machineId, req.method, path + qs, {
|
|
227
|
+
...req.headers,
|
|
228
|
+
host: 'localhost',
|
|
229
|
+
}, body);
|
|
230
|
+
|
|
231
|
+
// Don't forward hop-by-hop headers
|
|
232
|
+
const skip = new Set(['transfer-encoding', 'connection', 'keep-alive']);
|
|
233
|
+
Object.entries(result.headers || {}).forEach(([k, v]) => {
|
|
234
|
+
if (!skip.has(k.toLowerCase())) res.setHeader(k, v);
|
|
235
|
+
});
|
|
236
|
+
res.status(result.status).send(result.body);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
res.status(502).json({ error: e.message });
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// ─── HTTP + WebSocket server ──────────────────────────────────────────────────
|
|
243
|
+
const server = http.createServer(app);
|
|
244
|
+
|
|
245
|
+
// Two WS servers — one for machines registering, one for browser tunnels
|
|
246
|
+
const wssMachines = new WebSocketServer({ noServer: true });
|
|
247
|
+
const wssBrowser = new WebSocketServer({ noServer: true });
|
|
248
|
+
|
|
249
|
+
server.on('upgrade', (req, socket, head) => {
|
|
250
|
+
const url = new URL(req.url, 'http://localhost');
|
|
251
|
+
const pathname = url.pathname;
|
|
252
|
+
|
|
253
|
+
if (pathname === '/machine-connect') {
|
|
254
|
+
wssMachines.handleUpgrade(req, socket, head, ws => wssMachines.emit('connection', ws, req));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// /machine/:id/ws/chat or /machine/:id/ws/shell
|
|
259
|
+
const m = pathname.match(/^\/machine\/([^/]+)(\/ws\/.+)$/);
|
|
260
|
+
if (m) {
|
|
261
|
+
wssBrowser.handleUpgrade(req, socket, head, ws => wssBrowser.emit('connection', ws, req, m[1], m[2]));
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
socket.destroy();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// ─── Machine control connections ──────────────────────────────────────────────
|
|
269
|
+
wssMachines.on('connection', (ws, req) => {
|
|
270
|
+
// Verify shared token
|
|
271
|
+
const token = req.headers['x-machine-token'];
|
|
272
|
+
if (token !== MACHINE_TOKEN) {
|
|
273
|
+
ws.close(1008, 'Unauthorized');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let machineId = null;
|
|
278
|
+
|
|
279
|
+
// Heartbeat
|
|
280
|
+
const pingInterval = setInterval(() => {
|
|
281
|
+
if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'ping' }));
|
|
282
|
+
}, 30_000);
|
|
283
|
+
|
|
284
|
+
ws.on('message', raw => {
|
|
285
|
+
let msg;
|
|
286
|
+
try { msg = JSON.parse(raw.toString()); } catch { return; }
|
|
287
|
+
|
|
288
|
+
if (msg.type === 'register') {
|
|
289
|
+
machineId = msg.machineId;
|
|
290
|
+
machines.set(machineId, { ws, meta: msg.meta || {}, connectedAt: Date.now() });
|
|
291
|
+
console.log(`[gateway] Machine registered: ${machineId}`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
handleMachineMessage(msg);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
ws.on('close', () => {
|
|
299
|
+
clearInterval(pingInterval);
|
|
300
|
+
if (machineId) {
|
|
301
|
+
machines.delete(machineId);
|
|
302
|
+
console.log(`[gateway] Machine disconnected: ${machineId}`);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
ws.on('error', e => console.error('[gateway] machine ws error:', e.message));
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// ─── Browser WS tunnel connections ───────────────────────────────────────────
|
|
310
|
+
wssBrowser.on('connection', async (browserWs, req, machineId, wsPath) => {
|
|
311
|
+
const url = new URL(req.url, 'http://localhost');
|
|
312
|
+
const query = url.search; // e.g. ?token=xxx
|
|
313
|
+
const tunnelId = crypto.randomUUID();
|
|
314
|
+
|
|
315
|
+
if (!getMachine(machineId)) {
|
|
316
|
+
browserWs.close(1011, 'Machine not connected');
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
await openTunnel(machineId, tunnelId, wsPath, query);
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.error(`[gateway] Tunnel open failed: ${e.message}`);
|
|
324
|
+
browserWs.close(1011, 'Tunnel failed');
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
activeTunnels.set(tunnelId, browserWs);
|
|
329
|
+
|
|
330
|
+
browserWs.on('message', raw => {
|
|
331
|
+
const m = getMachine(machineId);
|
|
332
|
+
if (!m) return;
|
|
333
|
+
m.ws.send(JSON.stringify({ type: 'ws-msg', tunnelId, data: raw.toString() }));
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
browserWs.on('close', () => {
|
|
337
|
+
activeTunnels.delete(tunnelId);
|
|
338
|
+
const m = getMachine(machineId);
|
|
339
|
+
if (m) m.ws.send(JSON.stringify({ type: 'ws-close', tunnelId }));
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
browserWs.on('error', e => console.error('[gateway] browser ws error:', e.message));
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// ─── Start ────────────────────────────────────────────────────────────────────
|
|
346
|
+
server.listen(PORT, () => {
|
|
347
|
+
console.log(`\n Gateway running at http://localhost:${PORT}`);
|
|
348
|
+
console.log(` Waiting for machines to connect at ws://localhost:${PORT}/machine-connect\n`);
|
|
349
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-simple",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"claude-simple": "server.js",
|
|
7
|
+
"claude-simple-client": "client.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"server.js",
|
|
11
|
+
"client.js",
|
|
12
|
+
"gateway.js",
|
|
13
|
+
"src",
|
|
14
|
+
"dist",
|
|
15
|
+
"public"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "node build.mjs",
|
|
19
|
+
"prepublishOnly": "node build.mjs",
|
|
20
|
+
"start": "NODE_ENV=production node server.js",
|
|
21
|
+
"dev": "NODE_ENV=development node --watch server.js",
|
|
22
|
+
"serve": "node server.js",
|
|
23
|
+
"gateway": "node gateway.js",
|
|
24
|
+
"gateway:go": "cd gateway && go run .",
|
|
25
|
+
"gateway:build": "cd gateway && make build",
|
|
26
|
+
"client": "node client.js"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@anthropic-ai/claude-agent-sdk": "*",
|
|
30
|
+
"bcrypt": "^5.1.1",
|
|
31
|
+
"express": "^4.18.2",
|
|
32
|
+
"jsonwebtoken": "^9.0.2",
|
|
33
|
+
"ws": "^8.16.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@tailwindcss/cli": "^4.2.4",
|
|
37
|
+
"daisyui": "^5.5.19",
|
|
38
|
+
"esbuild": "^0.28.0",
|
|
39
|
+
"tailwindcss": "^4.2.4"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));
|
|
2
|
+
//# sourceMappingURL=xterm-addon-fit.js.map
|