@deadragdoll/tellymcp 0.0.13 → 0.0.15
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/.env.example.client +23 -39
- package/.env.example.gateway +52 -61
- package/CHANGELOG.md +57 -0
- package/README-ru.md +80 -6
- package/README.md +80 -6
- package/TOOLS.md +219 -10
- package/config/templates/env.both.template +19 -7
- package/config/templates/env.client.template +9 -19
- package/config/templates/env.gateway.template +19 -31
- package/dist/cli.js +252 -47
- package/dist/configureServer.js +966 -0
- package/dist/envMigration.js +316 -0
- package/dist/moleculer.config.js +1 -3
- package/dist/services/features/telegram-mcp/approval.service.js +1 -1
- package/dist/services/features/telegram-mcp/browser.service.js +18 -0
- package/dist/services/features/telegram-mcp/collaboration.service.js +2 -2
- package/dist/services/features/telegram-mcp/ensuredb.service.js +1 -1
- package/dist/services/features/telegram-mcp/file-content.service.js +94 -0
- package/dist/services/features/telegram-mcp/gateway-delivery.service.js +5 -1
- package/dist/services/features/telegram-mcp/gateway-socket.service.js +43 -11
- package/dist/services/features/telegram-mcp/gateway.service.js +1 -1
- package/dist/services/features/telegram-mcp/mcp-http.service.js +1 -0
- package/dist/services/features/telegram-mcp/mcp-server.service.js +20 -0
- package/dist/services/features/telegram-mcp/session-context.service.js +25 -1
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +79 -67
- package/dist/services/features/telegram-mcp/src/app/config/env.js +129 -38
- package/dist/services/features/telegram-mcp/src/app/config/environmentContract.js +66 -0
- package/dist/services/features/telegram-mcp/src/app/http.js +139 -99
- package/dist/services/features/telegram-mcp/src/app/oauthFacade.js +642 -0
- package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +151 -170
- package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +96 -99
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +88 -19
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachActiveTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserAttachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDetachTabTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +412 -29
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +37 -3
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +7 -6
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +214 -37
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +186 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/collaborationService.js +2 -0
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +5 -5
- package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +6 -3
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +5 -2
- package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +4 -4
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +33 -36
- package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +4 -3
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileListTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileService.js +327 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/getFileTool.js +81 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/temporaryFileLinkStore.js +307 -0
- package/dist/services/features/telegram-mcp/src/features/file-content/model/workspaceFilePolicy.js +115 -0
- package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +9 -5
- package/dist/services/features/telegram-mcp/src/features/session-context/model/getRuntimeDiagnosticsTool.js +30 -0
- package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +169 -7
- package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalStateStore.js +260 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +1 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +4 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +2 -2
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +6 -3
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +1 -1
- package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +2 -2
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +29 -6
- package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +100 -2
- package/dist/services/features/telegram-mcp/src/shared/lib/bodyLimits.js +63 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/gatewayAuth.js +13 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +5 -5
- package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +10 -0
- package/dist/services/features/telegram-mcp/src/shared/lib/time/localTimestamp.js +21 -0
- package/docs/CHAT_CONNECTOR.md +134 -0
- package/docs/STANDALONE-ru.md +41 -3
- package/docs/STANDALONE.md +41 -3
- package/package.json +5 -3
- package/packages/chrome-attach-extension/dist/background.js +572 -163
- package/packages/chrome-attach-extension/dist/manifest.json +2 -1
- package/packages/chrome-attach-extension/dist/options.js +15 -2
- package/packages/chrome-attach-extension/dist/recorder-content.js +14 -1
- package/packages/chrome-attach-extension/dist/recorder-page.js +34 -18
- package/packages/firefox-attach-extension/dist/background.js +413 -33
- package/packages/firefox-attach-extension/dist/manifest.json +0 -12
- package/packages/firefox-attach-extension/dist/options.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-content.js +14 -1
- package/packages/firefox-attach-extension/dist/recorder-page.js +34 -18
- package/scripts/postinstall.js +33 -1
|
@@ -5,6 +5,7 @@ exports.renderWebAppHtml = renderWebAppHtml;
|
|
|
5
5
|
const node_fs_1 = require("node:fs");
|
|
6
6
|
const XTERM_WEBAPP_CSS = (0, node_fs_1.readFileSync)(require.resolve("@xterm/xterm/css/xterm.css"), "utf8");
|
|
7
7
|
const XTERM_WEBAPP_JS = (0, node_fs_1.readFileSync)(require.resolve("@xterm/xterm/lib/xterm.js"), "utf8");
|
|
8
|
+
const XTERM_FIT_WEBAPP_JS = (0, node_fs_1.readFileSync)(require.resolve("@xterm/addon-fit/lib/addon-fit.js"), "utf8");
|
|
8
9
|
exports.WEBAPP_STYLES_CSS = `
|
|
9
10
|
:root {
|
|
10
11
|
color-scheme: dark;
|
|
@@ -258,18 +259,19 @@ const config = window.__TELEGRAM_MCP_WEBAPP__;
|
|
|
258
259
|
const state = {
|
|
259
260
|
token: null,
|
|
260
261
|
sessionId: null,
|
|
261
|
-
timer: null,
|
|
262
262
|
actionBusy: false,
|
|
263
|
-
pollIntervalMs: 2000,
|
|
264
263
|
wrapEnabled: true,
|
|
265
264
|
recoverPromise: null,
|
|
266
265
|
xterm: null,
|
|
266
|
+
xtermFitAddon: null,
|
|
267
267
|
xtermInputBound: false,
|
|
268
268
|
liveSocket: null,
|
|
269
269
|
liveSocketConnected: false,
|
|
270
|
+
liveConnectPromise: null,
|
|
271
|
+
liveReconnectTimer: null,
|
|
272
|
+
liveReconnectAttempt: 0,
|
|
270
273
|
lastRenderSignature: null,
|
|
271
274
|
resizeObserver: null,
|
|
272
|
-
fittedRows: null,
|
|
273
275
|
};
|
|
274
276
|
|
|
275
277
|
const elements = {
|
|
@@ -302,7 +304,10 @@ function setUpdated(text) {
|
|
|
302
304
|
}
|
|
303
305
|
|
|
304
306
|
function setLiveModeStatus(mode) {
|
|
305
|
-
setStatus(
|
|
307
|
+
setStatus(
|
|
308
|
+
mode === "stream" ? "Live (stream)" : "Reconnecting live stream...",
|
|
309
|
+
mode !== "stream",
|
|
310
|
+
);
|
|
306
311
|
}
|
|
307
312
|
|
|
308
313
|
function createHttpError(message, status) {
|
|
@@ -372,47 +377,29 @@ function getXtermCtor() {
|
|
|
372
377
|
return window.Terminal || window.XtermTerminal || null;
|
|
373
378
|
}
|
|
374
379
|
|
|
375
|
-
function
|
|
376
|
-
|
|
377
|
-
terminal &&
|
|
378
|
-
terminal._core &&
|
|
379
|
-
terminal._core._renderService &&
|
|
380
|
-
terminal._core._renderService.dimensions &&
|
|
381
|
-
terminal._core._renderService.dimensions.css &&
|
|
382
|
-
terminal._core._renderService.dimensions.css.cell;
|
|
383
|
-
|
|
384
|
-
if (!cell || !cell.height) {
|
|
385
|
-
return null;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return cell.height;
|
|
380
|
+
function getXtermFitAddonCtor() {
|
|
381
|
+
return window.FitAddon?.FitAddon || null;
|
|
389
382
|
}
|
|
390
383
|
|
|
391
|
-
function
|
|
384
|
+
function fitTerminal(notifyServer = true) {
|
|
392
385
|
const terminal = state.xterm;
|
|
393
|
-
|
|
386
|
+
const fitAddon = state.xtermFitAddon;
|
|
387
|
+
if (!terminal || !fitAddon) {
|
|
394
388
|
return;
|
|
395
389
|
}
|
|
396
390
|
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const nextRows = Math.max(5, Math.floor(elements.terminal.clientHeight / cellHeight));
|
|
403
|
-
if (!Number.isFinite(nextRows) || nextRows <= 0) {
|
|
391
|
+
const previousCols = terminal.cols;
|
|
392
|
+
const previousRows = terminal.rows;
|
|
393
|
+
try {
|
|
394
|
+
fitAddon.fit();
|
|
395
|
+
} catch (_error) {
|
|
404
396
|
return;
|
|
405
397
|
}
|
|
406
398
|
|
|
407
|
-
if (
|
|
399
|
+
if (terminal.cols === previousCols && terminal.rows === previousRows) {
|
|
408
400
|
return;
|
|
409
401
|
}
|
|
410
402
|
|
|
411
|
-
state.fittedRows = nextRows;
|
|
412
|
-
const currentCols =
|
|
413
|
-
typeof terminal.cols === "number" && terminal.cols > 0 ? terminal.cols : 80;
|
|
414
|
-
terminal.resize(currentCols, nextRows);
|
|
415
|
-
|
|
416
403
|
if (
|
|
417
404
|
notifyServer &&
|
|
418
405
|
state.liveSocketConnected &&
|
|
@@ -420,7 +407,7 @@ function fitTerminalRows(notifyServer = true) {
|
|
|
420
407
|
state.liveSocket.readyState === WebSocket.OPEN
|
|
421
408
|
) {
|
|
422
409
|
state.liveSocket.send(
|
|
423
|
-
JSON.stringify({ type: "resize", cols:
|
|
410
|
+
JSON.stringify({ type: "resize", cols: terminal.cols, rows: terminal.rows }),
|
|
424
411
|
);
|
|
425
412
|
}
|
|
426
413
|
}
|
|
@@ -431,7 +418,8 @@ function ensureXterm() {
|
|
|
431
418
|
}
|
|
432
419
|
|
|
433
420
|
const TerminalCtor = getXtermCtor();
|
|
434
|
-
|
|
421
|
+
const FitAddonCtor = getXtermFitAddonCtor();
|
|
422
|
+
if (!TerminalCtor || !FitAddonCtor || !elements.terminal) {
|
|
435
423
|
return null;
|
|
436
424
|
}
|
|
437
425
|
|
|
@@ -453,6 +441,8 @@ function ensureXterm() {
|
|
|
453
441
|
allowTransparency: true,
|
|
454
442
|
scrollback: 4000,
|
|
455
443
|
});
|
|
444
|
+
const fitAddon = new FitAddonCtor();
|
|
445
|
+
terminal.loadAddon(fitAddon);
|
|
456
446
|
terminal.open(elements.terminal);
|
|
457
447
|
terminal.onData((data) => {
|
|
458
448
|
if (!state.liveSocketConnected || !state.liveSocket) {
|
|
@@ -470,52 +460,27 @@ function ensureXterm() {
|
|
|
470
460
|
});
|
|
471
461
|
if (!state.resizeObserver && typeof ResizeObserver !== "undefined") {
|
|
472
462
|
state.resizeObserver = new ResizeObserver(() => {
|
|
473
|
-
|
|
463
|
+
fitTerminal();
|
|
474
464
|
});
|
|
475
465
|
state.resizeObserver.observe(elements.terminal);
|
|
476
466
|
}
|
|
477
467
|
window.addEventListener("resize", () => {
|
|
478
|
-
|
|
468
|
+
fitTerminal();
|
|
479
469
|
});
|
|
480
470
|
state.xterm = terminal;
|
|
471
|
+
state.xtermFitAddon = fitAddon;
|
|
481
472
|
window.setTimeout(() => {
|
|
482
|
-
|
|
473
|
+
fitTerminal();
|
|
483
474
|
}, 0);
|
|
484
475
|
return terminal;
|
|
485
476
|
}
|
|
486
477
|
|
|
487
|
-
function estimateTerminalSizeFromPayload(payload, options = {}) {
|
|
488
|
-
const text = payload.ansi || payload.content || "";
|
|
489
|
-
const lines = text.split("\\n");
|
|
490
|
-
const useViewportRows =
|
|
491
|
-
options.preferViewportRows === true &&
|
|
492
|
-
Number.isFinite(payload.rows) &&
|
|
493
|
-
payload.rows > 0;
|
|
494
|
-
const rows = useViewportRows
|
|
495
|
-
? Math.max(2, Math.min(120, payload.rows))
|
|
496
|
-
: Math.max(2, Math.min(400, lines.length || payload.rows || 24));
|
|
497
|
-
const baseCols = Number.isFinite(payload.cols) && payload.cols > 0
|
|
498
|
-
? payload.cols
|
|
499
|
-
: 40;
|
|
500
|
-
const cols = Math.max(
|
|
501
|
-
baseCols,
|
|
502
|
-
Math.min(
|
|
503
|
-
240,
|
|
504
|
-
Number.isFinite(payload.cols) && payload.cols > 0
|
|
505
|
-
? payload.cols
|
|
506
|
-
: lines.reduce((max, line) => Math.max(max, line.replace(/\\u001b\\[[0-9;]*m/g, "").length), 0) || 80,
|
|
507
|
-
),
|
|
508
|
-
);
|
|
509
|
-
return { cols, rows };
|
|
510
|
-
}
|
|
511
|
-
|
|
512
478
|
function renderTerminalPayload(payload, options = {}) {
|
|
513
479
|
const signature = JSON.stringify({
|
|
514
480
|
ansi: payload.ansi || "",
|
|
515
481
|
content: payload.content || "",
|
|
516
482
|
cols: payload.cols || null,
|
|
517
483
|
rows: payload.rows || null,
|
|
518
|
-
preferViewportRows: options.preferViewportRows === true,
|
|
519
484
|
});
|
|
520
485
|
if (state.lastRenderSignature === signature) {
|
|
521
486
|
return;
|
|
@@ -529,14 +494,13 @@ function renderTerminalPayload(payload, options = {}) {
|
|
|
529
494
|
return;
|
|
530
495
|
}
|
|
531
496
|
|
|
532
|
-
const size = estimateTerminalSizeFromPayload(payload, options);
|
|
533
497
|
const previousViewportY = terminal.buffer.active.viewportY;
|
|
534
498
|
const previousBaseY = terminal.buffer.active.baseY;
|
|
535
499
|
const wasNearBottom =
|
|
536
500
|
previousBaseY <= 0 ||
|
|
537
501
|
previousViewportY >= Math.max(0, previousBaseY - 2);
|
|
538
502
|
terminal.reset();
|
|
539
|
-
|
|
503
|
+
fitTerminal();
|
|
540
504
|
terminal.write(payload.ansi || payload.content || "");
|
|
541
505
|
if (options.forceScrollBottom === true || wasNearBottom) {
|
|
542
506
|
terminal.scrollToBottom();
|
|
@@ -544,7 +508,7 @@ function renderTerminalPayload(payload, options = {}) {
|
|
|
544
508
|
terminal.scrollToLine(Math.min(previousViewportY, terminal.buffer.active.baseY));
|
|
545
509
|
}
|
|
546
510
|
window.setTimeout(() => {
|
|
547
|
-
|
|
511
|
+
fitTerminal();
|
|
548
512
|
}, 0);
|
|
549
513
|
state.lastRenderSignature = signature;
|
|
550
514
|
}
|
|
@@ -888,7 +852,6 @@ async function bootstrap() {
|
|
|
888
852
|
function applyBootstrapPayload(bootstrapPayload) {
|
|
889
853
|
state.token = bootstrapPayload.token;
|
|
890
854
|
state.sessionId = bootstrapPayload.session_id;
|
|
891
|
-
state.pollIntervalMs = bootstrapPayload.poll_interval_ms || state.pollIntervalMs;
|
|
892
855
|
elements.session.textContent =
|
|
893
856
|
bootstrapPayload.session_label || bootstrapPayload.session_id;
|
|
894
857
|
elements.session.hidden = false;
|
|
@@ -928,22 +891,6 @@ async function withRecoveredSession(operation) {
|
|
|
928
891
|
}
|
|
929
892
|
}
|
|
930
893
|
|
|
931
|
-
async function fetchVisibleBuffer() {
|
|
932
|
-
const response = await fetch(config.basePath + "/api/view", {
|
|
933
|
-
method: "GET",
|
|
934
|
-
headers: {
|
|
935
|
-
authorization: "Bearer " + state.token,
|
|
936
|
-
},
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
if (!response.ok) {
|
|
940
|
-
const text = await response.text();
|
|
941
|
-
throw createHttpError(text || "Failed to fetch visible buffer.", response.status);
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
return response.json();
|
|
945
|
-
}
|
|
946
|
-
|
|
947
894
|
async function sendAction(action) {
|
|
948
895
|
if (state.actionBusy || !state.token) {
|
|
949
896
|
return;
|
|
@@ -1036,74 +983,132 @@ function closeLiveSocket() {
|
|
|
1036
983
|
}
|
|
1037
984
|
}
|
|
1038
985
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
986
|
+
function clearLiveReconnectTimer() {
|
|
987
|
+
if (state.liveReconnectTimer) {
|
|
988
|
+
clearTimeout(state.liveReconnectTimer);
|
|
989
|
+
state.liveReconnectTimer = null;
|
|
1043
990
|
}
|
|
991
|
+
}
|
|
1044
992
|
|
|
1045
|
-
|
|
1046
|
-
|
|
993
|
+
function scheduleLiveReconnect() {
|
|
994
|
+
if (
|
|
995
|
+
state.liveSocketConnected ||
|
|
996
|
+
state.liveReconnectTimer ||
|
|
997
|
+
!state.token
|
|
998
|
+
) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
const delay = Math.min(
|
|
1003
|
+
30000,
|
|
1004
|
+
1000 * 2 ** Math.min(state.liveReconnectAttempt, 5),
|
|
1005
|
+
);
|
|
1006
|
+
state.liveReconnectAttempt += 1;
|
|
1007
|
+
state.liveReconnectTimer = setTimeout(async () => {
|
|
1008
|
+
state.liveReconnectTimer = null;
|
|
1009
|
+
try {
|
|
1010
|
+
await connectLiveSocket();
|
|
1011
|
+
} catch (_error) {
|
|
1012
|
+
setLiveModeStatus("reconnect");
|
|
1013
|
+
scheduleLiveReconnect();
|
|
1014
|
+
}
|
|
1015
|
+
}, delay);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
function connectLiveSocket() {
|
|
1019
|
+
if (
|
|
1020
|
+
state.liveSocketConnected &&
|
|
1021
|
+
state.liveSocket?.readyState === WebSocket.OPEN
|
|
1022
|
+
) {
|
|
1023
|
+
return Promise.resolve();
|
|
1024
|
+
}
|
|
1025
|
+
if (state.liveConnectPromise) {
|
|
1026
|
+
return state.liveConnectPromise;
|
|
1027
|
+
}
|
|
1047
1028
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1029
|
+
state.liveConnectPromise = (async () => {
|
|
1030
|
+
closeLiveSocket();
|
|
1031
|
+
if (!state.token) {
|
|
1032
|
+
throw new Error("WebApp token is missing");
|
|
1033
|
+
}
|
|
1050
1034
|
|
|
1051
|
-
socket
|
|
1052
|
-
|
|
1053
|
-
settled = true;
|
|
1054
|
-
stopPolling();
|
|
1055
|
-
resolve();
|
|
1056
|
-
}, { once: true });
|
|
1035
|
+
const socket = new WebSocket(getLiveWsUrl());
|
|
1036
|
+
state.liveSocket = socket;
|
|
1057
1037
|
|
|
1058
|
-
socket.addEventListener("
|
|
1059
|
-
if (
|
|
1038
|
+
socket.addEventListener("message", (event) => {
|
|
1039
|
+
if (state.liveSocket !== socket) {
|
|
1060
1040
|
return;
|
|
1061
1041
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
previousBaseY <= 0 ||
|
|
1085
|
-
previousViewportY >= Math.max(0, previousBaseY - 2);
|
|
1086
|
-
terminal.write(payload.data);
|
|
1087
|
-
if (wasNearBottom) {
|
|
1088
|
-
terminal.scrollToBottom();
|
|
1042
|
+
const payload = JSON.parse(String(event.data));
|
|
1043
|
+
if (payload.type === "snapshot") {
|
|
1044
|
+
state.liveReconnectAttempt = 0;
|
|
1045
|
+
renderTerminalPayload(payload, {
|
|
1046
|
+
forceScrollBottom: true,
|
|
1047
|
+
});
|
|
1048
|
+
setUpdated(formatCapturedAt(payload.captured_at));
|
|
1049
|
+
setLiveModeStatus("stream");
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
if (payload.type === "data") {
|
|
1053
|
+
const terminal = ensureXterm();
|
|
1054
|
+
if (terminal && typeof payload.data === "string") {
|
|
1055
|
+
const previousViewportY = terminal.buffer.active.viewportY;
|
|
1056
|
+
const previousBaseY = terminal.buffer.active.baseY;
|
|
1057
|
+
const wasNearBottom =
|
|
1058
|
+
previousBaseY <= 0 ||
|
|
1059
|
+
previousViewportY >= Math.max(0, previousBaseY - 2);
|
|
1060
|
+
terminal.write(payload.data);
|
|
1061
|
+
if (wasNearBottom) {
|
|
1062
|
+
terminal.scrollToBottom();
|
|
1063
|
+
}
|
|
1089
1064
|
}
|
|
1065
|
+
return;
|
|
1090
1066
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1097
|
-
});
|
|
1067
|
+
if (payload.type === "exit") {
|
|
1068
|
+
setStatus("Terminal exited", true);
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1098
1071
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1072
|
+
await new Promise((resolve, reject) => {
|
|
1073
|
+
let settled = false;
|
|
1074
|
+
|
|
1075
|
+
socket.addEventListener("open", () => {
|
|
1076
|
+
if (state.liveSocket !== socket) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
state.liveSocketConnected = true;
|
|
1080
|
+
clearLiveReconnectTimer();
|
|
1081
|
+
settled = true;
|
|
1082
|
+
resolve();
|
|
1083
|
+
}, { once: true });
|
|
1084
|
+
|
|
1085
|
+
socket.addEventListener("error", () => {
|
|
1086
|
+
if (settled) {
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
settled = true;
|
|
1090
|
+
reject(new Error("Live stream connection failed"));
|
|
1091
|
+
}, { once: true });
|
|
1092
|
+
|
|
1093
|
+
socket.addEventListener("close", () => {
|
|
1094
|
+
if (state.liveSocket !== socket) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
state.liveSocket = null;
|
|
1098
|
+
state.liveSocketConnected = false;
|
|
1099
|
+
if (!settled) {
|
|
1100
|
+
settled = true;
|
|
1101
|
+
reject(new Error("Live stream connection closed"));
|
|
1102
|
+
}
|
|
1103
|
+
setLiveModeStatus("reconnect");
|
|
1104
|
+
scheduleLiveReconnect();
|
|
1105
|
+
});
|
|
1106
|
+
});
|
|
1107
|
+
})().finally(() => {
|
|
1108
|
+
state.liveConnectPromise = null;
|
|
1106
1109
|
});
|
|
1110
|
+
|
|
1111
|
+
return state.liveConnectPromise;
|
|
1107
1112
|
}
|
|
1108
1113
|
|
|
1109
1114
|
function confirmInterrupt() {
|
|
@@ -1119,33 +1124,6 @@ function confirmInterrupt() {
|
|
|
1119
1124
|
});
|
|
1120
1125
|
}
|
|
1121
1126
|
|
|
1122
|
-
async function refreshVisibleBuffer() {
|
|
1123
|
-
const payload = await withRecoveredSession(fetchVisibleBuffer);
|
|
1124
|
-
renderTerminalPayload(payload);
|
|
1125
|
-
setUpdated(formatCapturedAt(payload.captured_at));
|
|
1126
|
-
setLiveModeStatus("poll");
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
function stopPolling() {
|
|
1130
|
-
if (state.timer) {
|
|
1131
|
-
clearTimeout(state.timer);
|
|
1132
|
-
state.timer = null;
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
function startPolling() {
|
|
1137
|
-
stopPolling();
|
|
1138
|
-
state.timer = setTimeout(async () => {
|
|
1139
|
-
try {
|
|
1140
|
-
await refreshVisibleBuffer();
|
|
1141
|
-
} catch (error) {
|
|
1142
|
-
setStatus(error.message || String(error), true);
|
|
1143
|
-
} finally {
|
|
1144
|
-
startPolling();
|
|
1145
|
-
}
|
|
1146
|
-
}, state.pollIntervalMs);
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
1127
|
function bindUi() {
|
|
1150
1128
|
elements.wrap.addEventListener("click", () => {
|
|
1151
1129
|
toggleWrapMode();
|
|
@@ -1235,8 +1213,8 @@ async function main() {
|
|
|
1235
1213
|
try {
|
|
1236
1214
|
await connectLiveSocket();
|
|
1237
1215
|
} catch (_error) {
|
|
1238
|
-
|
|
1239
|
-
|
|
1216
|
+
setLiveModeStatus("reconnect");
|
|
1217
|
+
scheduleLiveReconnect();
|
|
1240
1218
|
}
|
|
1241
1219
|
} catch (error) {
|
|
1242
1220
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1298,6 +1276,9 @@ ${XTERM_WEBAPP_CSS}</style>
|
|
|
1298
1276
|
${XTERM_WEBAPP_JS}
|
|
1299
1277
|
</script>
|
|
1300
1278
|
<script>
|
|
1279
|
+
${XTERM_FIT_WEBAPP_JS}
|
|
1280
|
+
</script>
|
|
1281
|
+
<script>
|
|
1301
1282
|
(() => {
|
|
1302
1283
|
const source = ${JSON.stringify(exports.WEBAPP_APP_JS)};
|
|
1303
1284
|
(0, eval)(source);
|