tmex-cli 0.6.6 → 0.6.8

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.
@@ -20666,7 +20666,17 @@ Time: {{time}}`,
20666
20666
  },
20667
20667
  window: {
20668
20668
  noWindows: "No windows",
20669
- new: "New Window"
20669
+ new: "New Window",
20670
+ close: "Close window",
20671
+ closePane: "Close pane",
20672
+ closeConfirmTitle: "Close this window?",
20673
+ closePaneConfirmTitle: "Close this pane?",
20674
+ closeConfirmDesc: 'Processes running in "{{name}}" will be terminated. This action cannot be undone.',
20675
+ menu: "Window actions",
20676
+ rename: "Rename window",
20677
+ renamePlaceholder: "Enter a name",
20678
+ renameDesc: "The custom name overrides the title set by the terminal and is kept until the gateway restarts.",
20679
+ renameReset: "Use automatic name"
20670
20680
  },
20671
20681
  validation: {
20672
20682
  deviceNameRequired: "Device name is required",
@@ -21031,7 +21041,17 @@ Bot\uFF1A{{botName}}
21031
21041
  },
21032
21042
  window: {
21033
21043
  noWindows: "\u6682\u65E0\u7A97\u53E3",
21034
- new: "\u65B0\u5EFA\u7A97\u53E3"
21044
+ new: "\u65B0\u5EFA\u7A97\u53E3",
21045
+ close: "\u5173\u95ED\u7A97\u53E3",
21046
+ closePane: "\u5173\u95ED\u9762\u677F",
21047
+ closeConfirmTitle: "\u5173\u95ED\u6B64\u7A97\u53E3\uFF1F",
21048
+ closePaneConfirmTitle: "\u5173\u95ED\u6B64\u9762\u677F\uFF1F",
21049
+ closeConfirmDesc: '"{{name}}" \u4E2D\u8FD0\u884C\u7684\u8FDB\u7A0B\u5C06\u88AB\u7EC8\u6B62\uFF0C\u6B64\u64CD\u4F5C\u65E0\u6CD5\u64A4\u9500\u3002',
21050
+ menu: "\u7A97\u53E3\u64CD\u4F5C",
21051
+ rename: "\u91CD\u547D\u540D\u7A97\u53E3",
21052
+ renamePlaceholder: "\u8F93\u5165\u540D\u79F0",
21053
+ renameDesc: "\u81EA\u5B9A\u4E49\u540D\u79F0\u4F1A\u8986\u76D6\u7EC8\u7AEF\u8BBE\u7F6E\u7684\u6807\u9898\uFF0C\u5E76\u4FDD\u7559\u81F3 gateway \u91CD\u542F\u3002",
21054
+ renameReset: "\u6062\u590D\u81EA\u52A8\u540D\u79F0"
21035
21055
  },
21036
21056
  validation: {
21037
21057
  deviceNameRequired: "\u8BBE\u5907\u540D\u79F0\u4E3A\u5FC5\u586B\u9879",
@@ -21396,7 +21416,17 @@ Bot\uFF1A{{botName}}
21396
21416
  },
21397
21417
  window: {
21398
21418
  noWindows: "\u30A6\u30A3\u30F3\u30C9\u30A6\u304C\u3042\u308A\u307E\u305B\u3093",
21399
- new: "\u65B0\u898F\u30A6\u30A3\u30F3\u30C9\u30A6"
21419
+ new: "\u65B0\u898F\u30A6\u30A3\u30F3\u30C9\u30A6",
21420
+ close: "\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u9589\u3058\u308B",
21421
+ closePane: "\u30DA\u30A4\u30F3\u3092\u9589\u3058\u308B",
21422
+ closeConfirmTitle: "\u3053\u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u9589\u3058\u307E\u3059\u304B\uFF1F",
21423
+ closePaneConfirmTitle: "\u3053\u306E\u30DA\u30A4\u30F3\u3092\u9589\u3058\u307E\u3059\u304B\uFF1F",
21424
+ closeConfirmDesc: '"{{name}}" \u3067\u5B9F\u884C\u4E2D\u306E\u30D7\u30ED\u30BB\u30B9\u306F\u7D42\u4E86\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u64CD\u4F5C\u306F\u53D6\u308A\u6D88\u305B\u307E\u305B\u3093\u3002',
21425
+ menu: "\u30A6\u30A3\u30F3\u30C9\u30A6\u64CD\u4F5C",
21426
+ rename: "\u30A6\u30A3\u30F3\u30C9\u30A6\u540D\u3092\u5909\u66F4",
21427
+ renamePlaceholder: "\u540D\u524D\u3092\u5165\u529B",
21428
+ renameDesc: "\u30AB\u30B9\u30BF\u30E0\u540D\u306F\u30BF\u30FC\u30DF\u30CA\u30EB\u304C\u8A2D\u5B9A\u3057\u305F\u30BF\u30A4\u30C8\u30EB\u3092\u4E0A\u66F8\u304D\u3057\u3001\u30B2\u30FC\u30C8\u30A6\u30A7\u30A4\u304C\u518D\u8D77\u52D5\u3059\u308B\u307E\u3067\u4FDD\u6301\u3055\u308C\u307E\u3059\u3002",
21429
+ renameReset: "\u81EA\u52D5\u540D\u306B\u623B\u3059"
21400
21430
  },
21401
21431
  validation: {
21402
21432
  deviceNameRequired: "\u30C7\u30D0\u30A4\u30B9\u540D\u306F\u5FC5\u9808\u3067\u3059",
@@ -21442,6 +21472,7 @@ __export(exports_ws_borsh, {
21442
21472
  MAX_CHUNK_STREAMS: () => MAX_CHUNK_STREAMS,
21443
21473
  MAX_CHUNKS_PER_MESSAGE: () => MAX_CHUNKS_PER_MESSAGE,
21444
21474
  MAGIC: () => MAGIC,
21475
+ KIND_TMUX_SET_WINDOW_STYLE: () => KIND_TMUX_SET_WINDOW_STYLE,
21445
21476
  KIND_TMUX_SELECT_WINDOW: () => KIND_TMUX_SELECT_WINDOW,
21446
21477
  KIND_TMUX_SELECT: () => KIND_TMUX_SELECT,
21447
21478
  KIND_TMUX_RENAME_WINDOW: () => KIND_TMUX_RENAME_WINDOW,
@@ -21515,6 +21546,7 @@ var KIND_TMUX_RENAME_WINDOW = 518;
21515
21546
  var KIND_TMUX_EVENT = 519;
21516
21547
  var KIND_STATE_SNAPSHOT = 520;
21517
21548
  var KIND_STATE_SNAPSHOT_DIFF = 521;
21549
+ var KIND_TMUX_SET_WINDOW_STYLE = 522;
21518
21550
  var KIND_TERM_INPUT = 769;
21519
21551
  var KIND_TERM_PASTE = 770;
21520
21552
  var KIND_TERM_RESIZE = 771;
@@ -21544,6 +21576,7 @@ var VALID_KINDS = new Set([
21544
21576
  KIND_TMUX_EVENT,
21545
21577
  KIND_STATE_SNAPSHOT,
21546
21578
  KIND_STATE_SNAPSHOT_DIFF,
21579
+ KIND_TMUX_SET_WINDOW_STYLE,
21547
21580
  KIND_TERM_INPUT,
21548
21581
  KIND_TERM_PASTE,
21549
21582
  KIND_TERM_RESIZE,
@@ -21578,6 +21611,7 @@ function kindToString(kind) {
21578
21611
  [KIND_TMUX_EVENT]: "TMUX_EVENT",
21579
21612
  [KIND_STATE_SNAPSHOT]: "STATE_SNAPSHOT",
21580
21613
  [KIND_STATE_SNAPSHOT_DIFF]: "STATE_SNAPSHOT_DIFF",
21614
+ [KIND_TMUX_SET_WINDOW_STYLE]: "TMUX_SET_WINDOW_STYLE",
21581
21615
  [KIND_TERM_INPUT]: "TERM_INPUT",
21582
21616
  [KIND_TERM_PASTE]: "TERM_PASTE",
21583
21617
  [KIND_TERM_RESIZE]: "TERM_RESIZE",
@@ -21639,6 +21673,7 @@ __export(exports_schema, {
21639
21673
  WindowCloseEventSchema: () => WindowCloseEventSchema,
21640
21674
  WindowAddEventSchema: () => WindowAddEventSchema,
21641
21675
  WindowActiveEventSchema: () => WindowActiveEventSchema,
21676
+ TmuxSetWindowStyleSchema: () => TmuxSetWindowStyleSchema,
21642
21677
  TmuxSelectWindowSchema: () => TmuxSelectWindowSchema,
21643
21678
  TmuxSelectSchema: () => TmuxSelectSchema,
21644
21679
  TmuxRenameWindowSchema: () => TmuxRenameWindowSchema,
@@ -21765,6 +21800,10 @@ var TmuxRenameWindowSchema = import_zorsh.b.struct({
21765
21800
  windowId: import_zorsh.b.string(),
21766
21801
  name: import_zorsh.b.string()
21767
21802
  });
21803
+ var TmuxSetWindowStyleSchema = import_zorsh.b.struct({
21804
+ deviceId: import_zorsh.b.string(),
21805
+ style: import_zorsh.b.string()
21806
+ });
21768
21807
  var TmuxEventSchema = import_zorsh.b.struct({
21769
21808
  deviceId: import_zorsh.b.string(),
21770
21809
  eventType: import_zorsh.b.u8(),
@@ -21836,6 +21875,7 @@ var PaneWireSchema = import_zorsh.b.struct({
21836
21875
  var WindowWireSchema = import_zorsh.b.struct({
21837
21876
  id: import_zorsh.b.string(),
21838
21877
  name: import_zorsh.b.string(),
21878
+ customName: OptionStringSchema,
21839
21879
  index: import_zorsh.b.u16(),
21840
21880
  active: import_zorsh.b.bool(),
21841
21881
  panes: import_zorsh.b.vec(PaneWireSchema)
@@ -22256,6 +22296,7 @@ function encodeWindowWire(window2) {
22256
22296
  return {
22257
22297
  id: window2.id,
22258
22298
  name: window2.name,
22299
+ customName: window2.customName ?? null,
22259
22300
  index: window2.index,
22260
22301
  active: window2.active,
22261
22302
  panes: window2.panes.map(encodePaneWire)
@@ -22382,6 +22423,7 @@ function decodeWindowWire(wire) {
22382
22423
  return {
22383
22424
  id: wire.id,
22384
22425
  name: wire.name,
22426
+ customName: wire.customName ?? undefined,
22385
22427
  index: wire.index,
22386
22428
  active: wire.active,
22387
22429
  panes: wire.panes.map(decodePaneWire)
@@ -53401,7 +53443,7 @@ function resolveTmuxWindowStyle(value) {
53401
53443
  return null;
53402
53444
  }
53403
53445
  if (!WINDOW_STYLE_PATTERN.test(style)) {
53404
- console.warn(`[tmex] ignoring invalid TMEX_TMUX_WINDOW_STYLE: ${style}`);
53446
+ console.warn(`[tmex] ignoring invalid tmux window-style: ${style}`);
53405
53447
  return null;
53406
53448
  }
53407
53449
  return style;
@@ -53619,6 +53661,17 @@ class LocalExternalTmuxConnection {
53619
53661
  this.callbacks.onError(error);
53620
53662
  });
53621
53663
  }
53664
+ setWindowStyle(style) {
53665
+ if (!this.connected) {
53666
+ return;
53667
+ }
53668
+ if (!resolveTmuxWindowStyle(config.tmuxWindowStyle)) {
53669
+ return;
53670
+ }
53671
+ this.configureWindowStyle(style).catch((error) => {
53672
+ this.callbacks.onError(error);
53673
+ });
53674
+ }
53622
53675
  async ensureSession() {
53623
53676
  const exists3 = await this.runTmuxAllowFailure(["has-session", "-t", this.sessionName]);
53624
53677
  if (exists3.exitCode === 0) {
@@ -53680,8 +53733,8 @@ class LocalExternalTmuxConnection {
53680
53733
  ]);
53681
53734
  await this.configureWindowStyle();
53682
53735
  }
53683
- async configureWindowStyle() {
53684
- const windowStyle = resolveTmuxWindowStyle(config.tmuxWindowStyle);
53736
+ async configureWindowStyle(styleValue = config.tmuxWindowStyle) {
53737
+ const windowStyle = resolveTmuxWindowStyle(styleValue);
53685
53738
  if (!windowStyle) {
53686
53739
  return;
53687
53740
  }
@@ -53985,10 +54038,11 @@ class LocalExternalTmuxConnection {
53985
54038
  ]),
53986
54039
  this.runTmuxAllowFailure([
53987
54040
  "list-panes",
54041
+ "-s",
53988
54042
  "-t",
53989
54043
  this.sessionName,
53990
54044
  "-F",
53991
- "#{pane_id}\t#{window_id}\t#{pane_index}\t#{pane_title}\t#{pane_active}\t#{pane_width}\t#{pane_height}"
54045
+ "#{pane_id}\t#{window_id}\t#{pane_index}\t#{pane_title}\t#{pane_active}\t#{pane_width}\t#{pane_height}\t#{window_active}"
53992
54046
  ])
53993
54047
  ]);
53994
54048
  if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
@@ -54060,7 +54114,7 @@ ${panesRes.stderr}`;
54060
54114
  if (!line.trim()) {
54061
54115
  continue;
54062
54116
  }
