tmex-cli 0.9.0-test-1 → 0.9.1
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.
|
Binary file
|
package/dist/runtime/server.js
CHANGED
|
@@ -7721,7 +7721,7 @@ var require_bcrypt_pbkdf = __commonJS((exports, module) => {
|
|
|
7721
7721
|
|
|
7722
7722
|
// ../../node_modules/.bun/cpu-features@0.0.10/node_modules/cpu-features/build/Release/cpufeatures.node
|
|
7723
7723
|
var require_cpufeatures = __commonJS((exports, module) => {
|
|
7724
|
-
module.exports = __require("./cpufeatures-
|
|
7724
|
+
module.exports = __require("./cpufeatures-dxrn1j88.node");
|
|
7725
7725
|
});
|
|
7726
7726
|
|
|
7727
7727
|
// ../../node_modules/.bun/cpu-features@0.0.10/node_modules/cpu-features/lib/index.js
|
|
@@ -8334,12 +8334,12 @@ var require_utils3 = __commonJS((exports, module) => {
|
|
|
8334
8334
|
|
|
8335
8335
|
// ../../node_modules/.bun/ssh2@1.17.0/node_modules/ssh2/lib/protocol/crypto/build/Release/sshcrypto.node
|
|
8336
8336
|
var require_sshcrypto = __commonJS((exports, module) => {
|
|
8337
|
-
module.exports = __require("./sshcrypto-
|
|
8337
|
+
module.exports = __require("./sshcrypto-fjcj736m.node");
|
|
8338
8338
|
});
|
|
8339
8339
|
|
|
8340
8340
|
// ../../node_modules/.bun/ssh2@1.17.0/node_modules/ssh2/lib/protocol/crypto/poly1305.js
|
|
8341
8341
|
var require_poly1305 = __commonJS((exports, module) => {
|
|
8342
|
-
var __dirname = "/Users/krhougs/LocalCodes/tmex
|
|
8342
|
+
var __dirname = "/Users/krhougs/LocalCodes/tmex/node_modules/.bun/ssh2@1.17.0/node_modules/ssh2/lib/protocol/crypto", __filename = "/Users/krhougs/LocalCodes/tmex/node_modules/.bun/ssh2@1.17.0/node_modules/ssh2/lib/protocol/crypto/poly1305.js";
|
|
8343
8343
|
var createPoly1305 = function() {
|
|
8344
8344
|
var _scriptDir = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : undefined;
|
|
8345
8345
|
if (typeof __filename !== "undefined")
|
|
@@ -11112,7 +11112,7 @@ ${formatted}-----END ${type} KEY-----`;
|
|
|
11112
11112
|
|
|
11113
11113
|
// ../../node_modules/.bun/ssh2@1.17.0/node_modules/ssh2/lib/agent.js
|
|
11114
11114
|
var require_agent = __commonJS((exports, module) => {
|
|
11115
|
-
var __dirname = "/Users/krhougs/LocalCodes/tmex
|
|
11115
|
+
var __dirname = "/Users/krhougs/LocalCodes/tmex/node_modules/.bun/ssh2@1.17.0/node_modules/ssh2/lib";
|
|
11116
11116
|
var { Socket } = __require("net");
|
|
11117
11117
|
var { Duplex } = __require("stream");
|
|
11118
11118
|
var { resolve: resolve3 } = __require("path");
|
|
@@ -95739,6 +95739,9 @@ var TMEX_INJECTED_ENV_EXACT = new Set(["NODE_ENV", "DATABASE_URL", "GATEWAY_PORT
|
|
|
95739
95739
|
function isTmexInjectedEnvKey(key) {
|
|
95740
95740
|
return key.startsWith("TMEX_") || TMEX_INJECTED_ENV_EXACT.has(key);
|
|
95741
95741
|
}
|
|
95742
|
+
function isUtf8Locale(value) {
|
|
95743
|
+
return typeof value === "string" && /utf-?8/i.test(value);
|
|
95744
|
+
}
|
|
95742
95745
|
function buildLocalTmuxEnv(resolvedPath, baseEnv = process.env) {
|
|
95743
95746
|
const nextEnv = {};
|
|
95744
95747
|
for (const [key, value] of Object.entries(baseEnv)) {
|
|
@@ -95750,8 +95753,8 @@ function buildLocalTmuxEnv(resolvedPath, baseEnv = process.env) {
|
|
|
95750
95753
|
if (resolvedPath) {
|
|
95751
95754
|
nextEnv.PATH = resolvedPath;
|
|
95752
95755
|
}
|
|
95753
|
-
if (!nextEnv.
|
|
95754
|
-
nextEnv.
|
|
95756
|
+
if (!isUtf8Locale(nextEnv.LC_ALL) && (nextEnv.LC_ALL || !isUtf8Locale(nextEnv.LC_CTYPE) && !isUtf8Locale(nextEnv.LANG))) {
|
|
95757
|
+
nextEnv.LC_ALL = "C.UTF-8";
|
|
95755
95758
|
}
|
|
95756
95759
|
return nextEnv;
|
|
95757
95760
|
}
|
|
@@ -96631,6 +96634,76 @@ function encodeInputToHexChunks(input, chunkBytes = SEND_KEYS_HEX_CHUNK_BYTES) {
|
|
|
96631
96634
|
return chunks;
|
|
96632
96635
|
}
|
|
96633
96636
|
|
|
96637
|
+
// ../../apps/gateway/src/tmux-client/snapshot-format.ts
|
|
96638
|
+
var SNAPSHOT_FIELD_SEPARATOR = "|";
|
|
96639
|
+
var TMUX_SESSION_ID_PATTERN = /^\$\d+$/;
|
|
96640
|
+
var TMUX_WINDOW_ID_PATTERN = /^@\d+$/;
|
|
96641
|
+
var TMUX_PANE_ID_PATTERN = /^%\d+$/;
|
|
96642
|
+
function isTmuxSessionId(value) {
|
|
96643
|
+
return typeof value === "string" && TMUX_SESSION_ID_PATTERN.test(value);
|
|
96644
|
+
}
|
|
96645
|
+
function isTmuxWindowId(value) {
|
|
96646
|
+
return typeof value === "string" && TMUX_WINDOW_ID_PATTERN.test(value);
|
|
96647
|
+
}
|
|
96648
|
+
function isTmuxPaneId(value) {
|
|
96649
|
+
return typeof value === "string" && TMUX_PANE_ID_PATTERN.test(value);
|
|
96650
|
+
}
|
|
96651
|
+
function parseSnapshotInteger(value) {
|
|
96652
|
+
if (typeof value !== "string" || !/^\d+$/.test(value)) {
|
|
96653
|
+
return null;
|
|
96654
|
+
}
|
|
96655
|
+
return Number.parseInt(value, 10);
|
|
96656
|
+
}
|
|
96657
|
+
function formatSnapshotRowForLog(line, limit = 160) {
|
|
96658
|
+
if (line.length <= limit) {
|
|
96659
|
+
return line;
|
|
96660
|
+
}
|
|
96661
|
+
return `${line.slice(0, Math.max(0, limit - 3))}...`;
|
|
96662
|
+
}
|
|
96663
|
+
function splitSnapshotFields(line, fieldCount) {
|
|
96664
|
+
const parts = line.split(SNAPSHOT_FIELD_SEPARATOR);
|
|
96665
|
+
if (parts.length <= fieldCount) {
|
|
96666
|
+
return parts;
|
|
96667
|
+
}
|
|
96668
|
+
if (fieldCount === 2) {
|
|
96669
|
+
return [parts[0] ?? "", parts.slice(1).join(SNAPSHOT_FIELD_SEPARATOR)];
|
|
96670
|
+
}
|
|
96671
|
+
if (fieldCount === 4) {
|
|
96672
|
+
return [
|
|
96673
|
+
parts[0] ?? "",
|
|
96674
|
+
parts[1] ?? "",
|
|
96675
|
+
parts.slice(2, -1).join(SNAPSHOT_FIELD_SEPARATOR),
|
|
96676
|
+
parts.at(-1) ?? ""
|
|
96677
|
+
];
|
|
96678
|
+
}
|
|
96679
|
+
if (fieldCount === 8) {
|
|
96680
|
+
return [
|
|
96681
|
+
parts[0] ?? "",
|
|
96682
|
+
parts[1] ?? "",
|
|
96683
|
+
parts[2] ?? "",
|
|
96684
|
+
parts.slice(3, -4).join(SNAPSHOT_FIELD_SEPARATOR),
|
|
96685
|
+
parts.at(-4) ?? "",
|
|
96686
|
+
parts.at(-3) ?? "",
|
|
96687
|
+
parts.at(-2) ?? "",
|
|
96688
|
+
parts.at(-1) ?? ""
|
|
96689
|
+
];
|
|
96690
|
+
}
|
|
96691
|
+
if (fieldCount === 9) {
|
|
96692
|
+
return [
|
|
96693
|
+
parts[0] ?? "",
|
|
96694
|
+
parts[1] ?? "",
|
|
96695
|
+
parts[2] ?? "",
|
|
96696
|
+
parts.slice(3, -5).join(SNAPSHOT_FIELD_SEPARATOR),
|
|
96697
|
+
parts.at(-5) ?? "",
|
|
96698
|
+
parts.at(-4) ?? "",
|
|
96699
|
+
parts.at(-3) ?? "",
|
|
96700
|
+
parts.at(-2) ?? "",
|
|
96701
|
+
parts.at(-1) ?? ""
|
|
96702
|
+
];
|
|
96703
|
+
}
|
|
96704
|
+
return parts;
|
|
96705
|
+
}
|
|
96706
|
+
|
|
96634
96707
|
// ../../apps/gateway/src/tmux-client/target-missing.ts
|
|
96635
96708
|
class TmuxTargetMissingError extends Error {
|
|
96636
96709
|
constructor(message) {
|
|
@@ -96854,7 +96927,7 @@ class LocalExternalTmuxConnection {
|
|
|
96854
96927
|
if (!this.connected) {
|
|
96855
96928
|
return;
|
|
96856
96929
|
}
|
|
96857
|
-
this.runAndRefresh(["select-window", "-t", windowId]).catch((error51) => {
|
|
96930
|
+
this.runAndRefresh(["select-window", "-t", windowId], true).catch((error51) => {
|
|
96858
96931
|
this.callbacks.onError(error51);
|
|
96859
96932
|
});
|
|
96860
96933
|
}
|
|
@@ -97278,14 +97351,14 @@ class LocalExternalTmuxConnection {
|
|
|
97278
97351
|
"-p",
|
|
97279
97352
|
"-t",
|
|
97280
97353
|
this.sessionName,
|
|
97281
|
-
"#{session_id}
|
|
97354
|
+
["#{session_id}", "#{session_name}"].join(SNAPSHOT_FIELD_SEPARATOR)
|
|
97282
97355
|
]),
|
|
97283
97356
|
this.runTmuxAllowFailure([
|
|
97284
97357
|
"list-windows",
|
|
97285
97358
|
"-t",
|
|
97286
97359
|
this.sessionName,
|
|
97287
97360
|
"-F",
|
|
97288
|
-
"#{window_id}
|
|
97361
|
+
["#{window_id}", "#{window_index}", "#{window_name}", "#{window_active}"].join(SNAPSHOT_FIELD_SEPARATOR)
|
|
97289
97362
|
]),
|
|
97290
97363
|
this.runTmuxAllowFailure([
|
|
97291
97364
|
"list-panes",
|
|
@@ -97293,7 +97366,17 @@ class LocalExternalTmuxConnection {
|
|
|
97293
97366
|
"-t",
|
|
97294
97367
|
this.sessionName,
|
|
97295
97368
|
"-F",
|
|
97296
|
-
|
|
97369
|
+
[
|
|
97370
|
+
"#{pane_id}",
|
|
97371
|
+
"#{window_id}",
|
|
97372
|
+
"#{pane_index}",
|
|
97373
|
+
"#{pane_title}",
|
|
97374
|
+
"#{pane_active}",
|
|
97375
|
+
"#{pane_width}",
|
|
97376
|
+
"#{pane_height}",
|
|
97377
|
+
"#{window_active}",
|
|
97378
|
+
"#{pane_current_command}"
|
|
97379
|
+
].join(SNAPSHOT_FIELD_SEPARATOR)
|
|
97297
97380
|
])
|
|
97298
97381
|
]);
|
|
97299
97382
|
if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
|
|
@@ -97317,6 +97400,7 @@ ${panesRes.stderr}`;
|
|
|
97317
97400
|
this.parseSnapshotSession(sessionRes.stdout.split(/\r?\n/));
|
|
97318
97401
|
this.parseSnapshotWindows(windowsRes.stdout.split(/\r?\n/));
|
|
97319
97402
|
this.parseSnapshotPanes(panesRes.stdout.split(/\r?\n/));
|
|
97403
|
+
this.discardInvalidSnapshot();
|
|
97320
97404
|
this.controlSubscription?.prunePanes(new Set(this.getExpectedPaneIds()));
|
|
97321
97405
|
this.emitSnapshot();
|
|
97322
97406
|
}
|
|
@@ -97326,9 +97410,11 @@ ${panesRes.stderr}`;
|
|
|
97326
97410
|
if (!line.trim()) {
|
|
97327
97411
|
continue;
|
|
97328
97412
|
}
|
|
97329
|
-
const [id, name24] = line
|
|
97330
|
-
if (id) {
|
|
97413
|
+
const [id, name24] = splitSnapshotFields(line, 2);
|
|
97414
|
+
if (isTmuxSessionId(id)) {
|
|
97331
97415
|
this.snapshotSession = { id, name: name24 ?? "" };
|
|
97416
|
+
} else {
|
|
97417
|
+
console.warn(`[local] ignoring invalid tmux session id on ${this.deviceId}: ${id ?? ""}`);
|
|
97332
97418
|
}
|
|
97333
97419
|
return;
|
|
97334
97420
|
}
|
|
@@ -97339,18 +97425,19 @@ ${panesRes.stderr}`;
|
|
|
97339
97425
|
if (!line.trim()) {
|
|
97340
97426
|
continue;
|
|
97341
97427
|
}
|
|
97342
|
-
const [id, indexRaw, name24, activeRaw] = line
|
|
97343
|
-
|
|
97428
|
+
const [id, indexRaw, name24, activeRaw] = splitSnapshotFields(line, 4);
|
|
97429
|
+
const index = parseSnapshotInteger(indexRaw);
|
|
97430
|
+
if (!isTmuxWindowId(id) || index === null || !this.isSnapshotFlag(activeRaw)) {
|
|
97431
|
+
console.warn(`[local] ignoring invalid tmux window snapshot row on ${this.deviceId}: ${formatSnapshotRowForLog(line)}`);
|
|
97344
97432
|
continue;
|
|
97345
97433
|
}
|
|
97346
|
-
const index = Number.parseInt(indexRaw ?? "", 10);
|
|
97347
97434
|
const active = activeRaw === "1";
|
|
97348
97435
|
if (active) {
|
|
97349
97436
|
this.activeWindowId = id;
|
|
97350
97437
|
}
|
|
97351
97438
|
this.snapshotWindows.set(id, {
|
|
97352
97439
|
id,
|
|
97353
|
-
index
|
|
97440
|
+
index,
|
|
97354
97441
|
name: name24 ?? "",
|
|
97355
97442
|
active,
|
|
97356
97443
|
panes: []
|
|
@@ -97365,22 +97452,23 @@ ${panesRes.stderr}`;
|
|
|
97365
97452
|
if (!line.trim()) {
|
|
97366
97453
|
continue;
|
|
97367
97454
|
}
|
|
97368
|
-
const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw, windowActiveRaw, currentCommandRaw] = line
|
|
97369
|
-
|
|
97455
|
+
const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw, windowActiveRaw, currentCommandRaw] = splitSnapshotFields(line, 9);
|
|
97456
|
+
const index = parseSnapshotInteger(indexRaw);
|
|
97457
|
+
const width = parseSnapshotInteger(widthRaw);
|
|
97458
|
+
const height = parseSnapshotInteger(heightRaw);
|
|
97459
|
+
if (!isTmuxPaneId(paneId) || !isTmuxWindowId(windowId) || index === null || width === null || height === null || !this.isSnapshotFlag(activeRaw) || !this.isSnapshotFlag(windowActiveRaw)) {
|
|
97460
|
+
console.warn(`[local] ignoring invalid tmux pane snapshot row on ${this.deviceId}: ${formatSnapshotRowForLog(line)}`);
|
|
97370
97461
|
continue;
|
|
97371
97462
|
}
|
|
97372
|
-
const index = Number.parseInt(indexRaw ?? "", 10);
|
|
97373
|
-
const width = Number.parseInt(widthRaw ?? "", 10);
|
|
97374
|
-
const height = Number.parseInt(heightRaw ?? "", 10);
|
|
97375
97463
|
const pane = {
|
|
97376
97464
|
id: paneId,
|
|
97377
97465
|
windowId,
|
|
97378
|
-
index
|
|
97466
|
+
index,
|
|
97379
97467
|
title: this.pendingPaneTitles.get(paneId) ?? (titleRaw?.trim() ? titleRaw : undefined),
|
|
97380
97468
|
currentCommand: currentCommandRaw?.trim() ? currentCommandRaw.trim() : undefined,
|
|
97381
97469
|
active: activeRaw === "1",
|
|
97382
|
-
width
|
|
97383
|
-
height
|
|
97470
|
+
width,
|
|
97471
|
+
height
|
|
97384
97472
|
};
|
|
97385
97473
|
if (pane.active && windowActiveRaw === "1") {
|
|
97386
97474
|
this.activePaneId = paneId;
|
|
@@ -97397,6 +97485,23 @@ ${panesRes.stderr}`;
|
|
|
97397
97485
|
window2.panes.sort((left, right) => left.index - right.index);
|
|
97398
97486
|
}
|
|
97399
97487
|
}
|
|
97488
|
+
isSnapshotFlag(value) {
|
|
97489
|
+
return value === "0" || value === "1";
|
|
97490
|
+
}
|
|
97491
|
+
discardInvalidSnapshot() {
|
|
97492
|
+
if (!this.snapshotSession) {
|
|
97493
|
+
this.snapshotWindows.clear();
|
|
97494
|
+
this.activeWindowId = null;
|
|
97495
|
+
this.activePaneId = null;
|
|
97496
|
+
return;
|
|
97497
|
+
}
|
|
97498
|
+
if (this.snapshotWindows.size === 0) {
|
|
97499
|
+
console.warn(`[local] ignoring tmux snapshot with no valid windows on ${this.deviceId}`);
|
|
97500
|
+
this.snapshotSession = null;
|
|
97501
|
+
this.activeWindowId = null;
|
|
97502
|
+
this.activePaneId = null;
|
|
97503
|
+
}
|
|
97504
|
+
}
|
|
97400
97505
|
emitSnapshot() {
|
|
97401
97506
|
const session = this.snapshotSession ? {
|
|
97402
97507
|
id: this.snapshotSession.id,
|
|
@@ -97457,6 +97562,7 @@ ${panesRes.stderr}`;
|
|
|
97457
97562
|
this.recoverFromTargetMissingError(message);
|
|
97458
97563
|
return result;
|
|
97459
97564
|
}
|
|
97565
|
+
console.warn(`[local] tmux command failed deviceId=${this.deviceId} sessionName=${this.sessionName} argv=${argv.join(" ")} exitCode=${result.exitCode}: ${message}`);
|
|
97460
97566
|
this.notifyRuntimeError(message);
|
|
97461
97567
|
if (this.connected && !this.manualDisconnect && this.isTmuxServerGoneMessage(message)) {
|
|
97462
97568
|
console.warn(`[local] tmux server gone on ${this.deviceId}: ${message}`);
|
|
@@ -97868,51 +97974,12 @@ function hasRenderableTerminalContent2(value) {
|
|
|
97868
97974
|
}
|
|
97869
97975
|
var BELL_DEDUP_WINDOW_MS2 = 200;
|
|
97870
97976
|
var COMMAND_SENTINEL = "\x1ETMEX_END ";
|
|
97871
|
-
var SNAPSHOT_FIELD_SEPARATOR = "|";
|
|
97872
97977
|
var CONTROL_MAX_RESTARTS2 = 3;
|
|
97873
97978
|
var CONTROL_RESTART_DELAY_MS2 = 500;
|
|
97874
97979
|
var CONTROL_STABLE_RESET_MS2 = 1e4;
|
|
97875
97980
|
var CONTROL_STDERR_TAIL_LIMIT2 = 2048;
|
|
97876
97981
|
var CONTROL_ATTACH_READY_TIMEOUT_MS2 = 3000;
|
|
97877
97982
|
var PARKING_WINDOW_NAME2 = "tmex-park";
|
|
97878
|
-
function splitSnapshotFields(line, fieldCount) {
|
|
97879
|
-
const parts = line.split(SNAPSHOT_FIELD_SEPARATOR);
|
|
97880
|
-
if (parts.length <= fieldCount) {
|
|
97881
|
-
return parts;
|
|
97882
|
-
}
|
|
97883
|
-
if (fieldCount === 2) {
|
|
97884
|
-
return [parts[0] ?? "", parts.slice(1).join(SNAPSHOT_FIELD_SEPARATOR)];
|
|
97885
|
-
}
|
|
97886
|
-
if (fieldCount === 4) {
|
|
97887
|
-
return [parts[0] ?? "", parts[1] ?? "", parts.slice(2, -1).join(SNAPSHOT_FIELD_SEPARATOR), parts.at(-1) ?? ""];
|
|
97888
|
-
}
|
|
97889
|
-
if (fieldCount === 8) {
|
|
97890
|
-
return [
|
|
97891
|
-
parts[0] ?? "",
|
|
97892
|
-
parts[1] ?? "",
|
|
97893
|
-
parts[2] ?? "",
|
|
97894
|
-
parts.slice(3, -4).join(SNAPSHOT_FIELD_SEPARATOR),
|
|
97895
|
-
parts.at(-4) ?? "",
|
|
97896
|
-
parts.at(-3) ?? "",
|
|
97897
|
-
parts.at(-2) ?? "",
|
|
97898
|
-
parts.at(-1) ?? ""
|
|
97899
|
-
];
|
|
97900
|
-
}
|
|
97901
|
-
if (fieldCount === 9) {
|
|
97902
|
-
return [
|
|
97903
|
-
parts[0] ?? "",
|
|
97904
|
-
parts[1] ?? "",
|
|
97905
|
-
parts[2] ?? "",
|
|
97906
|
-
parts.slice(3, -5).join(SNAPSHOT_FIELD_SEPARATOR),
|
|
97907
|
-
parts.at(-5) ?? "",
|
|
97908
|
-
parts.at(-4) ?? "",
|
|
97909
|
-
parts.at(-3) ?? "",
|
|
97910
|
-
parts.at(-2) ?? "",
|
|
97911
|
-
parts.at(-1) ?? ""
|
|
97912
|
-
];
|
|
97913
|
-
}
|
|
97914
|
-
return parts;
|
|
97915
|
-
}
|
|
97916
97983
|
|
|
97917
97984
|
class SshExternalTmuxConnection {
|
|
97918
97985
|
deviceId;
|
|
@@ -98024,7 +98091,7 @@ class SshExternalTmuxConnection {
|
|
|
98024
98091
|
if (!this.connected) {
|
|
98025
98092
|
return;
|
|
98026
98093
|
}
|
|
98027
|
-
this.runAndRefresh(["select-window", "-t", windowId]).catch((error51) => {
|
|
98094
|
+
this.runAndRefresh(["select-window", "-t", windowId], true).catch((error51) => {
|
|
98028
98095
|
this.callbacks.onError(error51);
|
|
98029
98096
|
});
|
|
98030
98097
|
}
|
|
@@ -98564,6 +98631,7 @@ ${panesRes.stderr}`;
|
|
|
98564
98631
|
this.parseSnapshotSession(sessionRes.stdout.split(/\r?\n/));
|
|
98565
98632
|
this.parseSnapshotWindows(windowsRes.stdout.split(/\r?\n/));
|
|
98566
98633
|
this.parseSnapshotPanes(panesRes.stdout.split(/\r?\n/));
|
|
98634
|
+
this.discardInvalidSnapshot();
|
|
98567
98635
|
this.controlSubscription?.prunePanes(new Set(this.getExpectedPaneIds()));
|
|
98568
98636
|
this.emitSnapshot();
|
|
98569
98637
|
}
|
|
@@ -98574,8 +98642,10 @@ ${panesRes.stderr}`;
|
|
|
98574
98642
|
continue;
|
|
98575
98643
|
}
|
|
98576
98644
|
const [id, name24] = splitSnapshotFields(line, 2);
|
|
98577
|
-
if (id) {
|
|
98645
|
+
if (isTmuxSessionId(id)) {
|
|
98578
98646
|
this.snapshotSession = { id, name: name24 ?? "" };
|
|
98647
|
+
} else {
|
|
98648
|
+
console.warn(`[ssh] ignoring invalid tmux session id on ${this.deviceId}: ${id ?? ""}`);
|
|
98579
98649
|
}
|
|
98580
98650
|
return;
|
|
98581
98651
|
}
|
|
@@ -98587,17 +98657,18 @@ ${panesRes.stderr}`;
|
|
|
98587
98657
|
continue;
|
|
98588
98658
|
}
|
|
98589
98659
|
const [id, indexRaw, name24, activeRaw] = splitSnapshotFields(line, 4);
|
|
98590
|
-
|
|
98660
|
+
const index = parseSnapshotInteger(indexRaw);
|
|
98661
|
+
if (!isTmuxWindowId(id) || index === null || !this.isSnapshotFlag(activeRaw)) {
|
|
98662
|
+
console.warn(`[ssh] ignoring invalid tmux window snapshot row on ${this.deviceId}: ${formatSnapshotRowForLog(line)}`);
|
|
98591
98663
|
continue;
|
|
98592
98664
|
}
|
|
98593
|
-
const index = Number.parseInt(indexRaw ?? "", 10);
|
|
98594
98665
|
const active = activeRaw === "1";
|
|
98595
98666
|
if (active) {
|
|
98596
98667
|
this.activeWindowId = id;
|
|
98597
98668
|
}
|
|
98598
98669
|
this.snapshotWindows.set(id, {
|
|
98599
98670
|
id,
|
|
98600
|
-
index
|
|
98671
|
+
index,
|
|
98601
98672
|
name: name24 ?? "",
|
|
98602
98673
|
active,
|
|
98603
98674
|
panes: []
|
|
@@ -98613,21 +98684,22 @@ ${panesRes.stderr}`;
|
|
|
98613
98684
|
continue;
|
|
98614
98685
|
}
|
|
98615
98686
|
const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw, windowActiveRaw, currentCommandRaw] = splitSnapshotFields(line, 9);
|
|
98616
|
-
|
|
98687
|
+
const index = parseSnapshotInteger(indexRaw);
|
|
98688
|
+
const width = parseSnapshotInteger(widthRaw);
|
|
98689
|
+
const height = parseSnapshotInteger(heightRaw);
|
|
98690
|
+
if (!isTmuxPaneId(paneId) || !isTmuxWindowId(windowId) || index === null || width === null || height === null || !this.isSnapshotFlag(activeRaw) || !this.isSnapshotFlag(windowActiveRaw)) {
|
|
98691
|
+
console.warn(`[ssh] ignoring invalid tmux pane snapshot row on ${this.deviceId}: ${formatSnapshotRowForLog(line)}`);
|
|
98617
98692
|
continue;
|
|
98618
98693
|
}
|
|
98619
|
-
const index = Number.parseInt(indexRaw ?? "", 10);
|
|
98620
|
-
const width = Number.parseInt(widthRaw ?? "", 10);
|
|
98621
|
-
const height = Number.parseInt(heightRaw ?? "", 10);
|
|
98622
98694
|
const pane = {
|
|
98623
98695
|
id: paneId,
|
|
98624
98696
|
windowId,
|
|
98625
|
-
index
|
|
98697
|
+
index,
|
|
98626
98698
|
title: this.pendingPaneTitles.get(paneId) ?? (titleRaw?.trim() ? titleRaw : undefined),
|
|
98627
98699
|
currentCommand: currentCommandRaw?.trim() ? currentCommandRaw.trim() : undefined,
|
|
98628
98700
|
active: activeRaw === "1",
|
|
98629
|
-
width
|
|
98630
|
-
height
|
|
98701
|
+
width,
|
|
98702
|
+
height
|
|
98631
98703
|
};
|
|
98632
98704
|
if (pane.active && windowActiveRaw === "1") {
|
|
98633
98705
|
this.activePaneId = paneId;
|
|
@@ -98644,6 +98716,23 @@ ${panesRes.stderr}`;
|
|
|
98644
98716
|
window2.panes.sort((left, right) => left.index - right.index);
|
|
98645
98717
|
}
|
|
98646
98718
|
}
|
|
98719
|
+
isSnapshotFlag(value) {
|
|
98720
|
+
return value === "0" || value === "1";
|
|
98721
|
+
}
|
|
98722
|
+
discardInvalidSnapshot() {
|
|
98723
|
+
if (!this.snapshotSession) {
|
|
98724
|
+
this.snapshotWindows.clear();
|
|
98725
|
+
this.activeWindowId = null;
|
|
98726
|
+
this.activePaneId = null;
|
|
98727
|
+
return;
|
|
98728
|
+
}
|
|
98729
|
+
if (this.snapshotWindows.size === 0) {
|
|
98730
|
+
console.warn(`[ssh] ignoring tmux snapshot with no valid windows on ${this.deviceId}`);
|
|
98731
|
+
this.snapshotSession = null;
|
|
98732
|
+
this.activeWindowId = null;
|
|
98733
|
+
this.activePaneId = null;
|
|
98734
|
+
}
|
|
98735
|
+
}
|
|
98647
98736
|
emitSnapshot() {
|
|
98648
98737
|
const session = this.snapshotSession ? {
|
|
98649
98738
|
id: this.snapshotSession.id,
|
|
@@ -98704,6 +98793,7 @@ ${panesRes.stderr}`;
|
|
|
98704
98793
|
this.recoverFromTargetMissingError(message);
|
|
98705
98794
|
return result;
|
|
98706
98795
|
}
|
|
98796
|
+
console.warn(`[ssh] tmux command failed deviceId=${this.deviceId} sessionName=${this.sessionName} argv=${argv.join(" ")} exitCode=${result.exitCode}: ${message}`);
|
|
98707
98797
|
updateDeviceRuntimeStatus(this.deviceId, {
|
|
98708
98798
|
lastSeenAt: new Date().toISOString(),
|
|
98709
98799
|
tmuxAvailable: false,
|
|
@@ -105573,17 +105663,15 @@ class WebSocketServer {
|
|
|
105573
105663
|
}
|
|
105574
105664
|
handleTmuxSelect(ws, data) {
|
|
105575
105665
|
const deviceId = data.deviceId;
|
|
105576
|
-
const paneId = data.paneId ?? undefined;
|
|
105577
|
-
if (paneId) {
|
|
105578
|
-
ws.data.borshState.selectedPanes[deviceId] = paneId;
|
|
105579
|
-
this.refreshSnapshotPolling(deviceId);
|
|
105580
|
-
}
|
|
105581
105666
|
const entry = this.connections.get(deviceId);
|
|
105582
105667
|
if (!entry)
|
|
105583
105668
|
return;
|
|
105584
105669
|
const windowId = data.windowId ?? undefined;
|
|
105670
|
+
const paneId = data.paneId ?? undefined;
|
|
105585
105671
|
if (!windowId || !paneId)
|
|
105586
105672
|
return;
|
|
105673
|
+
if (!this.canSelectPane(entry, deviceId, windowId, paneId))
|
|
105674
|
+
return;
|
|
105587
105675
|
const started = switchBarrier.startTransaction(ws, {
|
|
105588
105676
|
deviceId,
|
|
105589
105677
|
windowId,
|
|
@@ -105597,6 +105685,8 @@ class WebSocketServer {
|
|
|
105597
105685
|
this.sendError(ws, null, exports_ws_borsh.ERROR_SELECT_CONFLICT, "Failed to start select transaction", false);
|
|
105598
105686
|
return;
|
|
105599
105687
|
}
|
|
105688
|
+
ws.data.borshState.selectedPanes[deviceId] = paneId;
|
|
105689
|
+
this.refreshSnapshotPolling(deviceId);
|
|
105600
105690
|
switchBarrier.sendSwitchAck(ws, deviceId);
|
|
105601
105691
|
const cols = data.cols ?? null;
|
|
105602
105692
|
const rows = data.rows ?? null;
|
|
@@ -105610,8 +105700,41 @@ class WebSocketServer {
|
|
|
105610
105700
|
const entry = this.connections.get(deviceId);
|
|
105611
105701
|
if (!entry)
|
|
105612
105702
|
return;
|
|
105703
|
+
if (!this.canSelectWindow(entry, deviceId, windowId))
|
|
105704
|
+
return;
|
|
105613
105705
|
entry.runtime.selectWindow(windowId);
|
|
105614
105706
|
}
|
|
105707
|
+
canSelectWindow(entry, deviceId, windowId) {
|
|
105708
|
+
if (!isTmuxWindowId(windowId)) {
|
|
105709
|
+
console.warn(`[ws] rejecting invalid tmux window id on ${deviceId}: ${windowId ?? ""}`);
|
|
105710
|
+
entry.runtime.requestSnapshot();
|
|
105711
|
+
return false;
|
|
105712
|
+
}
|
|
105713
|
+
const windows = entry.lastSnapshot?.session?.windows;
|
|
105714
|
+
if (!windows?.some((window2) => window2.id === windowId)) {
|
|
105715
|
+
console.warn(`[ws] rejecting missing tmux window id on ${deviceId}: ${windowId}`);
|
|
105716
|
+
entry.runtime.requestSnapshot();
|
|
105717
|
+
return false;
|
|
105718
|
+
}
|
|
105719
|
+
return true;
|
|
105720
|
+
}
|
|
105721
|
+
canSelectPane(entry, deviceId, windowId, paneId) {
|
|
105722
|
+
if (!this.canSelectWindow(entry, deviceId, windowId)) {
|
|
105723
|
+
return false;
|
|
105724
|
+
}
|
|
105725
|
+
if (!isTmuxPaneId(paneId)) {
|
|
105726
|
+
console.warn(`[ws] rejecting invalid tmux pane id on ${deviceId}: ${paneId ?? ""}`);
|
|
105727
|
+
entry.runtime.requestSnapshot();
|
|
105728
|
+
return false;
|
|
105729
|
+
}
|
|
105730
|
+
const window2 = entry.lastSnapshot?.session?.windows.find((candidate) => candidate.id === windowId);
|
|
105731
|
+
if (!window2?.panes.some((pane) => pane.id === paneId)) {
|
|
105732
|
+
console.warn(`[ws] rejecting missing tmux pane id on ${deviceId}: ${paneId}`);
|
|
105733
|
+
entry.runtime.requestSnapshot();
|
|
105734
|
+
return false;
|
|
105735
|
+
}
|
|
105736
|
+
return true;
|
|
105737
|
+
}
|
|
105615
105738
|
handleTermInput(deviceId, paneId, data) {
|
|
105616
105739
|
const entry = this.connections.get(deviceId);
|
|
105617
105740
|
if (!entry)
|
|
Binary file
|