tmex-cli 0.4.3 → 0.4.5
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/dist/runtime/server.js +139 -7
- package/package.json +1 -1
- package/resources/fe-dist/assets/{DevicePage-B9rZioAr.js → DevicePage-Di11uzbS.js} +8 -8
- package/resources/fe-dist/assets/{DevicePage-B9rZioAr.js.map → DevicePage-Di11uzbS.js.map} +1 -1
- package/resources/fe-dist/assets/{DevicesPage-Bco831ry.js → DevicesPage-dj7Pel6f.js} +2 -2
- package/resources/fe-dist/assets/{DevicesPage-Bco831ry.js.map → DevicesPage-dj7Pel6f.js.map} +1 -1
- package/resources/fe-dist/assets/{SettingsPage-BRs8Unfx.js → SettingsPage-DwpbDA_e.js} +2 -2
- package/resources/fe-dist/assets/{SettingsPage-BRs8Unfx.js.map → SettingsPage-DwpbDA_e.js.map} +1 -1
- package/resources/fe-dist/assets/{index-BhBqXsZI.js → index-61hq_aNX.js} +3 -3
- package/resources/fe-dist/assets/{index-BhBqXsZI.js.map → index-61hq_aNX.js.map} +1 -1
- package/resources/fe-dist/assets/{select-D70hG6p7.js → select-DI4HQZd4.js} +2 -2
- package/resources/fe-dist/assets/{select-D70hG6p7.js.map → select-DI4HQZd4.js.map} +1 -1
- package/resources/fe-dist/assets/{switch-DsyIGzyC.js → switch-DsfDIUrU.js} +2 -2
- package/resources/fe-dist/assets/{switch-DsyIGzyC.js.map → switch-DsfDIUrU.js.map} +1 -1
- package/resources/fe-dist/assets/{useValueChanged-CBb-JR7o.js → useValueChanged-AVaPYvln.js} +2 -2
- package/resources/fe-dist/assets/{useValueChanged-CBb-JR7o.js.map → useValueChanged-AVaPYvln.js.map} +1 -1
- package/resources/fe-dist/index.html +1 -1
package/dist/runtime/server.js
CHANGED
|
@@ -52814,6 +52814,8 @@ class LocalExternalTmuxConnection {
|
|
|
52814
52814
|
hookReadAbort = null;
|
|
52815
52815
|
hookBuffer = "";
|
|
52816
52816
|
bellDedup = new Map;
|
|
52817
|
+
closeNotified = false;
|
|
52818
|
+
cleanupPromise = null;
|
|
52817
52819
|
fsPaths = createRuntimeFsPaths({
|
|
52818
52820
|
deviceId: "pending",
|
|
52819
52821
|
sessionName: "pending",
|
|
@@ -52830,6 +52832,7 @@ class LocalExternalTmuxConnection {
|
|
|
52830
52832
|
}
|
|
52831
52833
|
async connect() {
|
|
52832
52834
|
this.manualDisconnect = false;
|
|
52835
|
+
this.closeNotified = false;
|
|
52833
52836
|
this.device = this.deps.getDevice(this.deviceId);
|
|
52834
52837
|
if (!this.device) {
|
|
52835
52838
|
throw new Error(`Device not found: ${this.deviceId}`);
|
|
@@ -52853,7 +52856,8 @@ class LocalExternalTmuxConnection {
|
|
|
52853
52856
|
updateDeviceRuntimeStatus(this.deviceId, {
|
|
52854
52857
|
lastSeenAt: new Date().toISOString(),
|
|
52855
52858
|
tmuxAvailable: true,
|
|
52856
|
-
lastError: null
|
|
52859
|
+
lastError: null,
|
|
52860
|
+
lastErrorType: null
|
|
52857
52861
|
});
|
|
52858
52862
|
await this.requestSnapshotInternal();
|
|
52859
52863
|
}
|
|
@@ -53137,6 +53141,20 @@ class LocalExternalTmuxConnection {
|
|
|
53137
53141
|
])
|
|
53138
53142
|
]);
|
|
53139
53143
|
if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
|
|
53144
|
+
const stderrBlob = `${sessionRes.stderr}
|
|
53145
|
+
${windowsRes.stderr}
|
|
53146
|
+
${panesRes.stderr}`;
|
|
53147
|
+
if (this.connected && !this.manualDisconnect && this.isTmuxServerGoneMessage(stderrBlob)) {
|
|
53148
|
+
const message = stderrBlob.trim().split(/\r?\n/).find((line) => line.trim())?.trim() ?? "tmux server gone";
|
|
53149
|
+
console.warn(`[local] tmux server gone during snapshot on ${this.deviceId}: ${message}`);
|
|
53150
|
+
updateDeviceRuntimeStatus(this.deviceId, {
|
|
53151
|
+
lastSeenAt: new Date().toISOString(),
|
|
53152
|
+
tmuxAvailable: false,
|
|
53153
|
+
lastError: message
|
|
53154
|
+
});
|
|
53155
|
+
this.shutdownInternal(true);
|
|
53156
|
+
return;
|
|
53157
|
+
}
|
|
53140
53158
|
this.callbacks.onSnapshot({ deviceId: this.deviceId, session: null });
|
|
53141
53159
|
return;
|
|
53142
53160
|
}
|
|
@@ -53382,6 +53400,10 @@ class LocalExternalTmuxConnection {
|
|
|
53382
53400
|
return result;
|
|
53383
53401
|
}
|
|
53384
53402
|
this.notifyRuntimeError(message);
|
|
53403
|
+
if (this.connected && !this.manualDisconnect && this.isTmuxServerGoneMessage(message)) {
|
|
53404
|
+
console.warn(`[local] tmux server gone on ${this.deviceId}: ${message}`);
|
|
53405
|
+
this.shutdownInternal(true);
|
|
53406
|
+
}
|
|
53385
53407
|
throw new Error(message);
|
|
53386
53408
|
}
|
|
53387
53409
|
async notifyRuntimeError(message) {
|
|
@@ -53408,6 +53430,40 @@ class LocalExternalTmuxConnection {
|
|
|
53408
53430
|
const normalized = message.toLowerCase();
|
|
53409
53431
|
return normalized.includes("can't find window") || normalized.includes("can't find pane") || normalized.includes("no such window") || normalized.includes("no such pane");
|
|
53410
53432
|
}
|
|
53433
|
+
isTmuxServerGoneMessage(message) {
|
|
53434
|
+
const normalized = message.toLowerCase();
|
|
53435
|
+
return normalized.includes("no server running on") || normalized.includes("no sessions") || normalized.includes("lost server") || normalized.includes("can't find session") || normalized.includes("session not found") || normalized.includes("no such session");
|
|
53436
|
+
}
|
|
53437
|
+
async shutdownInternal(notifyClose) {
|
|
53438
|
+
if (this.cleanupPromise) {
|
|
53439
|
+
await this.cleanupPromise;
|
|
53440
|
+
if (notifyClose && !this.closeNotified && !this.manualDisconnect) {
|
|
53441
|
+
this.closeNotified = true;
|
|
53442
|
+
this.callbacks.onClose();
|
|
53443
|
+
}
|
|
53444
|
+
return;
|
|
53445
|
+
}
|
|
53446
|
+
this.connected = false;
|
|
53447
|
+
this.cleanupPromise = (async () => {
|
|
53448
|
+
await this.stopAllPipeReaders().catch(() => {
|
|
53449
|
+
return;
|
|
53450
|
+
});
|
|
53451
|
+
if (this.deps.enableHooks) {
|
|
53452
|
+
await this.stopHooks().catch(() => {
|
|
53453
|
+
return;
|
|
53454
|
+
});
|
|
53455
|
+
}
|
|
53456
|
+
try {
|
|
53457
|
+
rmSync(this.fsPaths.rootDir, { recursive: true, force: true });
|
|
53458
|
+
} catch {}
|
|
53459
|
+
})();
|
|
53460
|
+
await this.cleanupPromise;
|
|
53461
|
+
this.cleanupPromise = null;
|
|
53462
|
+
if (notifyClose && !this.closeNotified && !this.manualDisconnect) {
|
|
53463
|
+
this.closeNotified = true;
|
|
53464
|
+
this.callbacks.onClose();
|
|
53465
|
+
}
|
|
53466
|
+
}
|
|
53411
53467
|
recoverFromTargetMissingError(message) {
|
|
53412
53468
|
const normalized = message.toLowerCase();
|
|
53413
53469
|
if (normalized.includes("window")) {
|
|
@@ -53560,6 +53616,16 @@ function resolvePrivateKeyFromConfig(identityFiles, deps) {
|
|
|
53560
53616
|
}
|
|
53561
53617
|
return;
|
|
53562
53618
|
}
|
|
53619
|
+
function resolvePrivateKeysFromConfig(identityFiles, deps) {
|
|
53620
|
+
const privateKeys = [];
|
|
53621
|
+
for (const identityFile of identityFiles) {
|
|
53622
|
+
if (!deps.fileExists(identityFile)) {
|
|
53623
|
+
continue;
|
|
53624
|
+
}
|
|
53625
|
+
privateKeys.push(deps.readTextFile(identityFile));
|
|
53626
|
+
}
|
|
53627
|
+
return privateKeys;
|
|
53628
|
+
}
|
|
53563
53629
|
function resolveSshConfigRef(device, deps) {
|
|
53564
53630
|
const ref = device.sshConfigRef?.trim();
|
|
53565
53631
|
if (!ref) {
|
|
@@ -53572,6 +53638,21 @@ function resolveSshConfigRef(device, deps) {
|
|
|
53572
53638
|
}
|
|
53573
53639
|
return parseSshConfigOutput(result.stdout, deps.env);
|
|
53574
53640
|
}
|
|
53641
|
+
function resolveImplicitIdentityFilesForAgentAuth(device, host, port, username, deps) {
|
|
53642
|
+
if (device.authMode !== "agent" || device.sshConfigRef?.trim()) {
|
|
53643
|
+
return [];
|
|
53644
|
+
}
|
|
53645
|
+
const target = username ? `${username}@${host}` : host;
|
|
53646
|
+
try {
|
|
53647
|
+
const result = deps.runSync(["ssh", "-G", "-p", String(port), target]);
|
|
53648
|
+
if (result.exitCode !== 0) {
|
|
53649
|
+
return [];
|
|
53650
|
+
}
|
|
53651
|
+
return parseSshConfigOutput(result.stdout, deps.env).identityFiles;
|
|
53652
|
+
} catch {
|
|
53653
|
+
return [];
|
|
53654
|
+
}
|
|
53655
|
+
}
|
|
53575
53656
|
async function resolveSshConnectConfig(device, decrypt2, inputDeps = {}) {
|
|
53576
53657
|
const deps = {
|
|
53577
53658
|
env: inputDeps.env ?? process.env,
|
|
@@ -53595,6 +53676,7 @@ async function resolveSshConnectConfig(device, decrypt2, inputDeps = {}) {
|
|
|
53595
53676
|
const configAgent = resolveAgentFromConfig(resolvedConfig?.identityAgent, deps);
|
|
53596
53677
|
const envAgent = resolveSshAgentSocket("auto", sshEnv);
|
|
53597
53678
|
const configPrivateKey = resolvePrivateKeyFromConfig(resolvedConfig?.identityFiles ?? [], deps);
|
|
53679
|
+
const implicitAgentFallbackPrivateKeys = resolvePrivateKeysFromConfig(resolveImplicitIdentityFilesForAgentAuth(device, host, port, username, deps), deps);
|
|
53598
53680
|
switch (device.authMode) {
|
|
53599
53681
|
case "password": {
|
|
53600
53682
|
if (!device.passwordEnc) {
|
|
@@ -53626,7 +53708,24 @@ async function resolveSshConnectConfig(device, decrypt2, inputDeps = {}) {
|
|
|
53626
53708
|
break;
|
|
53627
53709
|
}
|
|
53628
53710
|
case "agent": {
|
|
53629
|
-
|
|
53711
|
+
const agent = configAgent ?? resolveSshAgentSocket("agent", sshEnv);
|
|
53712
|
+
authConfig.agent = agent;
|
|
53713
|
+
if (implicitAgentFallbackPrivateKeys.length > 0) {
|
|
53714
|
+
const publicKeyFallbacks = implicitAgentFallbackPrivateKeys.map((key) => ({
|
|
53715
|
+
type: "publickey",
|
|
53716
|
+
username,
|
|
53717
|
+
key
|
|
53718
|
+
}));
|
|
53719
|
+
const authHandler = [
|
|
53720
|
+
{
|
|
53721
|
+
type: "agent",
|
|
53722
|
+
username,
|
|
53723
|
+
agent
|
|
53724
|
+
},
|
|
53725
|
+
...publicKeyFallbacks
|
|
53726
|
+
];
|
|
53727
|
+
authConfig.authHandler = authHandler;
|
|
53728
|
+
}
|
|
53630
53729
|
break;
|
|
53631
53730
|
}
|
|
53632
53731
|
case "configRef": {
|
|
@@ -53810,7 +53909,8 @@ class SshExternalTmuxConnection {
|
|
|
53810
53909
|
updateDeviceRuntimeStatus(this.deviceId, {
|
|
53811
53910
|
lastSeenAt: new Date().toISOString(),
|
|
53812
53911
|
tmuxAvailable: true,
|
|
53813
|
-
lastError: null
|
|
53912
|
+
lastError: null,
|
|
53913
|
+
lastErrorType: null
|
|
53814
53914
|
});
|
|
53815
53915
|
await this.requestSnapshotInternal();
|
|
53816
53916
|
}
|
|
@@ -54042,9 +54142,11 @@ class SshExternalTmuxConnection {
|
|
|
54042
54142
|
this.handleHookChunk(data.toString());
|
|
54043
54143
|
},
|
|
54044
54144
|
onClose: () => {
|
|
54045
|
-
if (
|
|
54046
|
-
|
|
54145
|
+
if (this.manualDisconnect) {
|
|
54146
|
+
return;
|
|
54047
54147
|
}
|
|
54148
|
+
console.error("[ssh] hook reader channel closed unexpectedly, tearing down");
|
|
54149
|
+
this.shutdownInternal(true);
|
|
54048
54150
|
}
|
|
54049
54151
|
});
|
|
54050
54152
|
this.hookReadAbort = () => {
|
|
@@ -54172,6 +54274,20 @@ class SshExternalTmuxConnection {
|
|
|
54172
54274
|
])
|
|
54173
54275
|
]);
|
|
54174
54276
|
if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
|
|
54277
|
+
const stderrBlob = `${sessionRes.stderr}
|
|
54278
|
+
${windowsRes.stderr}
|
|
54279
|
+
${panesRes.stderr}`;
|
|
54280
|
+
if (this.connected && !this.manualDisconnect && this.isTmuxServerGoneMessage(stderrBlob)) {
|
|
54281
|
+
const message = stderrBlob.trim().split(/\r?\n/).find((line) => line.trim())?.trim() ?? "tmux server gone";
|
|
54282
|
+
console.warn(`[ssh] tmux server gone during snapshot on ${this.deviceId}: ${message}`);
|
|
54283
|
+
updateDeviceRuntimeStatus(this.deviceId, {
|
|
54284
|
+
lastSeenAt: new Date().toISOString(),
|
|
54285
|
+
tmuxAvailable: false,
|
|
54286
|
+
lastError: message
|
|
54287
|
+
});
|
|
54288
|
+
this.shutdownInternal(true);
|
|
54289
|
+
return;
|
|
54290
|
+
}
|
|
54175
54291
|
this.callbacks.onSnapshot({ deviceId: this.deviceId, session: null });
|
|
54176
54292
|
return;
|
|
54177
54293
|
}
|
|
@@ -54331,9 +54447,17 @@ class SshExternalTmuxConnection {
|
|
|
54331
54447
|
}
|
|
54332
54448
|
},
|
|
54333
54449
|
onClose: () => {
|
|
54334
|
-
if (
|
|
54335
|
-
|
|
54450
|
+
if (this.manualDisconnect) {
|
|
54451
|
+
return;
|
|
54452
|
+
}
|
|
54453
|
+
const existing = this.paneReaders.get(paneId);
|
|
54454
|
+
if (!existing) {
|
|
54455
|
+
return;
|
|
54336
54456
|
}
|
|
54457
|
+
console.warn(`[ssh] pane reader channel closed for ${paneId}, resync on next snapshot`);
|
|
54458
|
+
this.paneReaders.delete(paneId);
|
|
54459
|
+
this.runShellAllowFailure(`rm -f ${quoteShellArg(existing.fifoPath)}`);
|
|
54460
|
+
this.requestSnapshot();
|
|
54337
54461
|
}
|
|
54338
54462
|
});
|
|
54339
54463
|
const handle = {
|
|
@@ -54409,6 +54533,10 @@ class SshExternalTmuxConnection {
|
|
|
54409
54533
|
tmuxAvailable: false,
|
|
54410
54534
|
lastError: message
|
|
54411
54535
|
});
|
|
54536
|
+
if (this.connected && !this.manualDisconnect && this.isTmuxServerGoneMessage(message)) {
|
|
54537
|
+
console.warn(`[ssh] tmux server gone on ${this.deviceId}: ${message}`);
|
|
54538
|
+
this.shutdownInternal(true);
|
|
54539
|
+
}
|
|
54412
54540
|
throw new Error(message);
|
|
54413
54541
|
}
|
|
54414
54542
|
async runTmuxAllowFailure(argv, timeoutMs = 1e4) {
|
|
@@ -54536,6 +54664,10 @@ printf '\\036TMEX_END %s %d\\036\\n' ${quoteShellArg(commandId)} $?
|
|
|
54536
54664
|
const normalized = message.toLowerCase();
|
|
54537
54665
|
return normalized.includes("can't find window") || normalized.includes("can't find pane") || normalized.includes("no such window") || normalized.includes("no such pane");
|
|
54538
54666
|
}
|
|
54667
|
+
isTmuxServerGoneMessage(message) {
|
|
54668
|
+
const normalized = message.toLowerCase();
|
|
54669
|
+
return normalized.includes("no server running on") || normalized.includes("no sessions") || normalized.includes("lost server") || normalized.includes("can't find session") || normalized.includes("session not found") || normalized.includes("no such session");
|
|
54670
|
+
}
|
|
54539
54671
|
recoverFromTargetMissingError(message) {
|
|
54540
54672
|
const normalized = message.toLowerCase();
|
|
54541
54673
|
if (normalized.includes("window")) {
|