54063
- const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw] = line.split("\t");
54117
+ const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw, windowActiveRaw] = line.split("\t");
54064
54118
  if (!paneId || !windowId) {
54065
54119
  continue;
54066
54120
  }
@@ -54076,7 +54130,7 @@ ${panesRes.stderr}`;
54076
54130
  width: Number.isNaN(width) ? 0 : width,
54077
54131
  height: Number.isNaN(height) ? 0 : height
54078
54132
  };
54079
- if (pane.active) {
54133
+ if (pane.active && windowActiveRaw === "1") {
54080
54134
  this.activePaneId = paneId;
54081
54135
  this.activeWindowId = windowId;
54082
54136
  }
@@ -54581,12 +54635,13 @@ function splitSnapshotFields(line, fieldCount) {
54581
54635
  if (fieldCount === 4) {
54582
54636
  return [parts[0] ?? "", parts[1] ?? "", parts.slice(2, -1).join(SNAPSHOT_FIELD_SEPARATOR), parts.at(-1) ?? ""];
54583
54637
  }
54584
- if (fieldCount === 7) {
54638
+ if (fieldCount === 8) {
54585
54639
  return [
54586
54640
  parts[0] ?? "",
54587
54641
  parts[1] ?? "",
54588
54642
  parts[2] ?? "",
54589
- parts.slice(3, -3).join(SNAPSHOT_FIELD_SEPARATOR),
54643
+ parts.slice(3, -4).join(SNAPSHOT_FIELD_SEPARATOR),
54644
+ parts.at(-4) ?? "",
54590
54645
  parts.at(-3) ?? "",
54591
54646
  parts.at(-2) ?? "",
54592
54647
  parts.at(-1) ?? ""
@@ -54742,6 +54797,17 @@ class SshExternalTmuxConnection {
54742
54797
  this.callbacks.onError(error);
54743
54798
  });
54744
54799
  }
54800
+ setWindowStyle(style) {
54801
+ if (!this.connected) {
54802
+ return;
54803
+ }
54804
+ if (!resolveTmuxWindowStyle(config.tmuxWindowStyle)) {
54805
+ return;
54806
+ }
54807
+ this.configureWindowStyle(style).catch((error) => {
54808
+ this.callbacks.onError(error);
54809
+ });
54810
+ }
54745
54811
  async connectSshClient() {
54746
54812
  if (!this.device) {
54747
54813
  throw new Error("SSH device not loaded");
@@ -54909,8 +54975,8 @@ class SshExternalTmuxConnection {
54909
54975
  ]);
54910
54976
  await this.configureWindowStyle();
54911
54977
  }
54912
- async configureWindowStyle() {
54913
- const windowStyle = resolveTmuxWindowStyle(config.tmuxWindowStyle);
54978
+ async configureWindowStyle(styleValue = config.tmuxWindowStyle) {
54979
+ const windowStyle = resolveTmuxWindowStyle(styleValue);
54914
54980
  if (!windowStyle) {
54915
54981
  return;
54916
54982
  }
@@ -55185,10 +55251,11 @@ class SshExternalTmuxConnection {
55185
55251
  ]),
55186
55252
  this.runTmuxAllowFailure([
55187
55253
  "list-panes",
55254
+ "-s",
55188
55255
  "-t",
55189
55256
  this.sessionName,
55190
55257
  "-F",
55191
- "#{pane_id}|#{window_id}|#{pane_index}|#{pane_title}|#{pane_active}|#{pane_width}|#{pane_height}"
55258
+ "#{pane_id}|#{window_id}|#{pane_index}|#{pane_title}|#{pane_active}|#{pane_width}|#{pane_height}|#{window_active}"
55192
55259
  ])
55193
55260
  ]);
55194
55261
  if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
@@ -55260,7 +55327,7 @@ ${panesRes.stderr}`;
55260
55327
  if (!line.trim()) {
55261
55328
  continue;
55262
55329
  }
