ntermqt 0.1.3__py3-none-any.whl → 0.1.5__py3-none-any.whl

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.
nterm/terminal/bridge.py CHANGED
@@ -38,6 +38,16 @@ class TerminalBridge(QObject):
38
38
  paste_requested = pyqtSignal(str) # base64 clipboard content for confirmation
39
39
  paste_confirmed = pyqtSignal() # user confirmed multiline paste
40
40
  paste_cancelled = pyqtSignal() # user cancelled multiline paste
41
+ # Signal to JS (Python -> JavaScript)
42
+ set_capture_state = pyqtSignal(bool, str) # is_capturing, filename
43
+
44
+ # Signal from JS (JavaScript -> Python)
45
+ capture_toggled = pyqtSignal()
46
+
47
+ @pyqtSlot()
48
+ def onCaptureToggle(self):
49
+ """Called from JS when capture menu item clicked."""
50
+ self.capture_toggled.emit()
41
51
 
42
52
  def __init__(self):
43
53
  super().__init__()
@@ -237,10 +237,15 @@
237
237
  <span class="context-menu-shortcut">Ctrl+Shift+V</span>
238
238
  </div>
239
239
  <div class="context-menu-separator"></div>
240
- <div class="context-menu-item" id="ctx-clear">
241
- <span>Clear Terminal</span>
242
- <span class="context-menu-shortcut"></span>
243
- </div>
240
+ <div class="context-menu-item" id="ctx-capture">
241
+ <span id="ctx-capture-text">Start Capture...</span>
242
+ <span class="context-menu-shortcut"></span>
243
+ </div>
244
+ <div class="context-menu-separator"></div>
245
+ <div class="context-menu-item" id="ctx-clear">
246
+ <span>Clear Terminal</span>
247
+ <span class="context-menu-shortcut"></span>
248
+ </div>
244
249
  </div>
245
250
 
246
251
  <script src="xterm.min.js"></script>
@@ -125,6 +125,12 @@
125
125
  contextMenu = document.getElementById('context-menu');
126
126
  const container = document.getElementById('terminal');
127
127
 
128
+ document.getElementById('ctx-capture').addEventListener('click', () => {
129
+ contextMenu.classList.remove('visible');
130
+ if (bridge) {
131
+ bridge.onCaptureToggle();
132
+ }
133
+ });
128
134
  // Show context menu on right-click
