tmex-cli 0.14.0 → 0.15.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.
- package/CHANGELOG.md +6 -28
- package/dist/runtime/server.js +158 -14
- package/package.json +1 -1
- package/resources/fe-dist/assets/{DevicePage-Ctq31eWb.js → DevicePage--HOY0kN6.js} +1 -1
- package/resources/fe-dist/assets/{DevicesPage-DGo44NW0.js → DevicesPage-Ngrej5Ot.js} +1 -1
- package/resources/fe-dist/assets/{FilePage-BpubOqjN.js → FilePage-HbiQHaa9.js} +1 -1
- package/resources/fe-dist/assets/{SettingsPage-QT6fy6XA.js → SettingsPage-CPdwRwyS.js} +1 -1
- package/resources/fe-dist/assets/{agent-tab-A2FeMPwL.js → agent-tab--8AsTl-t.js} +1 -1
- package/resources/fe-dist/assets/{api-CGfOwFKm.js → api-BLIQkwae.js} +1 -1
- package/resources/fe-dist/assets/{arc-B2dphCVi.js → arc-BxPdcU4u.js} +1 -1
- package/resources/fe-dist/assets/{architectureDiagram-3BPJPVTR-BpvEhd8M.js → architectureDiagram-3BPJPVTR-BTgMKoOk.js} +1 -1
- package/resources/fe-dist/assets/{blockDiagram-GPEHLZMM-CI_NnIJz.js → blockDiagram-GPEHLZMM-DGbVoBx0.js} +1 -1
- package/resources/fe-dist/assets/{c4Diagram-AAUBKEIU-Y6RrOc7Y.js → c4Diagram-AAUBKEIU-6Xsfbwgs.js} +1 -1
- package/resources/fe-dist/assets/{card-CydUB3N3.js → card-LIHKdO48.js} +1 -1
- package/resources/fe-dist/assets/channel-BGHWdKHN.js +1 -0
- package/resources/fe-dist/assets/{chunk-2J33WTMH-BQN_fYaa.js → chunk-2J33WTMH-gstBqLVO.js} +1 -1
- package/resources/fe-dist/assets/{chunk-4BX2VUAB-BExarxjk.js → chunk-4BX2VUAB-C-o3q6jv.js} +1 -1
- package/resources/fe-dist/assets/{chunk-55IACEB6-DeOEgcn_.js → chunk-55IACEB6-DddgDLxO.js} +1 -1
- package/resources/fe-dist/assets/{chunk-727SXJPM-CwkxCtPA.js → chunk-727SXJPM-CXYmmkMi.js} +1 -1
- package/resources/fe-dist/assets/{chunk-AQP2D5EJ-_IoTtvOb.js → chunk-AQP2D5EJ-DRLECkLk.js} +1 -1
- package/resources/fe-dist/assets/{chunk-FMBD7UC4-6pvmQ3Lj.js → chunk-FMBD7UC4-BExWPgsD.js} +1 -1
- package/resources/fe-dist/assets/{chunk-ND2GUHAM-CxpGf5zM.js → chunk-ND2GUHAM-C7VdaZU9.js} +1 -1
- package/resources/fe-dist/assets/{chunk-QZHKN3VN-DOMH0v_e.js → chunk-QZHKN3VN-BzDQ08zM.js} +1 -1
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-B47Acuru.js +1 -0
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-B47Acuru.js +1 -0
- package/resources/fe-dist/assets/{copy-DnlW35bA.js → copy-BF0hUIaY.js} +1 -1
- package/resources/fe-dist/assets/{cose-bilkent-S5V4N54A-D03NElzH.js → cose-bilkent-S5V4N54A-D6PcYL8a.js} +1 -1
- package/resources/fe-dist/assets/{dagre-BM42HDAG-CVOxLhKQ.js → dagre-BM42HDAG-CRImj5gw.js} +1 -1
- package/resources/fe-dist/assets/{diagram-2AECGRRQ-p564GAo-.js → diagram-2AECGRRQ-rxXesmyb.js} +1 -1
- package/resources/fe-dist/assets/{diagram-5GNKFQAL-C_pgnQLt.js → diagram-5GNKFQAL-1cV1ezU8.js} +1 -1
- package/resources/fe-dist/assets/{diagram-KO2AKTUF-B36jioML.js → diagram-KO2AKTUF-D_t6oZ15.js} +1 -1
- package/resources/fe-dist/assets/{diagram-LMA3HP47-B8P4WWeq.js → diagram-LMA3HP47-Bv2rw6Uu.js} +1 -1
- package/resources/fe-dist/assets/{diagram-OG6HWLK6-CTL4zJlz.js → diagram-OG6HWLK6-CDr2E2aw.js} +1 -1
- package/resources/fe-dist/assets/{en_US-DRPd4vPi.js → en_US-Chxeay8F.js} +1 -1
- package/resources/fe-dist/assets/{erDiagram-TEJ5UH35-DbKPL3Fa.js → erDiagram-TEJ5UH35-Dji-ptHQ.js} +1 -1
- package/resources/fe-dist/assets/{files-tab-CeUM00x8.js → files-tab-BW0vpgW7.js} +1 -1
- package/resources/fe-dist/assets/{flowDiagram-I6XJVG4X-DvOU6wtN.js → flowDiagram-I6XJVG4X-CeBLfMwm.js} +1 -1
- package/resources/fe-dist/assets/{ganttDiagram-6RSMTGT7-CwgNky8L.js → ganttDiagram-6RSMTGT7-C0W5vjVi.js} +1 -1
- package/resources/fe-dist/assets/{gitGraphDiagram-PVQCEYII-B3U-hNGe.js → gitGraphDiagram-PVQCEYII-1BOW9mBR.js} +1 -1
- package/resources/fe-dist/assets/{index-DAElYydw.js → index-B3aiK6xC.js} +79 -79
- package/resources/fe-dist/assets/{index-DBHh6Xu1.js → index-BbHTMCQt.js} +1 -1
- package/resources/fe-dist/assets/index-CHeveVji.css +1 -0
- package/resources/fe-dist/assets/{infoDiagram-5YYISTIA-BmcWF7v1.js → infoDiagram-5YYISTIA-rY2E1Qtb.js} +1 -1
- package/resources/fe-dist/assets/{ishikawaDiagram-YF4QCWOH-Dr8C0MtS.js → ishikawaDiagram-YF4QCWOH-bISKs9QA.js} +1 -1
- package/resources/fe-dist/assets/{ja_JP-DHREHMZZ.js → ja_JP-BI-C8I9X.js} +1 -1
- package/resources/fe-dist/assets/{journeyDiagram-JHISSGLW-DzlvXb4K.js → journeyDiagram-JHISSGLW-D5V6twg8.js} +1 -1
- package/resources/fe-dist/assets/{kanban-definition-UN3LZRKU-4aBWZlcm.js → kanban-definition-UN3LZRKU-DqOygrx5.js} +1 -1
- package/resources/fe-dist/assets/{linear-_wXLepjd.js → linear-CvBar11D.js} +1 -1
- package/resources/fe-dist/assets/{markdown-preview-BX0o83rG.js → markdown-preview-sViGxElv.js} +3 -3
- package/resources/fe-dist/assets/{mermaid.core-DoE3dx_X.js → mermaid.core-m9JEGou3.js} +5 -5
- package/resources/fe-dist/assets/{mindmap-definition-RKZ34NQL-CKpq2s43.js → mindmap-definition-RKZ34NQL-DMyUzSwg.js} +1 -1
- package/resources/fe-dist/assets/{pieDiagram-4H26LBE5-DlW1TLza.js → pieDiagram-4H26LBE5-Cp3KArEr.js} +1 -1
- package/resources/fe-dist/assets/{quadrantDiagram-W4KKPZXB-NEwxpMVe.js → quadrantDiagram-W4KKPZXB-B7aVg4vb.js} +1 -1
- package/resources/fe-dist/assets/{requirementDiagram-4Y6WPE33-CGysr6uH.js → requirementDiagram-4Y6WPE33-WDLGaUPr.js} +1 -1
- package/resources/fe-dist/assets/{sankeyDiagram-5OEKKPKP-j8yXOgys.js → sankeyDiagram-5OEKKPKP-AElPZwq5.js} +1 -1
- package/resources/fe-dist/assets/{send-BtOPYsPT.js → send-DjlZMim3.js} +1 -1
- package/resources/fe-dist/assets/{sequenceDiagram-3UESZ5HK-BRPWK9ZU.js → sequenceDiagram-3UESZ5HK-CUYki1W3.js} +1 -1
- package/resources/fe-dist/assets/{stateDiagram-AJRCARHV-C8ckQlA7.js → stateDiagram-AJRCARHV-BlImbgYm.js} +1 -1
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-CzqYErp9.js +1 -0
- package/resources/fe-dist/assets/{terminal-settings-panel-ZnL_cBER.js → terminal-settings-panel-DCm6ZfTX.js} +1 -1
- package/resources/fe-dist/assets/{timeline-definition-PNZ67QCA-BXMFPa99.js → timeline-definition-PNZ67QCA-DnXXxVyb.js} +1 -1
- package/resources/fe-dist/assets/{transfer-toast-CUkPc73G.js → transfer-toast-BWwT4yFg.js} +1 -1
- package/resources/fe-dist/assets/{triangle-alert-DyM9tU7d.js → triangle-alert-D1TuPKVl.js} +1 -1
- package/resources/fe-dist/assets/{vennDiagram-CIIHVFJN-Bk8oPY9E.js → vennDiagram-CIIHVFJN-BziXMAwl.js} +1 -1
- package/resources/fe-dist/assets/{wardley-L42UT6IY-Bi_GTP2_.js → wardley-L42UT6IY-B6fovAcQ.js} +1 -1
- package/resources/fe-dist/assets/{wardleyDiagram-YWT4CUSO-CaPDmxFM.js → wardleyDiagram-YWT4CUSO-DdAfrCkO.js} +1 -1
- package/resources/fe-dist/assets/{xychartDiagram-2RQKCTM6-EHogasXy.js → xychartDiagram-2RQKCTM6-CWuCpr0w.js} +1 -1
- package/resources/fe-dist/assets/{zap-CBgYyGBV.js → zap-CCdOD6uR.js} +1 -1
- package/resources/fe-dist/assets/{zh_CN-DMEKXuFd.js → zh_CN-DE-BaQ3P.js} +1 -1
- package/resources/fe-dist/index.html +2 -2
- package/resources/fe-dist/assets/channel-Ce3VMo9B.js +0 -1
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-BjK-bnh-.js +0 -1
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-BjK-bnh-.js +0 -1
- package/resources/fe-dist/assets/index-D-q7dOhH.css +0 -1
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-Cm0vyyJy.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,41 +1,19 @@
|
|
|
1
|
-
# 0.
|
|
1
|
+
# 0.15.1
|
|
2
2
|
|
|
3
3
|
_2026-06-29_
|
|
4
4
|
|
|
5
5
|
## English
|
|
6
6
|
|
|
7
|
-
### New
|
|
8
|
-
|
|
9
|
-
- Clipboard support for terminal programs: apps like vim, Claude Code, and other TUI tools can now copy text to your system clipboard via the terminal (OSC 52). A brief toast confirms each copy.
|
|
10
|
-
- Configurable default working directory: set a default path for new terminal windows per device — new windows and panes open there instead of the home directory. Changes take effect immediately without disconnecting.
|
|
11
|
-
- Installer now guides you through installing missing dependencies (tmux, bun) during setup, with distro-specific commands for common Linux distributions.
|
|
12
|
-
|
|
13
7
|
### Improvements
|
|
14
8
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- The installer detects whether systemd is available on Linux before proceeding, instead of failing midway on container or WSL environments without it.
|
|
18
|
-
|
|
19
|
-
### Fixes
|
|
20
|
-
|
|
21
|
-
- Fixed non-ASCII filenames (Chinese, Japanese, Korean, etc.) showing as garbled escape sequences in the file browser on Linux servers.
|
|
9
|
+
- Latency display: raise high-latency threshold to 200 ms, use softer orange color instead of red, fix vertical alignment with adjacent buttons.
|
|
10
|
+
- Reduce heartbeat interval from 15 s to 5 s for more responsive latency updates.
|
|
22
11
|
|
|
23
12
|
---
|
|
24
13
|
|
|
25
14
|
## 中文
|
|
26
15
|
|
|
27
|
-
###
|
|
28
|
-
|
|
29
|
-
- 终端程序剪贴板支持:vim、Claude Code 等 TUI 程序现在可以通过终端直接复制文本到系统剪贴板(OSC 52),复制成功时会显示提示。
|
|
30
|
-
- 可配置默认工作目录:可为每台设备设置新终端窗口的默认路径,新窗口将在该目录下打开而非主目录。修改后立即生效,无需断开连接。
|
|
31
|
-
- 安装器现在会在安装过程中引导用户安装缺失的依赖(tmux、bun),并为常见 Linux 发行版提供专属的安装命令。
|
|
32
|
-
|
|
33
|
-
### 改进
|
|
34
|
-
|
|
35
|
-
- 通知提示现在显示终端名称或正在运行的命令(如"vim"、"make"),而非数字索引,更容易识别是哪个终端触发了提醒。
|
|
36
|
-
- `tmex doctor` 检测到可修复的问题时会提示使用 `tmex doctor --fix`,且 `--fix --no-interactive` 支持完全无人值守的脚本化安装。
|
|
37
|
-
- 安装器在 Linux 上会先检测 systemd 是否可用,在容器或无 systemd 的 WSL 环境中提前给出明确错误,而非中途失败。
|
|
38
|
-
|
|
39
|
-
### 修复
|
|
16
|
+
### 体验优化
|
|
40
17
|
|
|
41
|
-
-
|
|
18
|
+
- 延迟显示:高延迟阈值调整为 200 ms,颜色由红色改为更柔和的橙色,修复与相邻按钮的垂直对齐。
|
|
19
|
+
- 心跳间隔从 15 秒缩短至 5 秒,延迟数值更新更及时。
|
package/dist/runtime/server.js
CHANGED
|
@@ -23122,7 +23122,9 @@ Time: {{time}}`,
|
|
|
23122
23122
|
error: "WebSocket connection error",
|
|
23123
23123
|
checkGateway: "Please check Gateway status",
|
|
23124
23124
|
upgradeFailed: "Upgrade failed",
|
|
23125
|
-
invalidMessage: "Invalid message format"
|
|
23125
|
+
invalidMessage: "Invalid message format",
|
|
23126
|
+
reconnecting: "Reconnecting",
|
|
23127
|
+
reconnect: "Reconnect"
|
|
23126
23128
|
},
|
|
23127
23129
|
wsError: {
|
|
23128
23130
|
checkGateway: "Please check Gateway status"
|
|
@@ -24118,7 +24120,9 @@ Bot\uFF1A{{botName}}
|
|
|
24118
24120
|
error: "WebSocket \u8FDE\u63A5\u9519\u8BEF",
|
|
24119
24121
|
checkGateway: "\u8BF7\u68C0\u67E5 Gateway \u72B6\u6001",
|
|
24120
24122
|
upgradeFailed: "Upgrade failed",
|
|
24121
|
-
invalidMessage: "Invalid message format"
|
|
24123
|
+
invalidMessage: "Invalid message format",
|
|
24124
|
+
reconnecting: "\u91CD\u8FDE\u4E2D",
|
|
24125
|
+
reconnect: "\u91CD\u65B0\u8FDE\u63A5"
|
|
24122
24126
|
},
|
|
24123
24127
|
wsError: {
|
|
24124
24128
|
checkGateway: "\u8BF7\u68C0\u67E5 Gateway \u72B6\u6001"
|
|
@@ -25114,7 +25118,9 @@ Bot\uFF1A{{botName}}
|
|
|
25114
25118
|
error: "WebSocket \u63A5\u7D9A\u30A8\u30E9\u30FC",
|
|
25115
25119
|
checkGateway: "Gateway \u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
25116
25120
|
upgradeFailed: "\u30A2\u30C3\u30D7\u30B0\u30EC\u30FC\u30C9\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
25117
|
-
invalidMessage: "\u7121\u52B9\u306A\u30E1\u30C3\u30BB\u30FC\u30B8\u5F62\u5F0F"
|
|
25121
|
+
invalidMessage: "\u7121\u52B9\u306A\u30E1\u30C3\u30BB\u30FC\u30B8\u5F62\u5F0F",
|
|
25122
|
+
reconnecting: "\u518D\u63A5\u7D9A\u4E2D",
|
|
25123
|
+
reconnect: "\u518D\u63A5\u7D9A"
|
|
25118
25124
|
},
|
|
25119
25125
|
wsError: {
|
|
25120
25126
|
checkGateway: "Gateway \u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
@@ -98613,6 +98619,11 @@ function createControlModeSubscription(callbacks) {
|
|
|
98613
98619
|
if (STRUCTURE_NOTIFICATION_TYPES.has(notification.type)) {
|
|
98614
98620
|
scheduleStructureChanged();
|
|
98615
98621
|
}
|
|
98622
|
+
if (notification.type === "pause") {
|
|
98623
|
+
callbacks.onPause?.(notification.args.trim());
|
|
98624
|
+
} else if (notification.type === "continue") {
|
|
98625
|
+
callbacks.onContinue?.(notification.args.trim());
|
|
98626
|
+
}
|
|
98616
98627
|
}
|
|
98617
98628
|
const parser = createControlModeParser({
|
|
98618
98629
|
onOutput: (paneId, data) => {
|
|
@@ -98888,6 +98899,8 @@ var CONTROL_RESTART_DELAY_MS = 500;
|
|
|
98888
98899
|
var CONTROL_STABLE_RESET_MS = 1e4;
|
|
98889
98900
|
var CONTROL_STDERR_TAIL_LIMIT = 2048;
|
|
98890
98901
|
var CONTROL_ATTACH_READY_TIMEOUT_MS = 3000;
|
|
98902
|
+
var HEARTBEAT_INTERVAL_MS = 30000;
|
|
98903
|
+
var HEARTBEAT_TIMEOUT_MS = 1e4;
|
|
98891
98904
|
var PARKING_WINDOW_NAME = "tmex-park";
|
|
98892
98905
|
function hasRenderableTerminalContent(value) {
|
|
98893
98906
|
return value.trim().length > 0;
|
|
@@ -98946,6 +98959,11 @@ function defaultSpawnControlClient(argv) {
|
|
|
98946
98959
|
stdin?.end();
|
|
98947
98960
|
} catch {}
|
|
98948
98961
|
subprocess.kill();
|
|
98962
|
+
},
|
|
98963
|
+
write: (data) => {
|
|
98964
|
+
try {
|
|
98965
|
+
stdin?.write(data);
|
|
98966
|
+
} catch {}
|
|
98949
98967
|
}
|
|
98950
98968
|
};
|
|
98951
98969
|
}
|
|
@@ -98973,6 +98991,9 @@ class LocalExternalTmuxConnection {
|
|
|
98973
98991
|
controlRestartCount = 0;
|
|
98974
98992
|
controlStderrTail = "";
|
|
98975
98993
|
spawnUnavailableNotified = false;
|
|
98994
|
+
heartbeatTimer = null;
|
|
98995
|
+
heartbeatPending = false;
|
|
98996
|
+
heartbeatTimeoutTimer = null;
|
|
98976
98997
|
constructor(options, inputDeps = {}) {
|
|
98977
98998
|
this.deviceId = options.deviceId;
|
|
98978
98999
|
this.callbacks = options;
|
|
@@ -99305,6 +99326,7 @@ class LocalExternalTmuxConnection {
|
|
|
99305
99326
|
await this.runTmuxAllowFailure(["kill-window", "-t", windowId]);
|
|
99306
99327
|
}
|
|
99307
99328
|
async startControlClient() {
|
|
99329
|
+
this.stopHeartbeat();
|
|
99308
99330
|
let attachReadyResolve = null;
|
|
99309
99331
|
const attachReady = new Promise((resolve3) => {
|
|
99310
99332
|
attachReadyResolve = resolve3;
|
|
@@ -99328,6 +99350,7 @@ class LocalExternalTmuxConnection {
|
|
|
99328
99350
|
console.warn(`[local] tmux control client died during attach on ${this.deviceId}: ${message}`);
|
|
99329
99351
|
throw new Error(message);
|
|
99330
99352
|
}
|
|
99353
|
+
this.startHeartbeat();
|
|
99331
99354
|
}
|
|
99332
99355
|
spawnControlClientProcess(onAttachReady) {
|
|
99333
99356
|
const subscription = createControlModeSubscription({
|
|
@@ -99353,9 +99376,16 @@ class LocalExternalTmuxConnection {
|
|
|
99353
99376
|
onStructureChanged: () => {
|
|
99354
99377
|
this.requestSnapshot();
|
|
99355
99378
|
},
|
|
99379
|
+
onPause: (paneId) => {
|
|
99380
|
+
this.controlProcess?.write("refresh-client -A " + paneId + `:continue
|
|
99381
|
+
`);
|
|
99382
|
+
},
|
|
99356
99383
|
onExit: () => {},
|
|
99357
|
-
onBlockEnd: () => {
|
|
99384
|
+
onBlockEnd: (block) => {
|
|
99358
99385
|
onAttachReady();
|
|
99386
|
+
if (!block.isError && block.lines.length === 1 && block.lines[0] === "tmex-hb") {
|
|
99387
|
+
this.onHeartbeatResponse();
|
|
99388
|
+
}
|
|
99359
99389
|
}
|
|
99360
99390
|
});
|
|
99361
99391
|
const proc = this.deps.spawnControlClient([
|
|
@@ -99395,6 +99425,10 @@ class LocalExternalTmuxConnection {
|
|
|
99395
99425
|
}
|
|
99396
99426
|
}
|
|
99397
99427
|
subscription.end();
|
|
99428
|
+
if (this.controlProcess === proc) {
|
|
99429
|
+
console.warn("[local] control client stdout ended unexpectedly on " + this.deviceId + ", killing process");
|
|
99430
|
+
proc.kill();
|
|
99431
|
+
}
|
|
99398
99432
|
}
|
|
99399
99433
|
async pumpControlStderr(proc) {
|
|
99400
99434
|
const reader = proc.stderr.getReader();
|
|
@@ -99412,12 +99446,55 @@ class LocalExternalTmuxConnection {
|
|
|
99412
99446
|
} catch {}
|
|
99413
99447
|
}
|
|
99414
99448
|
stopControlClient() {
|
|
99449
|
+
this.stopHeartbeat();
|
|
99415
99450
|
const proc = this.controlProcess;
|
|
99416
99451
|
this.controlProcess = null;
|
|
99417
99452
|
this.controlSubscription?.dispose();
|
|
99418
99453
|
this.controlSubscription = null;
|
|
99419
99454
|
proc?.kill();
|
|
99420
99455
|
}
|
|
99456
|
+
startHeartbeat() {
|
|
99457
|
+
this.stopHeartbeat();
|
|
99458
|
+
this.heartbeatTimer = setInterval(() => {
|
|
99459
|
+
this.sendHeartbeat();
|
|
99460
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
99461
|
+
}
|
|
99462
|
+
stopHeartbeat() {
|
|
99463
|
+
if (this.heartbeatTimer) {
|
|
99464
|
+
clearInterval(this.heartbeatTimer);
|
|
99465
|
+
this.heartbeatTimer = null;
|
|
99466
|
+
}
|
|
99467
|
+
if (this.heartbeatTimeoutTimer) {
|
|
99468
|
+
clearTimeout(this.heartbeatTimeoutTimer);
|
|
99469
|
+
this.heartbeatTimeoutTimer = null;
|
|
99470
|
+
}
|
|
99471
|
+
this.heartbeatPending = false;
|
|
99472
|
+
}
|
|
99473
|
+
sendHeartbeat() {
|
|
99474
|
+
if (!this.controlProcess || this.heartbeatPending || !this.connected || this.manualDisconnect) {
|
|
99475
|
+
return;
|
|
99476
|
+
}
|
|
99477
|
+
this.heartbeatPending = true;
|
|
99478
|
+
this.controlProcess.write(`display-message -p "tmex-hb"
|
|
99479
|
+
`);
|
|
99480
|
+
this.heartbeatTimeoutTimer = setTimeout(() => {
|
|
99481
|
+
if (!this.heartbeatPending || !this.connected || this.manualDisconnect) {
|
|
99482
|
+
return;
|
|
99483
|
+
}
|
|
99484
|
+
console.warn(`[local] tmux control client heartbeat timeout on ${this.deviceId}, killing stalled process`);
|
|
99485
|
+
this.controlProcess?.kill();
|
|
99486
|
+
}, HEARTBEAT_TIMEOUT_MS);
|
|
99487
|
+
}
|
|
99488
|
+
onHeartbeatResponse() {
|
|
99489
|
+
if (!this.heartbeatPending) {
|
|
99490
|
+
return;
|
|
99491
|
+
}
|
|
99492
|
+
this.heartbeatPending = false;
|
|
99493
|
+
if (this.heartbeatTimeoutTimer) {
|
|
99494
|
+
clearTimeout(this.heartbeatTimeoutTimer);
|
|
99495
|
+
this.heartbeatTimeoutTimer = null;
|
|
99496
|
+
}
|
|
99497
|
+
}
|
|
99421
99498
|
handleControlClientExit(proc, exitCode) {
|
|
99422
99499
|
if (this.controlProcess !== proc) {
|
|
99423
99500
|
return;
|
|
@@ -100197,6 +100274,8 @@ var CONTROL_RESTART_DELAY_MS2 = 500;
|
|
|
100197
100274
|
var CONTROL_STABLE_RESET_MS2 = 1e4;
|
|
100198
100275
|
var CONTROL_STDERR_TAIL_LIMIT2 = 2048;
|
|
100199
100276
|
var CONTROL_ATTACH_READY_TIMEOUT_MS2 = 3000;
|
|
100277
|
+
var HEARTBEAT_INTERVAL_MS2 = 30000;
|
|
100278
|
+
var HEARTBEAT_TIMEOUT_MS2 = 1e4;
|
|
100200
100279
|
var PARKING_WINDOW_NAME2 = "tmex-park";
|
|
100201
100280
|
|
|
100202
100281
|
class SshExternalTmuxConnection {
|
|
@@ -100220,6 +100299,9 @@ class SshExternalTmuxConnection {
|
|
|
100220
100299
|
controlStartedAt = 0;
|
|
100221
100300
|
controlRestartCount = 0;
|
|
100222
100301
|
controlStderrTail = "";
|
|
100302
|
+
heartbeatTimer = null;
|
|
100303
|
+
heartbeatPending = false;
|
|
100304
|
+
heartbeatTimeoutTimer = null;
|
|
100223
100305
|
sshClient = null;
|
|
100224
100306
|
commandStream = null;
|
|
100225
100307
|
commandStdoutBuffer = "";
|
|
@@ -100641,6 +100723,7 @@ class SshExternalTmuxConnection {
|
|
|
100641
100723
|
await this.runTmuxAllowFailure(["kill-window", "-t", windowId]);
|
|
100642
100724
|
}
|
|
100643
100725
|
async startControlClient() {
|
|
100726
|
+
this.stopHeartbeat();
|
|
100644
100727
|
let attachReadyResolve = null;
|
|
100645
100728
|
const attachReady = new Promise((resolve3) => {
|
|
100646
100729
|
attachReadyResolve = resolve3;
|
|
@@ -100662,6 +100745,7 @@ class SshExternalTmuxConnection {
|
|
|
100662
100745
|
if (this.controlChannel !== handle) {
|
|
100663
100746
|
throw new Error(this.controlStderrTail.trim() || "tmux control client channel closed during attach");
|
|
100664
100747
|
}
|
|
100748
|
+
this.startHeartbeat();
|
|
100665
100749
|
}
|
|
100666
100750
|
async openControlChannel(onAttachReady) {
|
|
100667
100751
|
const subscription = createControlModeSubscription({
|
|
@@ -100688,16 +100772,25 @@ class SshExternalTmuxConnection {
|
|
|
100688
100772
|
this.requestSnapshot();
|
|
100689
100773
|
},
|
|
100690
100774
|
onExit: () => {},
|
|
100691
|
-
|
|
100775
|
+
onPause: (paneId) => {
|
|
100776
|
+
if (this.controlChannel === handle) {
|
|
100777
|
+
handle.write("refresh-client -A " + paneId + ":continue" + `
|
|
100778
|
+
`);
|
|
100779
|
+
}
|
|
100780
|
+
},
|
|
100781
|
+
onBlockEnd: (block) => {
|
|
100692
100782
|
onAttachReady();
|
|
100783
|
+
if (!block.isError && block.lines.length === 1 && block.lines[0] === "tmex-hb") {
|
|
100784
|
+
this.onHeartbeatResponse();
|
|
100785
|
+
}
|
|
100693
100786
|
}
|
|
100694
100787
|
});
|
|
100695
|
-
const handle = { stop: () => {} };
|
|
100788
|
+
const handle = { stop: () => {}, write: () => {} };
|
|
100696
100789
|
this.controlChannel = handle;
|
|
100697
100790
|
this.controlSubscription = subscription;
|
|
100698
100791
|
this.controlStartedAt = Date.now();
|
|
100699
100792
|
this.controlStderrTail = "";
|
|
100700
|
-
const
|
|
100793
|
+
const reader = await this.openReaderChannel(`exec ${quoteShellArg(this.tmuxBin)} -C attach-session -t ${quoteShellArg(this.sessionName)}`, {
|
|
100701
100794
|
onData: (data) => {
|
|
100702
100795
|
if (this.controlChannel === handle) {
|
|
100703
100796
|
subscription.push(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
@@ -100712,16 +100805,60 @@ class SshExternalTmuxConnection {
|
|
|
100712
100805
|
this.handleControlChannelClose(handle);
|
|
100713
100806
|
}
|
|
100714
100807
|
});
|
|
100715
|
-
handle.stop =
|
|
100808
|
+
handle.stop = reader.stop;
|
|
100809
|
+
handle.write = reader.write;
|
|
100716
100810
|
return handle;
|
|
100717
100811
|
}
|
|
100718
100812
|
stopControlClient() {
|
|
100813
|
+
this.stopHeartbeat();
|
|
100719
100814
|
const handle = this.controlChannel;
|
|
100720
100815
|
this.controlChannel = null;
|
|
100721
100816
|
this.controlSubscription?.dispose();
|
|
100722
100817
|
this.controlSubscription = null;
|
|
100723
100818
|
handle?.stop();
|
|
100724
100819
|
}
|
|
100820
|
+
startHeartbeat() {
|
|
100821
|
+
if (this.heartbeatTimer) {
|
|
100822
|
+
clearInterval(this.heartbeatTimer);
|
|
100823
|
+
}
|
|
100824
|
+
if (this.heartbeatTimeoutTimer) {
|
|
100825
|
+
clearTimeout(this.heartbeatTimeoutTimer);
|
|
100826
|
+
}
|
|
100827
|
+
this.heartbeatPending = false;
|
|
100828
|
+
this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), HEARTBEAT_INTERVAL_MS2);
|
|
100829
|
+
}
|
|
100830
|
+
stopHeartbeat() {
|
|
100831
|
+
if (this.heartbeatTimer) {
|
|
100832
|
+
clearInterval(this.heartbeatTimer);
|
|
100833
|
+
this.heartbeatTimer = null;
|
|
100834
|
+
}
|
|
100835
|
+
if (this.heartbeatTimeoutTimer) {
|
|
100836
|
+
clearTimeout(this.heartbeatTimeoutTimer);
|
|
100837
|
+
this.heartbeatTimeoutTimer = null;
|
|
100838
|
+
}
|
|
100839
|
+
this.heartbeatPending = false;
|
|
100840
|
+
}
|
|
100841
|
+
sendHeartbeat() {
|
|
100842
|
+
if (!this.controlChannel || this.heartbeatPending || !this.connected || this.manualDisconnect) {
|
|
100843
|
+
return;
|
|
100844
|
+
}
|
|
100845
|
+
this.heartbeatPending = true;
|
|
100846
|
+
this.controlChannel.write('display-message -p "tmex-hb"' + `
|
|
100847
|
+
`);
|
|
100848
|
+
this.heartbeatTimeoutTimer = setTimeout(() => {
|
|
100849
|
+
if (this.heartbeatPending && this.connected && !this.manualDisconnect) {
|
|
100850
|
+
console.warn(`[ssh] tmux control client heartbeat timeout on ${this.deviceId}, killing stalled channel`);
|
|
100851
|
+
this.controlChannel?.stop();
|
|
100852
|
+
}
|
|
100853
|
+
}, HEARTBEAT_TIMEOUT_MS2);
|
|
100854
|
+
}
|
|
100855
|
+
onHeartbeatResponse() {
|
|
100856
|
+
this.heartbeatPending = false;
|
|
100857
|
+
if (this.heartbeatTimeoutTimer) {
|
|
100858
|
+
clearTimeout(this.heartbeatTimeoutTimer);
|
|
100859
|
+
this.heartbeatTimeoutTimer = null;
|
|
100860
|
+
}
|
|
100861
|
+
}
|
|
100725
100862
|
handleControlChannelClose(handle) {
|
|
100726
100863
|
if (this.controlChannel !== handle) {
|
|
100727
100864
|
return;
|
|
@@ -101172,10 +101309,17 @@ printf '\\036TMEX_END %s %d\\036\\n' ${quoteShellArg(commandId)} $?
|
|
|
101172
101309
|
});
|
|
101173
101310
|
stream.write(`${command}
|
|
101174
101311
|
`);
|
|
101175
|
-
return
|
|
101176
|
-
|
|
101177
|
-
|
|
101178
|
-
|
|
101312
|
+
return {
|
|
101313
|
+
stop: () => {
|
|
101314
|
+
stream.end();
|
|
101315
|
+
stream.close();
|
|
101316
|
+
stream.destroy();
|
|
101317
|
+
},
|
|
101318
|
+
write: (data) => {
|
|
101319
|
+
try {
|
|
101320
|
+
stream.write(data);
|
|
101321
|
+
} catch {}
|
|
101322
|
+
}
|
|
101179
101323
|
};
|
|
101180
101324
|
}
|
|
101181
101325
|
isTmuxServerGoneMessage(message) {
|
|
@@ -106601,8 +106745,8 @@ function getBaseVersion() {
|
|
|
106601
106745
|
if (cachedBase !== undefined)
|
|
106602
106746
|
return cachedBase;
|
|
106603
106747
|
let base = null;
|
|
106604
|
-
if ("0.
|
|
106605
|
-
base = "0.
|
|
106748
|
+
if ("0.15.1") {
|
|
106749
|
+
base = "0.15.1";
|
|
106606
106750
|
}
|
|
106607
106751
|
if (!base && config.isProd) {
|
|
106608
106752
|
base = readInstallMeta()?.cliVersion ?? null;
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Y as Fe,u as je,j as o,$ as tt,a0 as nt,a1 as rt,a2 as st,a3 as ot,a4 as it,r,d as H,a5 as J,a6 as Xe,a7 as Ke,a8 as ct,a9 as at,aa as lt,ab as Oe,o as xe,ac as ut,ad as Be,ae as dt,b as Ge,af as We,ag as ft,c as $e,ah as Ve,ai as Ee,aj as mt,ak as ht,al as ze,y as wt,am as pt,B as me,T as xt,an as vt,ao as gt,ap as St,aq as bt,A as Et,f as Rt,g as Tt,i as yt,k as jt,l as It,m as Ct,n as Nt}from"./index-
|
|
1
|
+
import{Y as Fe,u as je,j as o,$ as tt,a0 as nt,a1 as rt,a2 as st,a3 as ot,a4 as it,r,d as H,a5 as J,a6 as Xe,a7 as Ke,a8 as ct,a9 as at,aa as lt,ab as Oe,o as xe,ac as ut,ad as Be,ae as dt,b as Ge,af as We,ag as ft,c as $e,ah as Ve,ai as Ee,aj as mt,ak as ht,al as ze,y as wt,am as pt,B as me,T as xt,an as vt,ao as gt,ap as St,aq as bt,A as Et,f as Rt,g as Tt,i as yt,k as jt,l as It,m as Ct,n as Nt}from"./index-B3aiK6xC.js";import{T as kt,C as Mt,c as Pt,F as At,a as Qe,R as Lt,A as _t,f as zt,t as Dt,S as Ft}from"./terminal-settings-panel-DCm6ZfTX.js";import{w as Bt}from"./selection-clipboard-Dq6Zemfd.js";import{C as Wt}from"./copy-BF0hUIaY.js";import{S as qe,K as $t}from"./send-DjlZMim3.js";/**
|
|
2
2
|
* @license lucide-react v0.564.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as b,r as v,a as _,b as ie,c as re,d as ne,e as I,t as oe,j as s,M as X,B as C,P as Y,A as ce,f as de,g as le,h as ue,T as ee,i as me,k as he,l as pe,m as xe,n as ve,G as fe,o as f,D as ge,p as ye,E as je,q as we,s as $,v as Ne,w as De,x as Q,y as Ce,S as be,L as Se,z as ke,C as Ee,F as Me,H as Pe,I as Ie,J as Ke,K as x,N as z,O as V,Q as U,R as J,U as w,V as Re,W as $e}from"./index-DAElYydw.js";import{C as M,a as P,b as Ae,c as Te,d as Fe}from"./card-CydUB3N3.js";import{Z as We}from"./zap-CBgYyGBV.js";function g(e){const o=e.trim();return o||void 0}function qe(e){return e?{name:e.name,type:e.type,host:e.host??"",port:e.port??22,username:e.username??"",sshConfigRef:e.sshConfigRef??"",session:e.session??"tmex",defaultWorkingDir:e.defaultWorkingDir??"",authMode:e.type==="local"?"auto":e.authMode,password:"",privateKey:"",privateKeyPassphrase:""}:{name:"",type:"local",host:"",port:22,username:"root",sshConfigRef:"",session:"tmex",defaultWorkingDir:"",authMode:"auto",password:"",privateKey:"",privateKeyPassphrase:""}}function Le(e){if(e.type==="local")return{name:e.name.trim(),type:"local",session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir),authMode:"auto"};const o={name:e.name.trim(),type:"ssh",host:e.host.trim(),port:e.port,username:e.username.trim(),session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir),authMode:e.authMode};return e.authMode==="configRef"&&(o.sshConfigRef=e.sshConfigRef.trim()),e.authMode==="password"&&(o.password=e.password),e.authMode==="key"&&(o.privateKey=e.privateKey,o.privateKeyPassphrase=e.privateKeyPassphrase||void 0),o}function He(e){if(e.type==="local")return{name:e.name.trim(),session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir)??"",authMode:"auto"};const o={name:e.name.trim(),host:e.host.trim(),port:e.port,username:e.username.trim(),sshConfigRef:e.authMode==="configRef"?e.sshConfigRef.trim():"",session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir)??"",authMode:e.authMode};return e.authMode==="password"&&e.password&&(o.password=e.password),e.authMode==="key"&&e.privateKey&&(o.privateKey=e.privateKey,o.privateKeyPassphrase=e.privateKeyPassphrase||void 0),o}function se(e){return Number.isInteger(e)&&e>=1&&e<=65535}function Oe(e){return e.type!=="ssh"?null:e.host.trim()?se(e.port)?e.username.trim()?e.authMode==="configRef"&&!e.sshConfigRef.trim()?"validation.sshConfigRequired":null:"validation.usernameRequired":"validation.portRequired":"validation.hostRequired"}async function G(e,o){try{return(await e.json()).error??o}catch{return o}}function Ue(){const{t:e}=b(),[o,m]=v.useState(!1),[t,y]=v.useState(null),[r,d]=v.useState(null),l=_(),h=ie(n=>{var p;return((p=n.settings)==null?void 0:p.language)??"en_US"});v.useEffect(()=>{const n=()=>m(!0);return window.addEventListener("tmex:open-add-device",n),()=>window.removeEventListener("tmex:open-add-device",n)},[]);const{data:c,isLoading:K,isError:N}=re({queryKey:["devices"],queryFn:async()=>{const n=await fetch("/api/devices");if(!n.ok)throw new Error(e("device.loadFailed"));return n.json()},throwOnError:!1}),S=ne(n=>n.hydrateDeviceErrors);v.useEffect(()=>{c!=null&&c.devices&&S(c.devices.map(n=>({deviceId:n.id,lastError:n.lastError??null,lastErrorType:n.lastErrorType??null})))},[c,S]);const k=I({mutationFn:async n=>{if(!(await fetch(`/api/devices/${n}`,{method:"DELETE"})).ok)throw new Error(e("device.deleteFailed"))},onSuccess:()=>{l.invalidateQueries({queryKey:["devices"]}),f.success(e("common.success"))},onError:n=>{f.error(n instanceof Error?n.message:e("common.error"))}}),E=v.useMemo(()=>[...(c==null?void 0:c.devices)??[]].sort((p,D)=>p.sortOrder-D.sortOrder||p.name.localeCompare(D.name,oe(h),{numeric:!0,sensitivity:"base"})),[c==null?void 0:c.devices,h]);return s.jsxs("div",{className:"mx-auto flex w-full max-w-6xl flex-col gap-3 p-3 pb-[calc(1rem+env(safe-area-inset-bottom))] sm:gap-4 sm:p-5","data-testid":"devices-page",children:[K?s.jsx(M,{children:s.jsx(P,{className:"py-16 text-center text-sm text-muted-foreground",children:e("common.loading")})}):N?s.jsx(M,{children:s.jsx(P,{className:"py-16 text-center text-sm text-destructive",children:e("device.loadFailed")})}):E.length===0?s.jsx(M,{children:s.jsxs(P,{className:"space-y-4 py-14 text-center",children:[s.jsx("div",{className:"mx-auto flex h-12 w-12 items-center justify-center rounded-xl border border-border bg-muted",children:s.jsx(X,{className:"h-6 w-6 text-muted-foreground"})}),s.jsxs("div",{className:"space-y-1",children:[s.jsx("h2",{className:"text-lg font-medium",children:e("device.noDevices")}),s.jsx("p",{className:"text-sm text-muted-foreground",children:e("device.addDevice")})]}),s.jsxs(C,{variant:"default","data-testid":"devices-add-empty",onClick:()=>m(!0),children:[s.jsx(Y,{className:"h-4 w-4"}),e("device.addDevice")]})]})}):s.jsx("div",{className:"grid gap-3 lg:grid-cols-2",children:E.map(n=>s.jsx(Be,{device:n,onEdit:()=>y(n),onDelete:()=>d(n)},n.id))}),o&&s.jsx(Z,{mode:"create",onClose:()=>m(!1)}),t&&s.jsx(Z,{mode:"edit",device:t,onClose:()=>y(null)}),s.jsx(ce,{open:r!==null,onOpenChange:n=>!n&&d(null),children:s.jsxs(de,{children:[s.jsxs(le,{children:[s.jsx(ue,{className:"bg-destructive/10",children:s.jsx(ee,{className:"h-5 w-5 text-destructive"})}),s.jsx(me,{children:e("device.deleteConfirm")}),s.jsx(he,{children:e("device.deleteDescription",{name:(r==null?void 0:r.name)??""})})]}),s.jsxs(pe,{children:[s.jsx(xe,{children:e("common.cancel")}),s.jsx(ve,{variant:"destructive",disabled:!r||k.isPending,onClick:()=>{r&&(k.mutate(r.id),d(null))},children:e("common.delete")})]})]})})]})}function Be({device:e,onEdit:o,onDelete:m}){const{t}=b(),y=e.type==="local"?s.jsx(X,{className:"h-4 w-4"}):s.jsx(fe,{className:"h-4 w-4"}),r=e.type==="local"?t("device.typeLocal"):`${e.username??"-"}@${e.host??"-"}:${e.port??22}`,d=I({mutationFn:async()=>{const l=await fetch(`/api/devices/${e.id}/test-connection`,{method:"POST"});let h=null;try{h=await l.json()}catch{h=null}if(!l.ok){const c=h;throw new Error((c==null?void 0:c.error)??t("common.error"))}return h},onSuccess:l=>{f.success(l.message??t("common.success"))},onError:l=>{f.error(l instanceof Error?l.message:t("common.error"))}});return s.jsxs(M,{"data-testid":"device-card","data-device-id":e.id,"data-device-name":e.name,className:"overflow-hidden border-border/50",children:[s.jsxs(Ae,{className:"space-y-2 pb-2",children:[s.jsxs("div",{className:"flex items-start justify-between gap-2",children:[s.jsxs("div",{className:"flex min-w-0 items-center gap-2.5",children:[s.jsx("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground",children:y}),s.jsxs("div",{className:"min-w-0 space-y-0.5",children:[s.jsx(Te,{className:"line-clamp-1 text-sm",title:e.name,children:e.name}),s.jsx(Fe,{className:"line-clamp-1 text-xs",children:r})]})]}),s.jsx("div",{className:"flex shrink-0 items-center gap-1",children:s.jsxs(ge,{children:[s.jsx(ye,{render:s.jsx(C,{variant:"ghost",size:"icon-sm","data-testid":`device-card-actions-${e.id}`,"aria-label":t("common.edit"),title:t("common.edit")}),children:s.jsx(je,{className:"h-4 w-4"})}),s.jsxs(we,{align:"end",children:[s.jsxs($,{"data-testid":`device-card-edit-${e.id}`,onClick:o,children:[s.jsx(Ne,{className:"h-4 w-4"}),t("common.edit")]}),e.type==="ssh"&&s.jsxs($,{"data-testid":`device-card-test-${e.id}`,onClick:()=>d.mutate(),disabled:d.isPending,children:[s.jsx(We,{className:"h-4 w-4"}),t("common.test")]}),s.jsx(De,{}),s.jsxs($,{"data-testid":`device-card-delete-${e.id}`,variant:"destructive",onClick:m,children:[s.jsx(ee,{className:"h-4 w-4"}),t("common.delete")]})]})]})})]}),s.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[s.jsx(Q,{variant:"outline",className:"text-[11px] font-normal",children:e.type==="local"?t("device.typeLocal"):t("device.typeSSHBadge")}),e.session&&s.jsx(Q,{variant:"outline",className:"text-[11px] font-normal",children:e.session}),s.jsx(Ce,{deviceId:e.id})]})]}),s.jsxs(P,{className:"pt-0",children:[s.jsx(be,{className:"mb-2"}),s.jsx("div",{className:"flex items-center justify-end",children:s.jsx(Se,{to:`/devices/${e.id}`,"data-testid":`device-card-connect-${e.id}`,className:ke({variant:"outline",size:"sm"}),children:t("device.connect")})})]})]})}function Z({mode:e,device:o,onClose:m}){const{t}=b(),y=_(),[r,d]=v.useState(qe(o)),[l,h]=v.useState(!1),[c,K]=v.useState(!1),N=e==="edit",S=r.type==="ssh",k=I({mutationFn:async a=>{const i=await fetch("/api/devices",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw new Error(await G(i,t("device.createFailed")));return i.json()},onSuccess:()=>{y.invalidateQueries({queryKey:["devices"]}),f.success(t("common.success")),m()},onError:a=>{f.error(a instanceof Error?a.message:t("common.error"))}}),E=I({mutationFn:async a=>{if(!o)throw new Error(t("apiError.deviceNotFound"));const i=await fetch(`/api/devices/${o.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw new Error(await G(i,t("device.updateFailed")));return i.json()},onSuccess:()=>{y.invalidateQueries({queryKey:["devices"]}),f.success(t("common.success")),m()},onError:a=>{f.error(a instanceof Error?a.message:t("common.error"))}}),n=async a=>{a.preventDefault(),K(!0);const i=Oe(r);if(i){f.error(t(i));return}h(!0);try{e==="create"?await k.mutateAsync(Le(r)):await E.mutateAsync(He(r))}catch{}finally{h(!1)}},p=`${e}-device-name`,D=`${e}-device-type`,A=`${e}-device-host`,T=`${e}-device-port`,F=`${e}-device-username`,W=`${e}-device-session`,q=`${e}-device-default-working-dir`,L=`${e}-device-auth-mode`,H=`${e}-device-password`,O=`${e}-device-private-key`,B=`${e}-device-private-key-passphrase`,te={local:t("device.typeLocal"),ssh:t("device.typeSSH")},ae={password:t("device.authPassword"),key:t("device.authKey"),agent:t("device.authAgent"),configRef:t("device.authConfigRef")},R=a=>s.jsx("div",{className:"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground",children:a}),u=(a,i,j)=>s.jsxs("label",{className:"block text-xs font-medium text-foreground",htmlFor:a,children:[i,j&&s.jsx("span",{className:"ml-0.5 text-destructive",children:"*"})]});return s.jsx(Ee,{open:!0,onOpenChange:a=>!a&&m(),children:s.jsxs(Me,{"data-testid":"device-dialog",className:"w-full max-w-2xl",children:[s.jsxs(Pe,{children:[s.jsx(Ie,{children:t(N?"device.editDevice":"device.addDevice")}),s.jsx(Ke,{children:t(N?"device.editDeviceDescription":"device.addDeviceDescription")})]}),s.jsxs("form",{onSubmit:n,className:"space-y-4",children:[s.jsxs("div",{className:"-mr-2 max-h-[min(70dvh,720px)] space-y-5 overflow-y-auto pr-2",children:[s.jsxs("section",{className:"space-y-2.5",children:[R(t("device.sectionBasic")),s.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(p,t("device.name"),!0),s.jsx(x,{id:p,"data-testid":"device-name-input",type:"text",value:r.name,onChange:a=>d(i=>({...i,name:a.target.value})),placeholder:t("device.namePlaceholder"),required:!0})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(D,t("device.type")),s.jsxs(z,{value:r.type,onValueChange:a=>{if(!a)return;const i=a;d(j=>({...j,type:i,authMode:i==="local"?"auto":j.authMode==="auto"?"agent":j.authMode}))},disabled:N,children:[s.jsx(V,{id:D,"data-testid":"device-type-select",className:"w-full",children:s.jsx(U,{placeholder:t("device.type"),children:a=>te[a]??""})}),s.jsxs(J,{children:[s.jsx(w,{value:"local",children:t("device.typeLocal")}),s.jsx(w,{value:"ssh",children:t("device.typeSSH")})]})]})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(W,t("device.session")),s.jsx(x,{id:W,"data-testid":"device-session-input",type:"text",value:r.session,onChange:a=>d(i=>({...i,session:a.target.value})),placeholder:t("device.sessionPlaceholder")})]}),s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(q,t("device.defaultWorkingDir")),s.jsx(x,{id:q,"data-testid":"device-default-working-dir-input",type:"text",value:r.defaultWorkingDir,onChange:a=>d(i=>({...i,defaultWorkingDir:a.target.value})),placeholder:t("device.defaultWorkingDirPlaceholder")})]})]})]}),S&&s.jsxs(s.Fragment,{children:[s.jsxs("section",{className:"space-y-2.5",children:[R(t("device.sectionConnection")),s.jsxs("div",{className:"grid gap-3 sm:grid-cols-3",children:[s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(A,t("device.host"),!0),s.jsx(x,{id:A,type:"text",value:r.host,onChange:a=>d(i=>({...i,host:a.target.value})),placeholder:t("device.hostPlaceholder"),"aria-invalid":c&&!r.host.trim()})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(T,t("device.port"),!0),s.jsx(x,{id:T,type:"number",value:Number.isNaN(r.port)?"":r.port,onChange:a=>{const i=a.target.value;d(j=>({...j,port:i===""?Number.NaN:Number.parseInt(i,10)}))},min:1,max:65535,"aria-invalid":c&&!se(r.port)})]}),s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(F,t("device.username"),!0),s.jsx(x,{id:F,type:"text",value:r.username,onChange:a=>d(i=>({...i,username:a.target.value})),placeholder:t("device.usernamePlaceholder"),"aria-invalid":c&&!r.username.trim()})]})]})]}),s.jsxs("section",{className:"space-y-2.5",children:[R(t("device.sectionAuth")),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{className:"space-y-1.5",children:[u(L,t("device.authMode")),s.jsxs(z,{value:r.authMode,onValueChange:a=>{a&&d(i=>({...i,authMode:a}))},children:[s.jsx(V,{id:L,"data-testid":"device-auth-mode-select",className:"w-full",children:s.jsx(U,{placeholder:t("device.authMode"),children:a=>ae[a]??""})}),s.jsxs(J,{children:[s.jsx(w,{value:"password",children:t("device.authPassword")}),s.jsx(w,{value:"key",children:t("device.authKey")}),s.jsx(w,{value:"agent",children:t("device.authAgent")}),s.jsx(w,{value:"configRef",children:t("device.authConfigRef")})]})]})]}),r.authMode==="password"&&s.jsxs("div",{className:"space-y-1.5",children:[u(H,t("device.password")),s.jsx(x,{id:H,type:"password",value:r.password,onChange:a=>d(i=>({...i,password:a.target.value}))})]}),r.authMode==="key"&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"space-y-1.5",children:[u(O,t("device.privateKey")),s.jsx(Re,{id:O,value:r.privateKey,onChange:a=>d(i=>({...i,privateKey:a.target.value})),className:"h-28 font-mono text-xs",placeholder:t("device.privateKeyPlaceholder")})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(B,t("device.passphrase")),s.jsx(x,{id:B,type:"password",value:r.privateKeyPassphrase,onChange:a=>d(i=>({...i,privateKeyPassphrase:a.target.value}))})]})]}),r.authMode==="configRef"&&s.jsxs("div",{className:"space-y-1.5",children:[u(`${e}-device-ssh-config-ref`,t("device.authConfigRef"),!0),s.jsx(x,{id:`${e}-device-ssh-config-ref`,"data-testid":"device-ssh-config-ref-input",type:"text",value:r.sshConfigRef,onChange:a=>d(i=>({...i,sshConfigRef:a.target.value})),placeholder:t("device.sshConfigRefPlaceholder"),"aria-invalid":c&&!r.sshConfigRef.trim()}),s.jsx("p",{className:"text-[11px] text-muted-foreground",children:t("device.sshConfigRefHint")})]})]})]})]})]}),s.jsxs($e,{children:[s.jsx(C,{type:"button",variant:"outline",onClick:m,children:t("common.cancel")}),s.jsx(C,{type:"submit",variant:"default","data-testid":"device-dialog-save",disabled:l,children:t(l?"common.saving":"common.save")})]})]})]})})}function Je(){const{t:e}=b();return s.jsx(s.Fragment,{children:e("sidebar.manageDevices")})}function Ge(){const{t:e}=b(),o=()=>{window.dispatchEvent(new CustomEvent("tmex:open-add-device"))};return s.jsx(C,{variant:"ghost",size:"icon-sm","data-testid":"devices-add",onClick:o,"aria-label":e("sidebar.addDevice"),title:e("sidebar.addDevice"),children:s.jsx(Y,{className:"h-4 w-4"})})}export{Ge as PageActions,Je as PageTitle,Ue as default};
|
|
1
|
+
import{u as b,r as v,a as _,b as ie,c as re,d as ne,e as I,t as oe,j as s,M as X,B as C,P as Y,A as ce,f as de,g as le,h as ue,T as ee,i as me,k as he,l as pe,m as xe,n as ve,G as fe,o as f,D as ge,p as ye,E as je,q as we,s as $,v as Ne,w as De,x as Q,y as Ce,S as be,L as Se,z as ke,C as Ee,F as Me,H as Pe,I as Ie,J as Ke,K as x,N as z,O as V,Q as U,R as J,U as w,V as Re,W as $e}from"./index-B3aiK6xC.js";import{C as M,a as P,b as Ae,c as Te,d as Fe}from"./card-LIHKdO48.js";import{Z as We}from"./zap-CCdOD6uR.js";function g(e){const o=e.trim();return o||void 0}function qe(e){return e?{name:e.name,type:e.type,host:e.host??"",port:e.port??22,username:e.username??"",sshConfigRef:e.sshConfigRef??"",session:e.session??"tmex",defaultWorkingDir:e.defaultWorkingDir??"",authMode:e.type==="local"?"auto":e.authMode,password:"",privateKey:"",privateKeyPassphrase:""}:{name:"",type:"local",host:"",port:22,username:"root",sshConfigRef:"",session:"tmex",defaultWorkingDir:"",authMode:"auto",password:"",privateKey:"",privateKeyPassphrase:""}}function Le(e){if(e.type==="local")return{name:e.name.trim(),type:"local",session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir),authMode:"auto"};const o={name:e.name.trim(),type:"ssh",host:e.host.trim(),port:e.port,username:e.username.trim(),session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir),authMode:e.authMode};return e.authMode==="configRef"&&(o.sshConfigRef=e.sshConfigRef.trim()),e.authMode==="password"&&(o.password=e.password),e.authMode==="key"&&(o.privateKey=e.privateKey,o.privateKeyPassphrase=e.privateKeyPassphrase||void 0),o}function He(e){if(e.type==="local")return{name:e.name.trim(),session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir)??"",authMode:"auto"};const o={name:e.name.trim(),host:e.host.trim(),port:e.port,username:e.username.trim(),sshConfigRef:e.authMode==="configRef"?e.sshConfigRef.trim():"",session:g(e.session)??"tmex",defaultWorkingDir:g(e.defaultWorkingDir)??"",authMode:e.authMode};return e.authMode==="password"&&e.password&&(o.password=e.password),e.authMode==="key"&&e.privateKey&&(o.privateKey=e.privateKey,o.privateKeyPassphrase=e.privateKeyPassphrase||void 0),o}function se(e){return Number.isInteger(e)&&e>=1&&e<=65535}function Oe(e){return e.type!=="ssh"?null:e.host.trim()?se(e.port)?e.username.trim()?e.authMode==="configRef"&&!e.sshConfigRef.trim()?"validation.sshConfigRequired":null:"validation.usernameRequired":"validation.portRequired":"validation.hostRequired"}async function G(e,o){try{return(await e.json()).error??o}catch{return o}}function Ue(){const{t:e}=b(),[o,m]=v.useState(!1),[t,y]=v.useState(null),[r,d]=v.useState(null),l=_(),h=ie(n=>{var p;return((p=n.settings)==null?void 0:p.language)??"en_US"});v.useEffect(()=>{const n=()=>m(!0);return window.addEventListener("tmex:open-add-device",n),()=>window.removeEventListener("tmex:open-add-device",n)},[]);const{data:c,isLoading:K,isError:N}=re({queryKey:["devices"],queryFn:async()=>{const n=await fetch("/api/devices");if(!n.ok)throw new Error(e("device.loadFailed"));return n.json()},throwOnError:!1}),S=ne(n=>n.hydrateDeviceErrors);v.useEffect(()=>{c!=null&&c.devices&&S(c.devices.map(n=>({deviceId:n.id,lastError:n.lastError??null,lastErrorType:n.lastErrorType??null})))},[c,S]);const k=I({mutationFn:async n=>{if(!(await fetch(`/api/devices/${n}`,{method:"DELETE"})).ok)throw new Error(e("device.deleteFailed"))},onSuccess:()=>{l.invalidateQueries({queryKey:["devices"]}),f.success(e("common.success"))},onError:n=>{f.error(n instanceof Error?n.message:e("common.error"))}}),E=v.useMemo(()=>[...(c==null?void 0:c.devices)??[]].sort((p,D)=>p.sortOrder-D.sortOrder||p.name.localeCompare(D.name,oe(h),{numeric:!0,sensitivity:"base"})),[c==null?void 0:c.devices,h]);return s.jsxs("div",{className:"mx-auto flex w-full max-w-6xl flex-col gap-3 p-3 pb-[calc(1rem+env(safe-area-inset-bottom))] sm:gap-4 sm:p-5","data-testid":"devices-page",children:[K?s.jsx(M,{children:s.jsx(P,{className:"py-16 text-center text-sm text-muted-foreground",children:e("common.loading")})}):N?s.jsx(M,{children:s.jsx(P,{className:"py-16 text-center text-sm text-destructive",children:e("device.loadFailed")})}):E.length===0?s.jsx(M,{children:s.jsxs(P,{className:"space-y-4 py-14 text-center",children:[s.jsx("div",{className:"mx-auto flex h-12 w-12 items-center justify-center rounded-xl border border-border bg-muted",children:s.jsx(X,{className:"h-6 w-6 text-muted-foreground"})}),s.jsxs("div",{className:"space-y-1",children:[s.jsx("h2",{className:"text-lg font-medium",children:e("device.noDevices")}),s.jsx("p",{className:"text-sm text-muted-foreground",children:e("device.addDevice")})]}),s.jsxs(C,{variant:"default","data-testid":"devices-add-empty",onClick:()=>m(!0),children:[s.jsx(Y,{className:"h-4 w-4"}),e("device.addDevice")]})]})}):s.jsx("div",{className:"grid gap-3 lg:grid-cols-2",children:E.map(n=>s.jsx(Be,{device:n,onEdit:()=>y(n),onDelete:()=>d(n)},n.id))}),o&&s.jsx(Z,{mode:"create",onClose:()=>m(!1)}),t&&s.jsx(Z,{mode:"edit",device:t,onClose:()=>y(null)}),s.jsx(ce,{open:r!==null,onOpenChange:n=>!n&&d(null),children:s.jsxs(de,{children:[s.jsxs(le,{children:[s.jsx(ue,{className:"bg-destructive/10",children:s.jsx(ee,{className:"h-5 w-5 text-destructive"})}),s.jsx(me,{children:e("device.deleteConfirm")}),s.jsx(he,{children:e("device.deleteDescription",{name:(r==null?void 0:r.name)??""})})]}),s.jsxs(pe,{children:[s.jsx(xe,{children:e("common.cancel")}),s.jsx(ve,{variant:"destructive",disabled:!r||k.isPending,onClick:()=>{r&&(k.mutate(r.id),d(null))},children:e("common.delete")})]})]})})]})}function Be({device:e,onEdit:o,onDelete:m}){const{t}=b(),y=e.type==="local"?s.jsx(X,{className:"h-4 w-4"}):s.jsx(fe,{className:"h-4 w-4"}),r=e.type==="local"?t("device.typeLocal"):`${e.username??"-"}@${e.host??"-"}:${e.port??22}`,d=I({mutationFn:async()=>{const l=await fetch(`/api/devices/${e.id}/test-connection`,{method:"POST"});let h=null;try{h=await l.json()}catch{h=null}if(!l.ok){const c=h;throw new Error((c==null?void 0:c.error)??t("common.error"))}return h},onSuccess:l=>{f.success(l.message??t("common.success"))},onError:l=>{f.error(l instanceof Error?l.message:t("common.error"))}});return s.jsxs(M,{"data-testid":"device-card","data-device-id":e.id,"data-device-name":e.name,className:"overflow-hidden border-border/50",children:[s.jsxs(Ae,{className:"space-y-2 pb-2",children:[s.jsxs("div",{className:"flex items-start justify-between gap-2",children:[s.jsxs("div",{className:"flex min-w-0 items-center gap-2.5",children:[s.jsx("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground",children:y}),s.jsxs("div",{className:"min-w-0 space-y-0.5",children:[s.jsx(Te,{className:"line-clamp-1 text-sm",title:e.name,children:e.name}),s.jsx(Fe,{className:"line-clamp-1 text-xs",children:r})]})]}),s.jsx("div",{className:"flex shrink-0 items-center gap-1",children:s.jsxs(ge,{children:[s.jsx(ye,{render:s.jsx(C,{variant:"ghost",size:"icon-sm","data-testid":`device-card-actions-${e.id}`,"aria-label":t("common.edit"),title:t("common.edit")}),children:s.jsx(je,{className:"h-4 w-4"})}),s.jsxs(we,{align:"end",children:[s.jsxs($,{"data-testid":`device-card-edit-${e.id}`,onClick:o,children:[s.jsx(Ne,{className:"h-4 w-4"}),t("common.edit")]}),e.type==="ssh"&&s.jsxs($,{"data-testid":`device-card-test-${e.id}`,onClick:()=>d.mutate(),disabled:d.isPending,children:[s.jsx(We,{className:"h-4 w-4"}),t("common.test")]}),s.jsx(De,{}),s.jsxs($,{"data-testid":`device-card-delete-${e.id}`,variant:"destructive",onClick:m,children:[s.jsx(ee,{className:"h-4 w-4"}),t("common.delete")]})]})]})})]}),s.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[s.jsx(Q,{variant:"outline",className:"text-[11px] font-normal",children:e.type==="local"?t("device.typeLocal"):t("device.typeSSHBadge")}),e.session&&s.jsx(Q,{variant:"outline",className:"text-[11px] font-normal",children:e.session}),s.jsx(Ce,{deviceId:e.id})]})]}),s.jsxs(P,{className:"pt-0",children:[s.jsx(be,{className:"mb-2"}),s.jsx("div",{className:"flex items-center justify-end",children:s.jsx(Se,{to:`/devices/${e.id}`,"data-testid":`device-card-connect-${e.id}`,className:ke({variant:"outline",size:"sm"}),children:t("device.connect")})})]})]})}function Z({mode:e,device:o,onClose:m}){const{t}=b(),y=_(),[r,d]=v.useState(qe(o)),[l,h]=v.useState(!1),[c,K]=v.useState(!1),N=e==="edit",S=r.type==="ssh",k=I({mutationFn:async a=>{const i=await fetch("/api/devices",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw new Error(await G(i,t("device.createFailed")));return i.json()},onSuccess:()=>{y.invalidateQueries({queryKey:["devices"]}),f.success(t("common.success")),m()},onError:a=>{f.error(a instanceof Error?a.message:t("common.error"))}}),E=I({mutationFn:async a=>{if(!o)throw new Error(t("apiError.deviceNotFound"));const i=await fetch(`/api/devices/${o.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!i.ok)throw new Error(await G(i,t("device.updateFailed")));return i.json()},onSuccess:()=>{y.invalidateQueries({queryKey:["devices"]}),f.success(t("common.success")),m()},onError:a=>{f.error(a instanceof Error?a.message:t("common.error"))}}),n=async a=>{a.preventDefault(),K(!0);const i=Oe(r);if(i){f.error(t(i));return}h(!0);try{e==="create"?await k.mutateAsync(Le(r)):await E.mutateAsync(He(r))}catch{}finally{h(!1)}},p=`${e}-device-name`,D=`${e}-device-type`,A=`${e}-device-host`,T=`${e}-device-port`,F=`${e}-device-username`,W=`${e}-device-session`,q=`${e}-device-default-working-dir`,L=`${e}-device-auth-mode`,H=`${e}-device-password`,O=`${e}-device-private-key`,B=`${e}-device-private-key-passphrase`,te={local:t("device.typeLocal"),ssh:t("device.typeSSH")},ae={password:t("device.authPassword"),key:t("device.authKey"),agent:t("device.authAgent"),configRef:t("device.authConfigRef")},R=a=>s.jsx("div",{className:"text-[11px] font-semibold uppercase tracking-wider text-muted-foreground",children:a}),u=(a,i,j)=>s.jsxs("label",{className:"block text-xs font-medium text-foreground",htmlFor:a,children:[i,j&&s.jsx("span",{className:"ml-0.5 text-destructive",children:"*"})]});return s.jsx(Ee,{open:!0,onOpenChange:a=>!a&&m(),children:s.jsxs(Me,{"data-testid":"device-dialog",className:"w-full max-w-2xl",children:[s.jsxs(Pe,{children:[s.jsx(Ie,{children:t(N?"device.editDevice":"device.addDevice")}),s.jsx(Ke,{children:t(N?"device.editDeviceDescription":"device.addDeviceDescription")})]}),s.jsxs("form",{onSubmit:n,className:"space-y-4",children:[s.jsxs("div",{className:"-mr-2 max-h-[min(70dvh,720px)] space-y-5 overflow-y-auto pr-2",children:[s.jsxs("section",{className:"space-y-2.5",children:[R(t("device.sectionBasic")),s.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(p,t("device.name"),!0),s.jsx(x,{id:p,"data-testid":"device-name-input",type:"text",value:r.name,onChange:a=>d(i=>({...i,name:a.target.value})),placeholder:t("device.namePlaceholder"),required:!0})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(D,t("device.type")),s.jsxs(z,{value:r.type,onValueChange:a=>{if(!a)return;const i=a;d(j=>({...j,type:i,authMode:i==="local"?"auto":j.authMode==="auto"?"agent":j.authMode}))},disabled:N,children:[s.jsx(V,{id:D,"data-testid":"device-type-select",className:"w-full",children:s.jsx(U,{placeholder:t("device.type"),children:a=>te[a]??""})}),s.jsxs(J,{children:[s.jsx(w,{value:"local",children:t("device.typeLocal")}),s.jsx(w,{value:"ssh",children:t("device.typeSSH")})]})]})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(W,t("device.session")),s.jsx(x,{id:W,"data-testid":"device-session-input",type:"text",value:r.session,onChange:a=>d(i=>({...i,session:a.target.value})),placeholder:t("device.sessionPlaceholder")})]}),s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(q,t("device.defaultWorkingDir")),s.jsx(x,{id:q,"data-testid":"device-default-working-dir-input",type:"text",value:r.defaultWorkingDir,onChange:a=>d(i=>({...i,defaultWorkingDir:a.target.value})),placeholder:t("device.defaultWorkingDirPlaceholder")})]})]})]}),S&&s.jsxs(s.Fragment,{children:[s.jsxs("section",{className:"space-y-2.5",children:[R(t("device.sectionConnection")),s.jsxs("div",{className:"grid gap-3 sm:grid-cols-3",children:[s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(A,t("device.host"),!0),s.jsx(x,{id:A,type:"text",value:r.host,onChange:a=>d(i=>({...i,host:a.target.value})),placeholder:t("device.hostPlaceholder"),"aria-invalid":c&&!r.host.trim()})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(T,t("device.port"),!0),s.jsx(x,{id:T,type:"number",value:Number.isNaN(r.port)?"":r.port,onChange:a=>{const i=a.target.value;d(j=>({...j,port:i===""?Number.NaN:Number.parseInt(i,10)}))},min:1,max:65535,"aria-invalid":c&&!se(r.port)})]}),s.jsxs("div",{className:"space-y-1.5 sm:col-span-2",children:[u(F,t("device.username"),!0),s.jsx(x,{id:F,type:"text",value:r.username,onChange:a=>d(i=>({...i,username:a.target.value})),placeholder:t("device.usernamePlaceholder"),"aria-invalid":c&&!r.username.trim()})]})]})]}),s.jsxs("section",{className:"space-y-2.5",children:[R(t("device.sectionAuth")),s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{className:"space-y-1.5",children:[u(L,t("device.authMode")),s.jsxs(z,{value:r.authMode,onValueChange:a=>{a&&d(i=>({...i,authMode:a}))},children:[s.jsx(V,{id:L,"data-testid":"device-auth-mode-select",className:"w-full",children:s.jsx(U,{placeholder:t("device.authMode"),children:a=>ae[a]??""})}),s.jsxs(J,{children:[s.jsx(w,{value:"password",children:t("device.authPassword")}),s.jsx(w,{value:"key",children:t("device.authKey")}),s.jsx(w,{value:"agent",children:t("device.authAgent")}),s.jsx(w,{value:"configRef",children:t("device.authConfigRef")})]})]})]}),r.authMode==="password"&&s.jsxs("div",{className:"space-y-1.5",children:[u(H,t("device.password")),s.jsx(x,{id:H,type:"password",value:r.password,onChange:a=>d(i=>({...i,password:a.target.value}))})]}),r.authMode==="key"&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"space-y-1.5",children:[u(O,t("device.privateKey")),s.jsx(Re,{id:O,value:r.privateKey,onChange:a=>d(i=>({...i,privateKey:a.target.value})),className:"h-28 font-mono text-xs",placeholder:t("device.privateKeyPlaceholder")})]}),s.jsxs("div",{className:"space-y-1.5",children:[u(B,t("device.passphrase")),s.jsx(x,{id:B,type:"password",value:r.privateKeyPassphrase,onChange:a=>d(i=>({...i,privateKeyPassphrase:a.target.value}))})]})]}),r.authMode==="configRef"&&s.jsxs("div",{className:"space-y-1.5",children:[u(`${e}-device-ssh-config-ref`,t("device.authConfigRef"),!0),s.jsx(x,{id:`${e}-device-ssh-config-ref`,"data-testid":"device-ssh-config-ref-input",type:"text",value:r.sshConfigRef,onChange:a=>d(i=>({...i,sshConfigRef:a.target.value})),placeholder:t("device.sshConfigRefPlaceholder"),"aria-invalid":c&&!r.sshConfigRef.trim()}),s.jsx("p",{className:"text-[11px] text-muted-foreground",children:t("device.sshConfigRefHint")})]})]})]})]})]}),s.jsxs($e,{children:[s.jsx(C,{type:"button",variant:"outline",onClick:m,children:t("common.cancel")}),s.jsx(C,{type:"submit",variant:"default","data-testid":"device-dialog-save",disabled:l,children:t(l?"common.saving":"common.save")})]})]})]})})}function Je(){const{t:e}=b();return s.jsx(s.Fragment,{children:e("sidebar.manageDevices")})}function Ge(){const{t:e}=b(),o=()=>{window.dispatchEvent(new CustomEvent("tmex:open-add-device"))};return s.jsx(C,{variant:"ghost",size:"icon-sm","data-testid":"devices-add",onClick:o,"aria-label":e("sidebar.addDevice"),title:e("sidebar.addDevice"),children:s.jsx(Y,{className:"h-4 w-4"})})}export{Ge as PageActions,Je as PageTitle,Ue as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Y as zn,_ as ut,r as oe,j as h,X as gt,ad as bt,u as ae,c as $n,al as qn,a as mt,B as se,Z as nn}from"./index-
|
|
1
|
+
import{Y as zn,_ as ut,r as oe,j as h,X as gt,ad as bt,u as ae,c as $n,al as qn,a as mt,B as se,Z as nn}from"./index-B3aiK6xC.js";import{r as pt,M as _t}from"./markdown-preview-sViGxElv.js";import{k as ft,d as Ve,l as te,D as Kn,m as Et,f as ht,c as Nt}from"./api-BLIQkwae.js";import{R as yt,s as vt}from"./transfer-toast-BWwT4yFg.js";import"./index-BbHTMCQt.js";/**
|
|
2
2
|
* @license lucide-react v0.564.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Y as ce,u as F,j as e,L as It,M as Ze,z as Lt,r as w,c as Q,B as k,P as ge,a as O,e as M,o as b,am as D,v as De,T as te,A as xe,f as fe,g as pe,h as $t,i as we,k as ye,l as je,m as ve,n as be,C as ae,F as ne,H as ie,I as re,J as Ne,N as Ce,O as Ee,Q as ke,R as Se,U as le,K as B,W as de,al as U,G as Bt,x as xt,a4 as Dt,b as Oe,t as et,bo as $,X as ft,a5 as nt,bp as Ot,bq as _t,aS as zt,br as qt,bs as Kt,bt as Qt,bu as Ut,bv as it,Z as Ht}from"./index-
|
|
1
|
+
import{Y as ce,u as F,j as e,L as It,M as Ze,z as Lt,r as w,c as Q,B as k,P as ge,a as O,e as M,o as b,am as D,v as De,T as te,A as xe,f as fe,g as pe,h as $t,i as we,k as ye,l as je,m as ve,n as be,C as ae,F as ne,H as ie,I as re,J as Ne,N as Ce,O as Ee,Q as ke,R as Se,U as le,K as B,W as de,al as U,G as Bt,x as xt,a4 as Dt,b as Oe,t as et,bo as $,X as ft,a5 as nt,bp as Ot,bq as _t,aS as zt,br as qt,bs as Kt,bt as Qt,bu as Ut,bv as it,Z as Ht}from"./index-B3aiK6xC.js";import{C as H,b as G,c as J,d as pt,a as V}from"./card-LIHKdO48.js";import{e as Vt,h as wt,F as We,i as Wt,j as Gt,D as Jt}from"./api-BLIQkwae.js";import{R as tt,T as Yt,b as Xt,d as Zt}from"./terminal-settings-panel-DCm6ZfTX.js";import{S as yt}from"./send-DjlZMim3.js";import{M as es}from"./markdown-preview-sViGxElv.js";import{T as jt}from"./triangle-alert-D1TuPKVl.js";import"./selection-clipboard-Dq6Zemfd.js";import"./index-BbHTMCQt.js";/**
|
|
2
2
|
* @license lucide-react v0.564.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Y as _,r as N,j as e,X as C,u as k,aI as Y,aJ as ee,aK as te,al as se,aL as ne,aH as F,aM as B,a4 as H,B as y,G as be,M as ve,x as Ne,c as K,N as ye,O as ke,R as Ie,U as X,aN as Ce,aO as Se,V as re,v as Me,ae as _e,a5 as ze,aP as Te,ak as g,d as Ee,aQ as Be,aR as qe,P as $e,aS as Pe,am as Re,ah as Ae}from"./index-
|
|
1
|
+
import{Y as _,r as N,j as e,X as C,u as k,aI as Y,aJ as ee,aK as te,al as se,aL as ne,aH as F,aM as B,a4 as H,B as y,G as be,M as ve,x as Ne,c as K,N as ye,O as ke,R as Ie,U as X,aN as Ce,aO as Se,V as re,v as Me,ae as _e,a5 as ze,aP as Te,ak as g,d as Ee,aQ as Be,aR as qe,P as $e,aS as Pe,am as Re,ah as Ae}from"./index-B3aiK6xC.js";import{M as Fe,r as He}from"./index-BbHTMCQt.js";import{K as Ke,S as Z}from"./send-DjlZMim3.js";import{Z as ae}from"./zap-CCdOD6uR.js";/**
|
|
2
2
|
* @license lucide-react v0.564.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var N=Object.defineProperty;var P=(t,e,o)=>e in t?N(t,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[e]=o;var O=(t,e,o)=>P(t,typeof e!="symbol"?e+"":e,o);import{Y as x}from"./index-
|
|
1
|
+
var N=Object.defineProperty;var P=(t,e,o)=>e in t?N(t,e,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[e]=o;var O=(t,e,o)=>P(t,typeof e!="symbol"?e+"":e,o);import{Y as x}from"./index-B3aiK6xC.js";/**
|
|
2
2
|
* @license lucide-react v0.564.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a0 as ln,a1 as an,a2 as H,a3 as q,a4 as B,a5 as un,a6 as y,a7 as tn,a8 as L,a9 as _,aa as rn,ab as o,ac as on,ad as sn,ae as fn}from"./mermaid.core-
|
|
1
|
+
import{a0 as ln,a1 as an,a2 as H,a3 as q,a4 as B,a5 as un,a6 as y,a7 as tn,a8 as L,a9 as _,aa as rn,ab as o,ac as on,ad as sn,ae as fn}from"./mermaid.core-m9JEGou3.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(on(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,F=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<an)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(fn((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|