55263
- const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw] = splitSnapshotFields(line, 7);
55330
+ const [paneId, windowId, indexRaw, titleRaw, activeRaw, widthRaw, heightRaw, windowActiveRaw] = splitSnapshotFields(line, 8);
55264
55331
  if (!paneId || !windowId) {
55265
55332
  continue;
55266
55333
  }
@@ -55276,7 +55343,7 @@ ${panesRes.stderr}`;
55276
55343
  width: Number.isNaN(width) ? 0 : width,
55277
55344
  height: Number.isNaN(height) ? 0 : height
55278
55345
  };
55279
- if (pane.active) {
55346
+ if (pane.active && windowActiveRaw === "1") {
55280
55347
  this.activePaneId = paneId;
55281
55348
  this.activeWindowId = windowId;
55282
55349
  }
@@ -55647,6 +55714,9 @@ class DeviceSessionRuntime {
55647
55714
  renameWindow(windowId, name) {
55648
55715
  this.connection.renameWindow(windowId, name);
55649
55716
  }
55717
+ setWindowStyle(style) {
55718
+ this.connection.setWindowStyle(style);
55719
+ }
55650
55720
  broadcast(action) {
55651
55721
  for (const listener of this.listeners) {
55652
55722
  try {
@@ -57279,6 +57349,7 @@ var defaultDeps2 = {
57279
57349
  class WebSocketServer {
57280
57350
  connections = new Map;
57281
57351
  pendingConnectionEntries = new Map;
57352
+ windowCustomNames = new Map;
57282
57353
  deps;
57283
57354
  constructor(options = {}) {
57284
57355
  this.deps = {
@@ -57511,6 +57582,11 @@ class WebSocketServer {
57511
57582
  this.handleRenameWindow(decoded.deviceId, decoded.windowId, decoded.name);
57512
57583
  return;
57513
57584
  }
57585
+ case exports_ws_borsh.KIND_TMUX_SET_WINDOW_STYLE: {
57586
+ const decoded = exports_ws_borsh.decodePayload(exports_ws_borsh.schema.TmuxSetWindowStyleSchema, payload);
57587
+ this.handleSetWindowStyle(decoded.deviceId, decoded.style);
57588
+ return;
57589
+ }
57514
57590
  case exports_ws_borsh.KIND_TERM_INPUT: {
57515
57591
  const decoded = exports_ws_borsh.decodePayload(exports_ws_borsh.schema.TermInputSchema, payload);
57516
57592
  if (decoded.isComposing)
@@ -57638,7 +57714,7 @@ class WebSocketServer {
57638
57714
  });
57639
57715
  this.sendEnvelope(ws, exports_ws_borsh.KIND_DEVICE_CONNECTED, connectedPayload);
57640
57716
  if (entry.lastSnapshot) {
57641
- const snapshotBytes = exports_ws_borsh.encodeStateSnapshot(entry.lastSnapshot);
57717
+ const snapshotBytes = exports_ws_borsh.encodeStateSnapshot(this.applyWindowCustomNames(entry.lastSnapshot));
57642
57718
  this.sendChunked(ws, exports_ws_borsh.KIND_STATE_SNAPSHOT, snapshotBytes);
57643
57719
  } else {
57644
57720
  entry.runtime.requestSnapshot();
@@ -57742,10 +57818,52 @@ class WebSocketServer {
57742
57818
  entry.runtime.closePane(paneId);
57743
57819
  }
57744
57820
  handleRenameWindow(deviceId, windowId, name) {
57821
+ const trimmed = name.trim().slice(0, 64);
57822
+ const names = this.windowCustomNames.get(deviceId);
57823
+ if (!trimmed) {
57824
+ names?.delete(windowId);
57825
+ } else if (names) {
57826
+ names.set(windowId, trimmed);
57827
+ } else {
57828
+ this.windowCustomNames.set(deviceId, new Map([[windowId, trimmed]]));
57829
+ }
57830
+ const entry = this.connections.get(deviceId);
57831
+ if (!entry?.lastSnapshot)
57832
+ return;
57833
+ this.sendSnapshotToClients(entry, entry.lastSnapshot);
57834
+ }
57835
+ handleSetWindowStyle(deviceId, style) {
57745
57836
  const entry = this.connections.get(deviceId);
57746
57837
  if (!entry)
57747
57838
  return;
57748
- entry.runtime.renameWindow(windowId, name);
57839
+ entry.runtime.setWindowStyle(style);
57840
+ }
57841
+ applyWindowCustomNames(payload) {
57842
+ const names = this.windowCustomNames.get(payload.deviceId);
57843
+ if (!names?.size || !payload.session)
57844
+ return payload;
57845
+ const liveWindowIds = new Set(payload.session.windows.map((w) => w.id));
57846
+ for (const windowId of names.keys()) {
57847
+ if (!liveWindowIds.has(windowId)) {
57848
+ names.delete(windowId);
57849
+ }
57850
+ }
57851
+ return {
57852
+ ...payload,
57853
+ session: {
57854
+ ...payload.session,
57855
+ windows: payload.session.windows.map((window2) => {
57856
+ const customName = names.get(window2.id);
57857
+ return customName ? { ...window2, customName } : window2;
57858
+ })
57859
+ }
57860
+ };
57861
+ }
57862
+ sendSnapshotToClients(entry, payload) {
57863
+ const payloadBytes = exports_ws_borsh.encodeStateSnapshot(this.applyWindowCustomNames(payload));
57864
+ for (const client of entry.clients) {
57865
+ this.sendChunked(client, exports_ws_borsh.KIND_STATE_SNAPSHOT, payloadBytes);
57866
+ }
57749
57867
  }
57750
57868
  async createDeviceConnectionEntry(deviceId, ws) {
57751
57869
  let runtime = null;
@@ -57864,10 +57982,7 @@ class WebSocketServer {
57864
57982
  if (!entry)
57865
57983
  return;
57866
57984
  entry.lastSnapshot = payload;
57867
- const payloadBytes = exports_ws_borsh.encodeStateSnapshot(payload);
57868
- for (const client of entry.clients) {
57869
- this.sendChunked(client, exports_ws_borsh.KIND_STATE_SNAPSHOT, payloadBytes);
57870
- }
57985
+ this.sendSnapshotToClients(entry, payload);
57871
57986
  }
57872
57987
  broadcastTerminalOutput(deviceId, paneId, data) {
57873
57988
  const entry = this.connections.get(deviceId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmex-cli",
3
- "version": "0.6.6",
3
+ "version": "0.6.8",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tmex": "./bin/tmex.js",