129
135
  container.addEventListener('contextmenu', (e) => {
130
136
  e.preventDefault();
@@ -274,7 +280,14 @@
274
280
  function setupBridge() {
275
281
  new QWebChannel(qt.webChannelTransport, function(channel) {
276
282
  bridge = channel.objects.bridge;
277
-
283
+ bridge.set_capture_state.connect(function(isCapturing, filename) {
284
+ const captureText = document.getElementById('ctx-capture-text');
285
+ if (isCapturing) {
286
+ captureText.textContent = 'Stop Capture (' + filename + ')';
287
+ } else {
288
+ captureText.textContent = 'Start Capture...';
289
+ }
290
+ });
278
291
  // Data from Python to terminal - properly decode UTF-8
279
292
  bridge.write_data.connect(function(dataB64) {
280
293
  try {
nterm/terminal/widget.py CHANGED
@@ -6,11 +6,12 @@ from __future__ import annotations
6
6
  import base64
7
7
  import json
8
8
  import logging
9
+ import re
9
10
  from pathlib import Path
10
- from typing import Optional
11
+ from typing import Optional, BinaryIO
11
12
 
12
13
  from PyQt6.QtCore import Qt, QUrl, pyqtSignal, pyqtSlot
13
- from PyQt6.QtWidgets import QWidget, QVBoxLayout, QApplication
14
+ from PyQt6.QtWidgets import QWidget, QVBoxLayout, QApplication, QFileDialog
14
15
  from PyQt6.QtWebEngineWidgets import QWebEngineView
15
16
  from PyQt6.QtWebEngineCore import QWebEngineSettings
16
17
  from PyQt6.QtWebChannel import QWebChannel
@@ -29,6 +30,9 @@ from nterm.resources import resources
29
30
  # Default threshold for multiline paste warning
30
31
  MULTILINE_PASTE_THRESHOLD = 1
31
32
 
33
+ # ANSI escape sequence pattern for stripping from capture logs
34
+ ANSI_ESCAPE = re.compile(rb'\x1b\[[0-9;]*[a-zA-Z]|\x1b\].*?\x07|\x1b\[[\?0-9;]*[hl]')
35
+
32
36
 
33
37
  class TerminalWidget(QWidget):
34
38
  """
@@ -55,6 +59,10 @@ class TerminalWidget(QWidget):
55
59
  self._multiline_threshold = multiline_threshold
56
60
  self._pending_paste: Optional[bytes] = None # held during confirmation
57
61
 
62
+ # Session capture
63
+ self._capture_file: Optional[BinaryIO] = None
64
+ self._capture_path: Optional[Path] = None
65
+
58
66
  self._setup_ui()
59
67
  self._setup_bridge()
60
68
 
@@ -99,6 +107,9 @@ class TerminalWidget(QWidget):
99
107
  self._bridge.paste_confirmed.connect(self._on_paste_confirmed)
100
108
  self._bridge.paste_cancelled.connect(self._on_paste_cancelled)
101
109
 
110
+ # Capture signals
111
+ self._bridge.capture_toggled.connect(self._on_capture_toggle)
112
+
102
113
  # Load terminal HTML
103
114
  try:
104
115
  html_path = resources.get_path("terminal", "resources", "terminal.html")
@@ -130,6 +141,9 @@ class TerminalWidget(QWidget):
130
141
  self._awaiting_reconnect_confirm = False
131
142
  logger.debug("Detached session")
132
143
 
144
+ # Stop any active capture
145
+ self.stop_capture()
146
+
133
147
  def set_theme(self, theme: Theme) -> None:
134
148
  """
135
149
  Apply theme to terminal.
@@ -157,6 +171,11 @@ class TerminalWidget(QWidget):
157
171
  Args:
158
172
  data: Bytes to display
159
173
  """
174
+ # Session capture - strip ANSI escapes for clean text
175
+ if self._capture_file:
176
+ clean = ANSI_ESCAPE.sub(b'', data)
177
+ self._capture_file.write(clean)
178
+
160
179
  if self._ready:
161
180
  data_b64 = base64.b64encode(data).decode('ascii')
162
181
  self._bridge.write_data.emit(data_b64)
@@ -190,6 +209,58 @@ class TerminalWidget(QWidget):
190
209
  if self._ready:
191
210
  self._bridge.hide_overlay.emit()
192
211
 
212
+ # -------------------------------------------------------------------------
213
+ # Session capture
214
+ # -------------------------------------------------------------------------
215
+
216
+ @property
217
+ def is_capturing(self) -> bool:
218
+ """Check if session capture is active."""
219
+ return self._capture_file is not None
220
+
221
+ def start_capture(self, path: Path) -> None:
222
+ """
223
+ Start capturing session output to file.
224
+
225
+ Args:
226
+ path: File path to write captured output
227
+ """
228
+ self.stop_capture() # Close any existing capture
229
+ self._capture_path = path
230
+ self._capture_file = open(path, 'wb')
231
+ self._bridge.set_capture_state.emit(True, path.name)
232
+ logger.info(f"Started capture: {path}")
233
+
234
+ def stop_capture(self) -> None:
235
+ """Stop capturing session output."""
236
+ if self._capture_file:
237
+ self._capture_file.close()
238
+ logger.info(f"Stopped capture: {self._capture_path}")
239
+ self._capture_file = None
240
+ self._capture_path = None
241
+ self._bridge.set_capture_state.emit(False, "")
242
+
243
+ @pyqtSlot()
244
+ def _on_capture_toggle(self):
245
+ """Handle capture menu item click."""
246
+ if self._capture_file:
247
+ self.stop_capture()
248
+ else:
249
+ # Show file save dialog
250
+ default_name = "session.log"
251
+ if self._session:
252
+ # Use hostname if available for default filename
253
+ default_name = f"session_{self._session.hostname}.log" if hasattr(self._session, 'hostname') else "session.log"
254
+
255
+ path, _ = QFileDialog.getSaveFileName(
256
+ self,
257
+ "Save Session Capture",
258
+ str(Path.home() / default_name),
259
+ "Log Files (*.log *.txt);;All Files (*)"
260
+ )
261
+ if path:
262
+ self.start_capture(Path(path))
263
+
193
264
  # -------------------------------------------------------------------------
194
265
  # Clipboard operations
195
266
  # -------------------------------------------------------------------------
nterm/theme/engine.py CHANGED
@@ -564,6 +564,50 @@ class Theme:
564
564
  overlay_text_color="#3c3836",
565
565
  )
566
566
 
567
+ @classmethod
568
+ def nord_hybrid(cls) -> Theme:
569
+ """
570
+ Nord Hybrid theme.
571
+
572
+ Polar Night UI + Snow Storm terminal.
573
+ Dark chrome, soft light terminal (not harsh white).
574
+ """
575
+ return cls(
576
+ name="nord_hybrid",
577
+ terminal_colors={
578
+ "background": "#eceff4",
579
+ "foreground": "#2e3440",
580
+ "cursor": "#2e3440",
581
+ "cursorAccent": "#eceff4",
582
+ "selectionBackground": "#d8dee9",
583
+ "selectionForeground": "#2e3440",
584
+ "black": "#2e3440",
585
+ "red": "#bf616a",
586
+ "green": "#a3be8c",
587
+ "yellow": "#d08770",
588
+ "blue": "#5e81ac",
589
+ "magenta": "#b48ead",
590
+ "cyan": "#88c0d0",
591
+ "white": "#d8dee9",
592
+ "brightBlack": "#4c566a",
593
+ "brightRed": "#bf616a",
594
+ "brightGreen": "#a3be8c",
595
+ "brightYellow": "#ebcb8b",
596
+ "brightBlue": "#81a1c1",
597
+ "brightMagenta": "#b48ead",
598
+ "brightCyan": "#8fbcbb",
599
+ "brightWhite": "#eceff4",
600
+ },
601
+ font_family="JetBrains Mono, Cascadia Code, Consolas, Menlo, monospace",
602
+ font_size=14,
603
+ background_color="#2e3440",
604
+ foreground_color="#d8dee9",
605
+ border_color="#3b4252",
606
+ accent_color="#88c0d0",
607
+ overlay_background="rgba(46, 52, 64, 0.95)",
608
+ overlay_text_color="#eceff4",
609
+ )
610
+
567
611
  @classmethod
568
612
  def gruvbox_hybrid(cls) -> Theme:
569
613
  """
@@ -630,6 +674,7 @@ class ThemeEngine:
630
674
  self._themes["default"] = Theme.default()
631
675
  self._themes["dracula"] = Theme.dracula()
632
676
  self._themes["nord"] = Theme.nord()
677
+ self._themes["nord_hybrid"] = Theme.nord_hybrid()
633
678
  self._themes["solarized_dark"] = Theme.solarized_dark()
634
679
  self._themes["gruvbox_dark"] = Theme.gruvbox_dark()
635
680
  self._themes["gruvbox_light"] = Theme.gruvbox_light()
@@ -0,0 +1,43 @@
1
+ name: nord_hybrid
2
+
3
+ # Nord Hybrid theme
4
+ # Polar Night UI + softer Snow Storm terminal
5
+ # Adjusted palette for better contrast on light background
6
+
7
+ terminal_colors:
8
+ # Softer terminal - nord4 instead of nord6
9
+ background: "#d8dee9"
10
+ foreground: "#2e3440"
11
+ cursor: "#2e3440"
12
+ cursorAccent: "#d8dee9"
13
+ selectionBackground: "#4c566a"
14
+ selectionForeground: "#eceff4"
15
+ # Darkened palette for light background contrast
16
+ black: "#2e3440"
17
+ red: "#a54242"
18
+ green: "#4e6a3d"
19
+ yellow: "#a07040"
20
+ blue: "#3b6186"
21
+ magenta: "#8a4b7c"
22
+ cyan: "#2b7694"
23
+ white: "#4c566a"
24
+ brightBlack: "#3b4252"
25
+ brightRed: "#bf616a"
26
+ brightGreen: "#5c8045"
27
+ brightYellow: "#d08770"
28
+ brightBlue: "#5e81ac"
29
+ brightMagenta: "#b48ead"
30
+ brightCyan: "#4e9a9a"
31
+ brightWhite: "#2e3440"
32
+
33
+ font_family: "JetBrains Mono, Cascadia Code, Consolas, monospace"
34
+ font_size: 14
35
+
36
+ # Polar Night UI chrome (unchanged)
37
+ background_color: "#2e3440"
38
+ foreground_color: "#d8dee9"
39
+ border_color: "#3b4252"
40
+ accent_color: "#88c0d0"
41
+
42
+ overlay_background: "rgba(46, 52, 64, 0.95)"
43
+ overlay_text_color: "#eceff4"
nterm/vault/store.py CHANGED
@@ -295,7 +295,7 @@ class CredentialStore:
295
295
 
296
296
  # Encrypt sensitive fields
297
297
  password_enc = self._encrypt(password) if password else None
298
- ssh_key_enc = self._encrypt(ssh_key) if ssh_key else None
298
+ ssh_key_enc = self._encrypt(ssh_key.strip()) if ssh_key else None
299
299
  ssh_key_pass_enc = self._encrypt(ssh_key_passphrase) if ssh_key_passphrase else None
300
300
 
301
301
  # Serialize lists
@@ -523,8 +523,8 @@ class CredentialStore:
523
523
  updates['password_enc'] = self._encrypt(kwargs['password']) if kwargs['password'] else None
524
524
 
525
525
  if 'ssh_key' in kwargs:
526
- updates['ssh_key_enc'] = self._encrypt(kwargs['ssh_key']) if kwargs['ssh_key'] else None
527
-
526
+ updates['ssh_key_enc'] = self._encrypt(kwargs['ssh_key'].strip()) if kwargs['ssh_key'] else None
527
+
528
528
  if 'ssh_key_passphrase' in kwargs:
529
529
  updates['ssh_key_passphrase_enc'] = self._encrypt(kwargs['ssh_key_passphrase']) if kwargs['ssh_key_passphrase'] else None
530
530
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ntermqt
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Modern SSH terminal widget for PyQt6 with credential vault and jump host support
5
5
  Author: Scott Peterman
6
6
  License: GPL-3.0
@@ -26,22 +26,21 @@ Requires-Dist: paramiko>=3.0.0
26
26
  Requires-Dist: cryptography>=41.0.0
27
27
  Requires-Dist: pyyaml>=6.0
28
28
  Requires-Dist: click>=8.0.0
29
+ Requires-Dist: ipython>=8.0.0
30
+ Requires-Dist: requests>=2.10.0
31
+ Requires-Dist: textfsm>=2.0.0
29
32
  Requires-Dist: pexpect>=4.8.0; sys_platform != "win32"
30
33
  Requires-Dist: pywinpty>=2.0.0; sys_platform == "win32"
31
34
  Provides-Extra: keyring
32
35
  Requires-Dist: keyring>=24.0.0; extra == "keyring"
33
- Provides-Extra: scripting
34
- Requires-Dist: ipython>=8.0.0; extra == "scripting"
35
36
  Provides-Extra: dev
36
37
  Requires-Dist: pytest; extra == "dev"
37
38
  Requires-Dist: black; extra == "dev"
38
39
  Requires-Dist: pyinstaller; extra == "dev"
39
40
  Requires-Dist: build; extra == "dev"
40
41
  Requires-Dist: twine; extra == "dev"
41
- Requires-Dist: ipython>=8.0.0; extra == "dev"
42
42
  Provides-Extra: all
43
43
  Requires-Dist: keyring>=24.0.0; extra == "all"
44
- Requires-Dist: ipython>=8.0.0; extra == "all"
45
44
 
46
45
  # nterm
47
46
 
@@ -59,9 +58,11 @@ Built for managing hundreds of devices through bastion hosts with hardware secur
59
58
 
60
59
  **Terminal**
61
60
  - xterm.js rendering via QWebEngineView — full VT100/ANSI support
62
- - Built-in themes: Catppuccin, Dracula, Nord, Solarized, Gruvbox (dark/light/hybrid)
61
+ - 12 built-in themes: Catppuccin, Dracula, Nord, Solarized, Gruvbox, Enterprise variants
62
+ - Hybrid themes: dark UI chrome with light terminal for readability
63
63
  - Custom YAML themes with independent terminal and UI colors
64
64
  - Tab or window per session — pop sessions to separate windows
65
+ - Session capture to file (clean text, ANSI stripped)
65
66
  - Unicode, emoji, box-drawing characters
66
67
 
67
68
  **Authentication**
@@ -306,19 +307,33 @@ session.connect()
306
307
 
307
308
  ## Themes
308
309
 
309
- ### Built-in
310
+ nterm includes 12 built-in themes covering dark, light, and hybrid styles.
311
+
312
+ ### Built-in Themes
310
313
 
311
314
  ```python
312
- Theme.default() # Catppuccin Mocha
313
- Theme.dracula() # Dracula
314
- Theme.nord() # Nord
315
- Theme.solarized_dark() # Solarized Dark
316
- Theme.gruvbox_dark() # Gruvbox Dark
317
- Theme.gruvbox_light() # Gruvbox Light
318
- Theme.gruvbox_hybrid() # Dark UI + Light terminal
315
+ # Dark themes
316
+ Theme.default() # Catppuccin Mocha
317
+ Theme.dracula() # Dracula
318
+ Theme.nord() # Nord
319
+ Theme.solarized_dark() # Solarized Dark
320
+ Theme.gruvbox_dark() # Gruvbox Dark
321
+ Theme.enterprise_dark() # Microsoft-inspired dark
322
+
323
+ # Light themes
324
+ Theme.gruvbox_light() # Gruvbox Light
325
+ Theme.enterprise_light() # Microsoft-inspired light
326
+ Theme.clean() # Warm paper tones
327
+
328
+ # Hybrid themes (dark UI + light terminal)
329
+ Theme.gruvbox_hybrid() # Gruvbox dark chrome, light terminal
330
+ Theme.nord_hybrid() # Nord polar night chrome, snow storm terminal
331
+ Theme.enterprise_hybrid() # VS Code-style dark/light split
319
332
  ```
320
333
 
321
- ### Custom YAML
334
+ **Hybrid themes** combine a dark application chrome (menus, tabs, sidebars) with a light terminal for maximum readability — ideal for long sessions reviewing configs or logs.
335
+
336
+ ### Custom YAML Themes
322
337
 
323
338
  ```yaml
324
339
  # ~/.nterm/themes/my-theme.yaml
@@ -347,6 +362,19 @@ accent_color: "#7aa2f7"
347
362
 
348
363
  ---
349
364
 
365
+ ## Session Capture
366
+
367
+ Capture session output to a file for documentation, auditing, or extracting config snippets.
368
+
369
+ **Right-click in terminal → Start Capture...** to begin recording. Output is saved as clean text with ANSI escape sequences stripped — ready for grep, diff, or pasting into tickets.
370
+
371
+ - Per-session capture (each tab independent)
372
+ - File dialog for save location
373
+ - Menu shows active capture filename
374
+ - Auto-stops when session closes
375
+
376
+ ---
377
+
350
378
  ## Jump Hosts
351
379
 
352
380
  ```python
@@ -1,5 +1,5 @@
1
1
  nterm/__init__.py,sha256=Liu1bya6xi3NnwO9KLqqlYyLD1eS-2HeEdEpJRc2480,1346
2
- nterm/__main__.py,sha256=X4R51lyR9j3IteX-Bzs1Q-UcbCJFfvcVitaPWDFBdck,33765
2
+ nterm/__main__.py,sha256=sushq7oXsyBk6pLEff7qDSWck7Emk1QxxKLIfPHh0HY,35546
3
3
  nterm/config.py,sha256=19T28opP-rdLRuxXCGP-qrklAlh4HNbXNTyAwveBhu8,4690
4
4
  nterm/resources.py,sha256=SYC8JeF7vVfER93KKRd-tt5b25t0tHTkd7fSJqVDXnI,1447
5
5
  nterm/askpass/__init__.py,sha256=UpJBk0EOm0nkRwMVv7YdIB4v75ZJpSYmNsU_GlgzbUg,495
@@ -12,9 +12,15 @@ nterm/manager/editor.py,sha256=Fn2YWHJ1EwPYrhKhsi4GTBYwRfCYsHsqgKkLY-LQ8JI,8469
12
12
  nterm/manager/io.py,sha256=R5ksWgpEz0VdVCokcgTN5G3PFgp5QYhjjt40OypSWkY,21687
13
13
  nterm/manager/models.py,sha256=cvC2HzCRadNG1EYsnZN4C9YS6uolHGcUGGZtt-wzGF4,12237
14
14
  nterm/manager/settings.py,sha256=r6MTw_9r1Wl2UX_ALpXIuPbDvJ0D91Y8wRKq6Bfr_3g,9210
15
- nterm/manager/tree.py,sha256=D1aLVH7xy9m-V1PSwu-GFW1r6UYd93zyufrO0HBRidE,18996
15
+ nterm/manager/tree.py,sha256=I78wSjkSuyM6903II-XNyPug9saMSODUNBCHCDrq4ls,22397
16
+ nterm/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ nterm/parser/api_help_dialog.py,sha256=qcmgNKjge8xwVNZeKZFu47Zn0SxZjyzE7cv9h91XGxg,16165
18
+ nterm/parser/ntc_download_dialog.py,sha256=TGaMCxKBTIOhGNUoLEJLnD0uAnwYWdbHdb9PRZEY604,14151
19
+ nterm/parser/tfsm_engine.py,sha256=6p4wrNa9tQRuCmWgsR4E3rZTprpLmii5PNjoGpCQBCw,7954
20
+ nterm/parser/tfsm_fire.py,sha256=AHbN6p4HlgcYDjLWb67CF9YfMSTk-3aetMswmEZyRVc,9222
21
+ nterm/parser/tfsm_fire_tester.py,sha256=chIoZMrvjAmtayuqdRC9FEHKihLKV4rSYrOVO2QdnQQ,85804
16
22
  nterm/scripting/__init__.py,sha256=4WvwvJfJNMwXW6jas8wFreIzKBgjvAhMQnR2cnA_mEE,967
17
- nterm/scripting/api.py,sha256=O-EyV0ksj7LATMSSPrDJShE3x4JPuEBs0SsPZdc2yUo,13931
23
+ nterm/scripting/api.py,sha256=WEx8jNACyM3rdOC3RJJelMK-leBIUhQxEK-Gzp3sroE,46609
18
24
  nterm/scripting/cli.py,sha256=W2DK4ZnuutaArye_to7CBchg0ogClURxVbGsMdnj1y0,9187
19
25
  nterm/session/__init__.py,sha256=FkgHF1WPz78JBOWHSC7LLynG2NqoR6aanNTRlEzsO6I,1612
20
26
  nterm/session/askpass_ssh.py,sha256=U-frmLBIXwE2L5ZCEtai91G1dVRSWKLCtxn88t_PqGs,14083
@@ -24,17 +30,17 @@ nterm/session/local_terminal.py,sha256=sG2lFAOpItMiT93dYCi05nrGRS-MB52XG4J-iZbco
24
30
  nterm/session/pty_transport.py,sha256=QwSFqKKuJhgcLWzv1CUKf3aCGDGbbkmmGwIB1L1A2PU,17176
25
31
  nterm/session/ssh.py,sha256=sGOxjBa9FX6GjVwkmfiKsupoLVsrPVk-LSREjlNmAdE,20942
26
32
  nterm/terminal/__init__.py,sha256=uFnG366Z166pK-ijT1dZanVSSFVZCiMGeNKXvss_sDg,184
27
- nterm/terminal/bridge.py,sha256=FSZMArlq-7a3IsKUrOL42MZeDJ4FfdZwC5UTRk1xryc,2860
28
- nterm/terminal/widget.py,sha256=snUBsH4W0njPogGk3TJYJuvye3YCL1GJSt3cV2YFCeI,13165
29
- nterm/terminal/resources/terminal.html,sha256=LNtXx19SVANjObNydWoAqkBJloKz_bt0kbN41Z7EFxI,7778
30
- nterm/terminal/resources/terminal.js,sha256=wZqVhEu-_KASGfDo-s3nmVZKhupI2r-Ak_poIn_1FU8,13224
33
+ nterm/terminal/bridge.py,sha256=mSkxZr3UGyaFI14w08dzekCkOhfUetq0GIjrBtA3qI0,3199
34
+ nterm/terminal/widget.py,sha256=mxUrQxFmigNR6S3vgnzHahTRGYQI2bNYTBqNg47yaR8,15716
35
+ nterm/terminal/resources/terminal.html,sha256=1onb3qUdDa0qzETR8XaKx0UR6BPlCm_ZpMFVgt36ZPA,7985
36
+ nterm/terminal/resources/terminal.js,sha256=zW9n1MRujSXv66ENgU-gzk_mc75EpWye_f88ejChSW4,13852
31
37
  nterm/terminal/resources/xterm-addon-fit.min.js,sha256=x45XlcZIes3ySrQ2eY1KnOw4SBAbKBvGWwYfOdtxS-E,1789
32
38
  nterm/terminal/resources/xterm-addon-unicode11.min.js,sha256=_sT7CbMSksBfUPmKZYj29IDjq7LMjiwciFs0iGNomBM,7500
33
39
  nterm/terminal/resources/xterm-addon-web-links.min.js,sha256=_iizzOZ3_DRg6y7iu111muLnWVW8bzC9V6_EAPu0hK8,3219
34
40
  nterm/terminal/resources/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
35
41
  nterm/terminal/resources/xterm.min.js,sha256=_B3TGyIePl-SlIbgeoC0d6iq-dzitPnD_-fdJfNwZV0,283670
36
42
  nterm/theme/__init__.py,sha256=ZTywoJliQcFre0Gh7I30n-_7RrPmdR1NHnE4wSkSCsQ,130
37
- nterm/theme/engine.py,sha256=e1mh8JQeErqc59d1-rbcsbVvz86_BEZCrtDapDjQOyk,24718
43
+ nterm/theme/engine.py,sha256=0C3K9hoFOdEVJv3xJXmPs1DPGT2mSVJNtA0dDm4w-uA,26340
38
44
  nterm/theme/stylesheet.py,sha256=Ycy-y_kiP-SLcQFrAEdJtbSDtKm4yvBfxEe-N26qlDg,9004
39
45
  nterm/theme/themes/clean.yaml,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
46
  nterm/theme/themes/default.yaml,sha256=niUrI_K8fayPCZDy1gc3hueLtkWjfmm1p1R33JjYgS4,810
@@ -45,15 +51,16 @@ nterm/theme/themes/enterprise_light.yaml,sha256=Q6H5lSsStoFVJNFS63IPp0FaBhkjN9uB
45
51
  nterm/theme/themes/gruvbox_dark.yaml,sha256=cAr-67R7QhW80ncHptpyyrZuUqD65xoSuLtmHeDgQM0,815
46
52
  nterm/theme/themes/gruvbox_hybrid.yaml,sha256=Ml7Ed3sTBjcSYVJ9t961KhiG3DwMAdVdRBtzI4eWZg0,936
47
53
  nterm/theme/themes/gruvbox_light.yaml,sha256=InqYF-TsLLIzhCHpSSHqSxnest5tu28htQ4AaFN4BFY,820
54
+ nterm/theme/themes/nord_hybrid.yaml,sha256=QAT056Jo2UAdQPmbc3GezjpD7Mge-GQSl4wPeSiaqSE,1065
48
55
  nterm/vault/__init__.py,sha256=e1W3GZKOf0FXNerSp1mojl-yaidYIsygnRwTGBd6mfM,708
49
56
  nterm/vault/credential_manager.py,sha256=TWAMfjpntPXEJ-4AauDz2PPS0q140sUebFk8AjvC-A0,5347
50
57
  nterm/vault/keychain.py,sha256=_2-yUhc2ro-An2zvFlJHYyxozM55iJ4bSseOVKMCNGo,4229
51
58
  nterm/vault/manager_ui.py,sha256=qle-W40j6L_pOR0AaOCeyU8myizFTRkISNrloCn0H_Y,34530
52
59
  nterm/vault/profile.py,sha256=qM9TJf68RKdjtxo-sJehO7wS4iTi2G26BKbmlmHLA5M,6246
53
60
  nterm/vault/resolver.py,sha256=GWB2YR9H1MH98RGQBKvitIsjWT_-wSMLuddZNz4wbns,7800
54
- nterm/vault/store.py,sha256=fbmABHWRjkZ5t42O7r74D3B_R2mZ0WPY8STPo3fGMdw,21191
55
- ntermqt-0.1.3.dist-info/METADATA,sha256=oP3lHksgZAXVWTV3GL3e5c3s8snzr1d_0meieLh-xqA,12344
56
- ntermqt-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- ntermqt-0.1.3.dist-info/entry_points.txt,sha256=Gunr-_3w-aSpfqoMuGKM2PJSCRo9hZ7K1BksUtp1yd8,130
58
- ntermqt-0.1.3.dist-info/top_level.txt,sha256=bZdnNLTHNRNqo9jsOQGUWF7h5st0xW_thH0n2QOxWUo,6
59
- ntermqt-0.1.3.dist-info/RECORD,,
61
+ nterm/vault/store.py,sha256=_0Lfe0WKjm3uSAtxgn9qAPlpBOLCuq9SVgzqsE_qaGQ,21199
62
+ ntermqt-0.1.5.dist-info/METADATA,sha256=CRqoeB5fr5f9j9WouRuQcpx4gjME8CZs9r_PHcEDmho,13495
63
+ ntermqt-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
64
+ ntermqt-0.1.5.dist-info/entry_points.txt,sha256=Gunr-_3w-aSpfqoMuGKM2PJSCRo9hZ7K1BksUtp1yd8,130
65
+ ntermqt-0.1.5.dist-info/top_level.txt,sha256=bZdnNLTHNRNqo9jsOQGUWF7h5st0xW_thH0n2QOxWUo,6
66
+ ntermqt-0.1.5.dist-info/RECORD,,