@tiphareth/dsh-hardssh 0.1.2-alpha

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.
Files changed (165) hide show
  1. package/README.md +50 -0
  2. package/cordis.patch.yml +26 -0
  3. package/lib/client.js +17794 -0
  4. package/lib/environment-BL1jddfB.js +449 -0
  5. package/lib/fs.js +478 -0
  6. package/lib/index.js +6758 -0
  7. package/lib/subprocess.js +600 -0
  8. package/lib/switch-fs-CAJpFY9C.js +193 -0
  9. package/lib/switch-fs-RrZtG2gv.js +210 -0
  10. package/lib/types/backend.d.ts +108 -0
  11. package/lib/types/base/capability.d.ts +107 -0
  12. package/lib/types/base/index.d.ts +18 -0
  13. package/lib/types/base/ledger-router.d.ts +48 -0
  14. package/lib/types/base/ledger.d.ts +82 -0
  15. package/lib/types/base/model.d.ts +108 -0
  16. package/lib/types/base/namespace.d.ts +57 -0
  17. package/lib/types/base/plugin.d.ts +102 -0
  18. package/lib/types/base/registry.d.ts +60 -0
  19. package/lib/types/base/router.d.ts +40 -0
  20. package/lib/types/client/api.d.ts +85 -0
  21. package/lib/types/client/directory-flow.d.ts +82 -0
  22. package/lib/types/client/icons.d.ts +19 -0
  23. package/lib/types/client/index.d.ts +34 -0
  24. package/lib/types/client/locales.d.ts +104 -0
  25. package/lib/types/client/manager-button.d.ts +32 -0
  26. package/lib/types/client/migrate.d.ts +20 -0
  27. package/lib/types/client/ssh/api.d.ts +89 -0
  28. package/lib/types/client/ssh/apply.d.ts +23 -0
  29. package/lib/types/client/ssh/locales.d.ts +156 -0
  30. package/lib/types/client/ssh/mount.d.ts +13 -0
  31. package/lib/types/client/ssh/panel/ClusterTab.d.ts +8 -0
  32. package/lib/types/client/ssh/panel/HostFingerprintDialog.d.ts +16 -0
  33. package/lib/types/client/ssh/panel/HostFormDialog.d.ts +13 -0
  34. package/lib/types/client/ssh/panel/HostsTab.d.ts +10 -0
  35. package/lib/types/client/ssh/panel/SessionSecretDialog.d.ts +16 -0
  36. package/lib/types/client/ssh/panel/SshPanel.d.ts +14 -0
  37. package/lib/types/client/ssh/panel/TerminalTab.d.ts +12 -0
  38. package/lib/types/client/ssh/panel/TransferTab.d.ts +8 -0
  39. package/lib/types/client/ssh/panel/TunnelsTab.d.ts +8 -0
  40. package/lib/types/client/ssh/panel/controller.d.ts +23 -0
  41. package/lib/types/client/ssh/panel/helpers.d.ts +15 -0
  42. package/lib/types/client/ssh/panel/xterm.css.d.ts +3 -0
  43. package/lib/types/client/ssh/sidebar-entry.d.ts +25 -0
  44. package/lib/types/client/state.d.ts +32 -0
  45. package/lib/types/client/text.d.ts +11 -0
  46. package/lib/types/client/workspace-badges.d.ts +38 -0
  47. package/lib/types/client/workspace-gate.d.ts +15 -0
  48. package/lib/types/client-http.d.ts +15 -0
  49. package/lib/types/core.d.ts +43 -0
  50. package/lib/types/fs.d.ts +36 -0
  51. package/lib/types/host-http.d.ts +25 -0
  52. package/lib/types/index.d.ts +53 -0
  53. package/lib/types/ledger.d.ts +132 -0
  54. package/lib/types/protocol.d.ts +101 -0
  55. package/lib/types/providers/index.d.ts +19 -0
  56. package/lib/types/providers/local/provider.d.ts +58 -0
  57. package/lib/types/providers/ssh/provider.d.ts +112 -0
  58. package/lib/types/remote/environment.d.ts +29 -0
  59. package/lib/types/remote/output.d.ts +38 -0
  60. package/lib/types/remote/remote-fs.d.ts +69 -0
  61. package/lib/types/remote/remote-process.d.ts +41 -0
  62. package/lib/types/remote/remote-subprocess.d.ts +31 -0
  63. package/lib/types/remote/remote-terminal.d.ts +41 -0
  64. package/lib/types/remote-runner.d.ts +83 -0
  65. package/lib/types/remote-search.d.ts +50 -0
  66. package/lib/types/routes.d.ts +24 -0
  67. package/lib/types/runtime/workspace-core.d.ts +59 -0
  68. package/lib/types/seam-state.d.ts +69 -0
  69. package/lib/types/shell.d.ts +8 -0
  70. package/lib/types/ssh/connection/lease.d.ts +16 -0
  71. package/lib/types/ssh/connection/pool.d.ts +57 -0
  72. package/lib/types/ssh/engine.d.ts +434 -0
  73. package/lib/types/ssh/exec/output.d.ts +31 -0
  74. package/lib/types/ssh/known-hosts.d.ts +89 -0
  75. package/lib/types/ssh/plugin.d.ts +57 -0
  76. package/lib/types/ssh/protocol.d.ts +236 -0
  77. package/lib/types/ssh/routes.d.ts +44 -0
  78. package/lib/types/ssh/store.d.ts +107 -0
  79. package/lib/types/ssh/tools.d.ts +35 -0
  80. package/lib/types/ssh/transfer/progress.d.ts +14 -0
  81. package/lib/types/ssh/vault.d.ts +110 -0
  82. package/lib/types/subprocess.d.ts +32 -0
  83. package/lib/types/switch/switch-fs.d.ts +88 -0
  84. package/lib/types/switch/switch-subprocess.d.ts +34 -0
  85. package/lib/types/tools.d.ts +12 -0
  86. package/package.json +142 -0
  87. package/src/backend.ts +624 -0
  88. package/src/base/capability.ts +86 -0
  89. package/src/base/index.ts +18 -0
  90. package/src/base/ledger-router.ts +128 -0
  91. package/src/base/ledger.ts +299 -0
  92. package/src/base/model.ts +118 -0
  93. package/src/base/namespace.ts +102 -0
  94. package/src/base/plugin.ts +170 -0
  95. package/src/base/registry.ts +109 -0
  96. package/src/base/router.ts +43 -0
  97. package/src/client/api.ts +196 -0
  98. package/src/client/css-modules.d.ts +5 -0
  99. package/src/client/directory-flow.tsx +482 -0
  100. package/src/client/icons.tsx +50 -0
  101. package/src/client/index.ts +210 -0
  102. package/src/client/locales.ts +105 -0
  103. package/src/client/manager-button.tsx +269 -0
  104. package/src/client/migrate.ts +109 -0
  105. package/src/client/ssh/api.ts +411 -0
  106. package/src/client/ssh/apply.ts +50 -0
  107. package/src/client/ssh/locales.ts +322 -0
  108. package/src/client/ssh/mount.tsx +83 -0
  109. package/src/client/ssh/panel/ClusterTab.tsx +123 -0
  110. package/src/client/ssh/panel/HostFingerprintDialog.tsx +82 -0
  111. package/src/client/ssh/panel/HostFormDialog.tsx +228 -0
  112. package/src/client/ssh/panel/HostsTab.tsx +236 -0
  113. package/src/client/ssh/panel/SessionSecretDialog.tsx +80 -0
  114. package/src/client/ssh/panel/SshPanel.tsx +77 -0
  115. package/src/client/ssh/panel/TerminalTab.tsx +176 -0
  116. package/src/client/ssh/panel/TransferTab.tsx +232 -0
  117. package/src/client/ssh/panel/TunnelsTab.tsx +177 -0
  118. package/src/client/ssh/panel/controller.ts +48 -0
  119. package/src/client/ssh/panel/helpers.ts +26 -0
  120. package/src/client/ssh/panel/panel.module.css +1006 -0
  121. package/src/client/ssh/panel/xterm.css.ts +2 -0
  122. package/src/client/ssh/sidebar-entry.ts +123 -0
  123. package/src/client/state.ts +99 -0
  124. package/src/client/text.ts +22 -0
  125. package/src/client/workspace-badges.ts +99 -0
  126. package/src/client/workspace-gate.ts +232 -0
  127. package/src/client/workspace.module.css +283 -0
  128. package/src/client-http.ts +45 -0
  129. package/src/core.ts +47 -0
  130. package/src/fs.ts +85 -0
  131. package/src/host-http.ts +74 -0
  132. package/src/index.ts +244 -0
  133. package/src/ledger.ts +416 -0
  134. package/src/protocol.ts +114 -0
  135. package/src/providers/index.ts +34 -0
  136. package/src/providers/local/provider.ts +179 -0
  137. package/src/providers/ssh/provider.ts +274 -0
  138. package/src/remote/environment.ts +123 -0
  139. package/src/remote/output.ts +142 -0
  140. package/src/remote/remote-fs.ts +532 -0
  141. package/src/remote/remote-process.ts +203 -0
  142. package/src/remote/remote-subprocess.ts +159 -0
  143. package/src/remote/remote-terminal.ts +141 -0
  144. package/src/remote-runner.ts +201 -0
  145. package/src/remote-search.ts +163 -0
  146. package/src/routes.ts +395 -0
  147. package/src/runtime/workspace-core.ts +154 -0
  148. package/src/seam-state.ts +185 -0
  149. package/src/shell.ts +10 -0
  150. package/src/ssh/connection/lease.ts +17 -0
  151. package/src/ssh/connection/pool.ts +275 -0
  152. package/src/ssh/engine.ts +1761 -0
  153. package/src/ssh/exec/output.ts +70 -0
  154. package/src/ssh/known-hosts.ts +214 -0
  155. package/src/ssh/plugin.ts +184 -0
  156. package/src/ssh/protocol.ts +227 -0
  157. package/src/ssh/routes.ts +892 -0
  158. package/src/ssh/store.ts +544 -0
  159. package/src/ssh/tools.ts +402 -0
  160. package/src/ssh/transfer/progress.ts +75 -0
  161. package/src/ssh/vault.ts +477 -0
  162. package/src/subprocess.ts +71 -0
  163. package/src/switch/switch-fs.ts +253 -0
  164. package/src/switch/switch-subprocess.ts +59 -0
  165. package/src/tools.ts +221 -0
@@ -0,0 +1,1006 @@
1
+ /**
2
+ * dsh-ssh panel styles. Scoped by the plugin's own data attributes so nothing
3
+ * leaks into the rest of the GUI; colors ride the dsh --dsw-* tokens so the
4
+ * panel follows the active theme (light/dark and skins). The center-column
5
+ * hide rules are attribute-scoped and must stay in this stylesheet (it is
6
+ * imported by mount.tsx, so the styles load with the plugin).
7
+ */
8
+
9
+ /* --- center-column takeover (global rules, attribute-scoped) ----------------- */
10
+
11
+ [data-pane='conversation'] {
12
+ position: relative;
13
+ }
14
+
15
+ /* The panel container rides inside the conversation grid item as an extra
16
+ trailing child; hidden unless the panel is active. */
17
+ [data-dsh-ssh-view] {
18
+ position: absolute;
19
+ inset: 0;
20
+ display: none;
21
+ z-index: 5;
22
+ }
23
+
24
+ html[data-dsh-ssh-active] [data-dsh-ssh-view] {
25
+ display: block;
26
+ }
27
+
28
+ /* While the panel is active, the conversation content underneath is hidden
29
+ (it stays mounted and stateful). */
30
+ html[data-dsh-ssh-active] [data-pane='conversation'] > :not([data-dsh-ssh-view]) {
31
+ display: none;
32
+ }
33
+
34
+ /* --- sidebar entry row ------------------------------------------------------- */
35
+
36
+ .entry {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 8px;
40
+ width: 100%;
41
+ height: 32px;
42
+ padding: 0 12px;
43
+ background: transparent;
44
+ border: none;
45
+ border-radius: 8px;
46
+ color: var(--dsw-alias-label-secondary);
47
+ cursor: pointer;
48
+ font-size: 13px;
49
+ white-space: nowrap;
50
+ }
51
+
52
+ .entry:hover {
53
+ background: var(--dsw-specific-sidebar-nav-item-hover);
54
+ color: var(--dsw-alias-label-primary);
55
+ }
56
+
57
+ .entry[data-active] {
58
+ background: var(--dsw-specific-sidebar-nav-item-active);
59
+ color: var(--dsw-alias-label-primary);
60
+ font-weight: 600;
61
+ }
62
+
63
+ .entryIcon {
64
+ display: inline-flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ flex: none;
68
+ }
69
+
70
+ .entryLabel {
71
+ overflow: hidden;
72
+ text-overflow: ellipsis;
73
+ }
74
+
75
+ /* Collapsed rail: icon-only, centered, matching the shell's 56px rail. */
76
+ [data-dsh-frame][data-sidebar-collapsed] .entry {
77
+ justify-content: center;
78
+ padding: 0;
79
+ width: 100%;
80
+ }
81
+
82
+ [data-dsh-frame][data-sidebar-collapsed] .entryLabel {
83
+ display: none;
84
+ }
85
+
86
+ /* --- panel frame -------------------------------------------------------------- */
87
+
88
+ .view {
89
+ overflow: hidden;
90
+ }
91
+
92
+ .panel {
93
+ display: flex;
94
+ flex-direction: column;
95
+ height: 100%;
96
+ min-width: 0;
97
+ min-height: 0;
98
+ padding: 14px 16px 16px;
99
+ gap: 10px;
100
+ background: var(--dsw-alias-bg-base);
101
+ color: var(--dsw-alias-label-primary);
102
+ font-family: var(--dsw-font-family);
103
+ }
104
+
105
+ .panelHeader {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 10px;
109
+ flex: none;
110
+ }
111
+
112
+ .panelTitle {
113
+ margin: 0;
114
+ flex: 1;
115
+ font-size: 16px;
116
+ font-weight: 700;
117
+ color: var(--dsw-alias-label-primary);
118
+ white-space: nowrap;
119
+ }
120
+
121
+ /* --- tab bar ------------------------------------------------------------------ */
122
+
123
+ .tabBar {
124
+ display: flex;
125
+ gap: 2px;
126
+ flex: none;
127
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
128
+ }
129
+
130
+ .tab {
131
+ padding: 7px 14px;
132
+ font-size: 13px;
133
+ color: var(--dsw-alias-label-secondary);
134
+ background: transparent;
135
+ border: none;
136
+ border-bottom: 2px solid transparent;
137
+ border-radius: 6px 6px 0 0;
138
+ cursor: pointer;
139
+ white-space: nowrap;
140
+ }
141
+
142
+ .tab:hover {
143
+ color: var(--dsw-alias-label-primary);
144
+ background: var(--dsw-alias-interactive-bg-hover);
145
+ }
146
+
147
+ .tab[data-active] {
148
+ color: var(--dsw-alias-label-primary);
149
+ font-weight: 600;
150
+ border-bottom-color: var(--dsw-alias-state-business-primary);
151
+ }
152
+
153
+ .panelContent {
154
+ flex: 1;
155
+ min-height: 0;
156
+ display: flex;
157
+ flex-direction: column;
158
+ overflow: hidden;
159
+ }
160
+
161
+ /* Scrollable tab body (transfer / tunnels); hosts and cluster use fillBody so
162
+ their toolbars stay put while the table scrolls internally. */
163
+ .tabBody {
164
+ display: flex;
165
+ flex-direction: column;
166
+ gap: 10px;
167
+ flex: 1;
168
+ min-height: 0;
169
+ overflow-y: auto;
170
+ overflow-x: hidden;
171
+ }
172
+
173
+ .fillBody {
174
+ display: flex;
175
+ flex-direction: column;
176
+ gap: 10px;
177
+ flex: 1;
178
+ min-height: 0;
179
+ overflow: hidden;
180
+ }
181
+
182
+ /* --- toolbar / controls ------------------------------------------------------- */
183
+
184
+ .toolbar {
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 8px;
188
+ flex: none;
189
+ flex-wrap: wrap;
190
+ }
191
+
192
+ .controls {
193
+ display: flex;
194
+ align-items: center;
195
+ gap: 8px;
196
+ flex: none;
197
+ flex-wrap: wrap;
198
+ }
199
+
200
+ .controls .input {
201
+ flex: 0 1 260px;
202
+ min-width: 150px;
203
+ }
204
+
205
+ .toolbarSpacer {
206
+ flex: 1;
207
+ }
208
+
209
+ .search {
210
+ flex: 0 1 260px;
211
+ min-width: 120px;
212
+ padding: 6px 10px;
213
+ font-size: 13px;
214
+ color: var(--dsw-alias-label-primary);
215
+ background: var(--dsw-specific-input-major);
216
+ border: 1px solid var(--dsw-alias-border-l2);
217
+ border-radius: 8px;
218
+ outline: none;
219
+ }
220
+
221
+ .search::placeholder {
222
+ color: var(--dsw-alias-label-tertiary);
223
+ }
224
+
225
+ /* --- tables ------------------------------------------------------------------- */
226
+
227
+ .tableWrap {
228
+ flex: 1;
229
+ min-height: 0;
230
+ overflow: auto;
231
+ border: 1px solid var(--dsw-alias-border-l1);
232
+ border-radius: 10px;
233
+ }
234
+
235
+ .table {
236
+ width: 100%;
237
+ border-collapse: collapse;
238
+ font-size: 12.5px;
239
+ }
240
+
241
+ .table th {
242
+ position: sticky;
243
+ top: 0;
244
+ z-index: 1;
245
+ padding: 8px 10px;
246
+ text-align: left;
247
+ background: var(--dsw-alias-bg-layer-2);
248
+ color: var(--dsw-alias-label-secondary);
249
+ font-weight: 600;
250
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
251
+ white-space: nowrap;
252
+ }
253
+
254
+ .table td {
255
+ padding: 7px 10px;
256
+ border-bottom: 1px solid var(--dsw-alias-separator-primary);
257
+ vertical-align: top;
258
+ }
259
+
260
+ .table tbody tr:last-child td {
261
+ border-bottom: none;
262
+ }
263
+
264
+ .table tbody tr:hover td {
265
+ background: var(--dsw-alias-interactive-bg-hover);
266
+ }
267
+
268
+ .mono {
269
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
270
+ }
271
+
272
+ .cellMuted {
273
+ color: var(--dsw-alias-label-tertiary);
274
+ }
275
+
276
+ .actions {
277
+ display: flex;
278
+ align-items: center;
279
+ gap: 8px;
280
+ white-space: nowrap;
281
+ }
282
+
283
+ .inlineTest {
284
+ display: inline-flex;
285
+ align-items: center;
286
+ gap: 6px;
287
+ font-size: 11.5px;
288
+ color: var(--dsw-alias-label-secondary);
289
+ }
290
+
291
+ .inlineTest[data-status='ok'] {
292
+ color: var(--dsw-alias-state-success-primary);
293
+ }
294
+
295
+ .inlineTest[data-status='fail'] {
296
+ color: var(--dsw-alias-state-error-primary);
297
+ }
298
+
299
+ /* --- badges ------------------------------------------------------------------- */
300
+
301
+ .badge {
302
+ display: inline-block;
303
+ padding: 1px 8px;
304
+ font-size: 11px;
305
+ line-height: 1.6;
306
+ border-radius: 999px;
307
+ border: 1px solid var(--dsw-alias-border-l2);
308
+ color: var(--dsw-alias-label-secondary);
309
+ white-space: nowrap;
310
+ }
311
+
312
+ .badge[data-kind='key'] {
313
+ color: var(--dsw-alias-state-business-primary);
314
+ border-color: var(--dsw-alias-state-business-primary);
315
+ }
316
+
317
+ .badge[data-kind='password'] {
318
+ color: var(--dsw-alias-state-warn-primary);
319
+ border-color: var(--dsw-alias-state-warn-primary);
320
+ }
321
+
322
+ .badge[data-status='ok'] {
323
+ color: var(--dsw-alias-state-success-primary);
324
+ border-color: var(--dsw-alias-state-success-primary);
325
+ }
326
+
327
+ .badge[data-status='fail'] {
328
+ color: var(--dsw-alias-state-error-primary);
329
+ border-color: var(--dsw-alias-state-error-primary);
330
+ }
331
+
332
+ .badge[data-status='timeout'] {
333
+ color: var(--dsw-alias-state-warn-primary);
334
+ border-color: var(--dsw-alias-state-warn-primary);
335
+ }
336
+
337
+ /* --- buttons ------------------------------------------------------------------ */
338
+
339
+ .primaryButton {
340
+ padding: 6px 14px;
341
+ font-size: 13px;
342
+ font-weight: 600;
343
+ color: var(--dsw-alias-label-primary-foreground);
344
+ background: var(--dsw-alias-button-info-fill);
345
+ border: none;
346
+ border-radius: 8px;
347
+ cursor: pointer;
348
+ white-space: nowrap;
349
+ }
350
+
351
+ .primaryButton:hover:not(:disabled) {
352
+ background: var(--dsw-alias-button-info-hover);
353
+ }
354
+
355
+ .primaryButton:disabled {
356
+ opacity: 0.5;
357
+ cursor: default;
358
+ }
359
+
360
+ .ghostButton {
361
+ padding: 5px 12px;
362
+ font-size: 12px;
363
+ color: var(--dsw-alias-label-primary);
364
+ background: transparent;
365
+ border: 1px solid var(--dsw-alias-border-l2);
366
+ border-radius: 8px;
367
+ cursor: pointer;
368
+ white-space: nowrap;
369
+ }
370
+
371
+ .ghostButton:hover:not(:disabled) {
372
+ background: var(--dsw-alias-interactive-bg-hover);
373
+ }
374
+
375
+ .ghostButton:disabled {
376
+ opacity: 0.45;
377
+ cursor: default;
378
+ }
379
+
380
+ .iconButton {
381
+ display: inline-flex;
382
+ align-items: center;
383
+ justify-content: center;
384
+ width: 26px;
385
+ height: 26px;
386
+ padding: 0;
387
+ background: transparent;
388
+ border: none;
389
+ border-radius: 6px;
390
+ color: var(--dsw-alias-label-secondary);
391
+ cursor: pointer;
392
+ font-size: 13px;
393
+ }
394
+
395
+ .iconButton:hover {
396
+ background: var(--dsw-alias-interactive-bg-hover);
397
+ color: var(--dsw-alias-label-primary);
398
+ }
399
+
400
+ .linkButton {
401
+ padding: 0;
402
+ font-size: 12px;
403
+ color: var(--dsw-alias-state-business-primary);
404
+ background: none;
405
+ border: none;
406
+ cursor: pointer;
407
+ white-space: nowrap;
408
+ }
409
+
410
+ .linkButton:hover:not(:disabled) {
411
+ text-decoration: underline;
412
+ }
413
+
414
+ .linkButton:disabled {
415
+ opacity: 0.45;
416
+ cursor: default;
417
+ }
418
+
419
+ .linkButton[data-danger] {
420
+ color: var(--dsw-alias-state-error-primary);
421
+ }
422
+
423
+ /* --- spinner / banners / states ------------------------------------------------ */
424
+
425
+ .spinner {
426
+ display: inline-block;
427
+ width: 11px;
428
+ height: 11px;
429
+ flex: none;
430
+ border: 2px solid var(--dsw-alias-state-business-primary);
431
+ border-top-color: transparent;
432
+ border-radius: 50%;
433
+ animation: dshSshSpin 800ms linear infinite;
434
+ vertical-align: -1px;
435
+ }
436
+
437
+ @keyframes dshSshSpin {
438
+ to { transform: rotate(360deg); }
439
+ }
440
+
441
+ .banner {
442
+ padding: 8px 12px;
443
+ font-size: 12.5px;
444
+ line-height: 1.5;
445
+ border-radius: 8px;
446
+ border: 1px solid var(--dsw-alias-border-l2);
447
+ color: var(--dsw-alias-label-secondary);
448
+ overflow-wrap: anywhere;
449
+ }
450
+
451
+ .banner[data-kind='ok'] {
452
+ color: var(--dsw-alias-state-success-primary);
453
+ border-color: var(--dsw-alias-state-success-primary);
454
+ }
455
+
456
+ .banner[data-kind='error'] {
457
+ color: var(--dsw-alias-state-error-primary);
458
+ border-color: var(--dsw-alias-state-error-primary);
459
+ }
460
+
461
+ .banner[data-kind='info'] {
462
+ color: var(--dsw-alias-state-business-primary);
463
+ border-color: var(--dsw-alias-state-business-primary);
464
+ }
465
+
466
+ .empty {
467
+ padding: 28px 12px;
468
+ text-align: center;
469
+ font-size: 12.5px;
470
+ color: var(--dsw-alias-label-tertiary);
471
+ }
472
+
473
+ .loading {
474
+ padding: 28px 12px;
475
+ text-align: center;
476
+ font-size: 12.5px;
477
+ color: var(--dsw-alias-label-tertiary);
478
+ }
479
+
480
+ /* --- modal (host form) 闂?dsh theme (light/dark following) ------------------ */
481
+ /* Follows the dsh --dsw-* tokens so the dialog matches the active GUI theme
482
+ (light gray / white surface, dark text). Small radii, flat minimal
483
+ DeepSeek-brand primary button, no glass, no glow. */
484
+
485
+ .modalBackdrop {
486
+ position: fixed;
487
+ inset: 0;
488
+ z-index: 40;
489
+ display: flex;
490
+ align-items: center;
491
+ justify-content: center;
492
+ padding: 24px;
493
+ background: var(--dsw-alias-bg-mask-1, rgba(0, 0, 0, 0.45));
494
+ }
495
+
496
+ .modal {
497
+ position: relative;
498
+ display: flex;
499
+ flex-direction: column;
500
+ box-sizing: border-box;
501
+ width: min(560px, calc(100vw - 48px));
502
+ min-width: 0;
503
+ /* The card sizes to its content so every input is fully visible without
504
+ scrolling; only a viewport-smaller-than-content screen falls back to
505
+ the body scroll. Native dsh card: 12px radius, hairline border, flat. */
506
+ max-height: calc(100vh - 48px);
507
+ min-height: 0;
508
+ overflow: hidden;
509
+ background: var(--dsw-alias-bg-base, #fff);
510
+ border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, 0.04));
511
+ border-radius: 12px;
512
+ color: #000000;
513
+ font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI',
514
+ Roboto, system-ui, 'PingFang SC', 'Microsoft YaHei', sans-serif);
515
+ }
516
+
517
+
518
+ .modalHeader {
519
+ display: flex;
520
+ align-items: center;
521
+ gap: 10px;
522
+ flex: none;
523
+ padding: 14px 18px 10px;
524
+ min-width: 0;
525
+ box-sizing: border-box;
526
+ }
527
+
528
+ .modalTitle {
529
+ margin: 0;
530
+ flex: 1;
531
+ display: flex;
532
+ align-items: center;
533
+ gap: 8px;
534
+ font-size: 15px;
535
+ font-weight: 600;
536
+ color: #000000;
537
+ }
538
+
539
+ /* tiny whale glyph: DeepSeek's friendly blue-whale mark */
540
+ .whaleMark {
541
+ width: 14px;
542
+ height: 14px;
543
+ flex: none;
544
+ border-radius: 50% 50% 38% 38%;
545
+ background:
546
+ radial-gradient(circle at 32% 30%, rgba(255, 255, 255, 0.7) 0 12%, transparent 13%),
547
+ radial-gradient(circle at 50% 60%, #4d6bfe 0 42%, transparent 43%);
548
+ box-shadow: 0 0 0 1px rgba(77, 107, 254, 0.35);
549
+ }
550
+
551
+ .modalBody {
552
+
553
+ flex: 1 1 auto;
554
+ min-width: 0;
555
+ min-height: 0;
556
+ overflow-y: auto;
557
+ overflow-x: hidden;
558
+ overscroll-behavior: contain;
559
+ padding: 4px 18px 8px;
560
+ display: flex;
561
+ flex-direction: column;
562
+ gap: 12px;
563
+ scrollbar-width: thin;
564
+ scrollbar-color: var(--dsw-alias-label-caption, rgba(128, 128, 128, 0.5)) transparent;
565
+ }
566
+
567
+ .modalBody::-webkit-scrollbar {
568
+ width: 6px;
569
+ }
570
+
571
+ .modalBody::-webkit-scrollbar-thumb {
572
+ background: var(--dsw-alias-label-caption, rgba(128, 128, 128, 0.5));
573
+ border-radius: 6px;
574
+ }
575
+
576
+ .modalBody::-webkit-scrollbar-track {
577
+ background: transparent;
578
+ }
579
+
580
+ .modalFooter {
581
+ display: flex;
582
+ justify-content: flex-end;
583
+ align-items: center;
584
+ gap: 10px;
585
+ flex: none;
586
+ padding: 12px 18px 14px;
587
+ min-width: 0;
588
+ box-sizing: border-box;
589
+ border-top: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.08));
590
+ }
591
+
592
+ /* DeepSeek-style primary: flat brand blue, no gradient, no glow */
593
+ .modalPrimary {
594
+ padding: 7px 18px;
595
+ border: none;
596
+ border-radius: 8px;
597
+ background: var(--dsw-alias-button-primary-fill, #0f1115);
598
+ color: var(--dsw-alias-label-primary-foreground, #fff);
599
+ font-size: 13px;
600
+ font-weight: 600;
601
+ cursor: pointer;
602
+ transition: background 0.15s ease;
603
+ font-family: inherit;
604
+ }
605
+
606
+ .modalPrimary:hover:not(:disabled) {
607
+ background: var(--dsw-alias-button-primary-hover, #2b2f36);
608
+ }
609
+
610
+ .modalPrimary:disabled {
611
+ opacity: 0.5;
612
+ cursor: default;
613
+ }
614
+
615
+ .modalGhost {
616
+ padding: 7px 15px;
617
+ border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.15));
618
+ border-radius: 8px;
619
+ background: transparent;
620
+ color: var(--dsw-alias-label-primary, #0f1115);
621
+ font-size: 13px;
622
+ cursor: pointer;
623
+ transition: background 0.15s ease;
624
+ font-family: inherit;
625
+ }
626
+
627
+ .modalGhost:hover:not(:disabled) {
628
+ background: var(--dsw-alias-bg-overlay, rgba(0, 0, 0, 0.05));
629
+ }
630
+
631
+ .modalGhost:disabled {
632
+ opacity: 0.5;
633
+ cursor: default;
634
+ }
635
+
636
+ .formError {
637
+ margin: 0 18px 2px;
638
+ padding: 8px 12px;
639
+ border-radius: 6px;
640
+ background: var(--dsw-alias-state-error-bg, rgba(245, 63, 63, 0.1));
641
+ border: 1px solid var(--dsw-alias-state-error-primary, rgba(245, 63, 63, 0.4));
642
+ font-size: 12px;
643
+ color: var(--dsw-alias-state-error-primary, #d03050);
644
+ }
645
+
646
+ .hint {
647
+ font-size: 11.5px;
648
+ line-height: 1.45;
649
+ color: var(--dsw-alias-label-tertiary, #81858c);
650
+ }
651
+
652
+ .field {
653
+ display: flex;
654
+ flex-direction: column;
655
+ gap: 5px;
656
+ min-width: 0;
657
+ }
658
+
659
+ .fieldLabel {
660
+ font-size: 13px;
661
+ font-weight: 500;
662
+ color: var(--dsw-alias-label-primary, #0f1115);
663
+ }
664
+
665
+ .input {
666
+ padding: 7px 10px;
667
+ width: 100%;
668
+ min-width: 0;
669
+ min-height: 36px;
670
+ box-sizing: border-box;
671
+ font-size: 13px;
672
+ color: var(--dsw-alias-label-primary, #0f1115);
673
+ background: var(--dsw-alias-bg-layer-1, #fff);
674
+ border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.14));
675
+ border-radius: 8px;
676
+ outline: none;
677
+ font-family: inherit;
678
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
679
+ }
680
+
681
+ .input:focus {
682
+ border-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);
683
+ box-shadow: 0 0 0 2px rgba(65, 118, 230, 0.15);
684
+ }
685
+
686
+ .input::placeholder {
687
+ color: var(--dsw-alias-label-tertiary, #81858c);
688
+ }
689
+
690
+ .input:disabled {
691
+ opacity: 0.5;
692
+ }
693
+
694
+ .formRow {
695
+ display: grid;
696
+ grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
697
+ gap: 12px;
698
+ min-width: 0;
699
+ }
700
+
701
+ .radioRow {
702
+ display: flex;
703
+ gap: 18px;
704
+ align-items: center;
705
+ }
706
+
707
+ .radioLabel {
708
+ display: inline-flex;
709
+ gap: 7px;
710
+ align-items: center;
711
+ font-size: 13px;
712
+ color: #000000;
713
+ cursor: pointer;
714
+ }
715
+
716
+ .radioLabel input[type='radio'] {
717
+ accent-color: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);
718
+ }
719
+
720
+ /* --- terminal ----------------------------------------------------------------- */
721
+
722
+ .termBody {
723
+ display: flex;
724
+ flex-direction: column;
725
+ gap: 8px;
726
+ flex: 1;
727
+ min-height: 0;
728
+ overflow: hidden;
729
+ }
730
+
731
+ .termWrap {
732
+ position: relative;
733
+ flex: 1;
734
+ min-height: 0;
735
+ border: 1px solid var(--dsw-alias-border-l1);
736
+ border-radius: 10px;
737
+ overflow: hidden;
738
+ background: #0b0e14;
739
+ }
740
+
741
+ .termContainer {
742
+ position: absolute;
743
+ inset: 0;
744
+ padding: 8px 10px;
745
+ }
746
+
747
+ .termPlaceholder {
748
+ position: absolute;
749
+ inset: 0;
750
+ z-index: 2;
751
+ display: flex;
752
+ align-items: center;
753
+ justify-content: center;
754
+ padding: 0 24px;
755
+ text-align: center;
756
+ font-size: 12.5px;
757
+ color: var(--dsw-alias-label-tertiary);
758
+ background: var(--dsw-alias-bg-base);
759
+ }
760
+
761
+ /* --- transfer ----------------------------------------------------------------- */
762
+
763
+ .hiddenFile {
764
+ display: none;
765
+ }
766
+
767
+ .browsePanel {
768
+ display: flex;
769
+ flex-direction: column;
770
+ flex: none;
771
+ border: 1px solid var(--dsw-alias-border-l1);
772
+ border-radius: 10px;
773
+ overflow: hidden;
774
+ }
775
+
776
+ .browseHeader {
777
+ display: flex;
778
+ align-items: center;
779
+ gap: 8px;
780
+ padding: 8px 10px;
781
+ background: var(--dsw-alias-bg-layer-2);
782
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
783
+ }
784
+
785
+ .browsePath {
786
+ flex: 1;
787
+ min-width: 0;
788
+ overflow: hidden;
789
+ text-overflow: ellipsis;
790
+ white-space: nowrap;
791
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
792
+ font-size: 12px;
793
+ color: var(--dsw-alias-label-secondary);
794
+ }
795
+
796
+ .browseList {
797
+ max-height: 240px;
798
+ overflow-y: auto;
799
+ overflow-x: hidden;
800
+ }
801
+
802
+ .dirRow {
803
+ display: grid;
804
+ grid-template-columns: minmax(0, 1fr) auto auto;
805
+ gap: 12px;
806
+ min-width: 0;
807
+ width: 100%;
808
+ padding: 5px 10px;
809
+ text-align: left;
810
+ font: inherit;
811
+ font-size: 12.5px;
812
+ color: var(--dsw-alias-label-primary);
813
+ background: transparent;
814
+ border: none;
815
+ border-bottom: 1px solid var(--dsw-alias-separator-primary);
816
+ cursor: pointer;
817
+ }
818
+
819
+ .dirRow:hover {
820
+ background: var(--dsw-alias-interactive-bg-hover);
821
+ }
822
+
823
+ .dirRow[data-type='dir'] .dirName {
824
+ color: var(--dsw-alias-state-business-primary);
825
+ }
826
+
827
+ .dirRow[data-up] {
828
+ color: var(--dsw-alias-label-secondary);
829
+ }
830
+
831
+ .dirName {
832
+ overflow: hidden;
833
+ text-overflow: ellipsis;
834
+ white-space: nowrap;
835
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
836
+ }
837
+
838
+ .dirType {
839
+ color: var(--dsw-alias-label-tertiary);
840
+ white-space: nowrap;
841
+ }
842
+
843
+ .dirSize {
844
+ color: var(--dsw-alias-label-tertiary);
845
+ white-space: nowrap;
846
+ text-align: right;
847
+ }
848
+
849
+ .transferBlock {
850
+ display: flex;
851
+ flex-direction: column;
852
+ gap: 6px;
853
+ flex: none;
854
+ }
855
+
856
+ .progressMeta {
857
+ display: flex;
858
+ gap: 12px;
859
+ min-width: 0;
860
+ flex-wrap: wrap;
861
+ font-size: 12px;
862
+ color: var(--dsw-alias-label-secondary);
863
+ }
864
+
865
+ .progressTrack {
866
+ height: 8px;
867
+ border-radius: 999px;
868
+ background: var(--dsw-alias-interactive-bg-hover);
869
+ overflow: hidden;
870
+ }
871
+
872
+ .progressBar {
873
+ height: 100%;
874
+ border-radius: 999px;
875
+ background: var(--dsw-alias-state-business-primary);
876
+ transition: width 120ms linear;
877
+ }
878
+
879
+ /* --- tunnels ------------------------------------------------------------------ */
880
+
881
+ .tunnelList {
882
+ display: flex;
883
+ flex-direction: column;
884
+ gap: 8px;
885
+ flex: none;
886
+ }
887
+
888
+ .tunnelRow {
889
+ display: flex;
890
+ align-items: center;
891
+ gap: 10px;
892
+ padding: 8px 12px;
893
+ background: var(--dsw-alias-bg-layer-2);
894
+ border: 1px solid var(--dsw-alias-border-l2);
895
+ border-radius: 10px;
896
+ }
897
+
898
+ .tunnelRow[data-state='forwarding'] {
899
+ border-color: var(--dsw-alias-state-success-primary);
900
+ }
901
+
902
+ .tunnelRow[data-state='connecting'] {
903
+ border-color: var(--dsw-alias-state-warn-primary);
904
+ }
905
+
906
+ .tunnelRow[data-state='failed'] {
907
+ border-color: var(--dsw-alias-state-error-primary);
908
+ }
909
+
910
+ .tunnelLabel {
911
+ flex: 1;
912
+ min-width: 0;
913
+ overflow: hidden;
914
+ text-overflow: ellipsis;
915
+ white-space: nowrap;
916
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
917
+ font-size: 12.5px;
918
+ }
919
+
920
+ .formCard {
921
+ display: flex;
922
+ flex-direction: column;
923
+ gap: 10px;
924
+ padding: 12px;
925
+ background: var(--dsw-alias-bg-layer-2);
926
+ border: 1px solid var(--dsw-alias-border-l1);
927
+ border-radius: 10px;
928
+ flex: none;
929
+ }
930
+
931
+ /* --- cluster ------------------------------------------------------------------ */
932
+
933
+ .clusterForm {
934
+ display: flex;
935
+ flex-direction: column;
936
+ gap: 8px;
937
+ flex: none;
938
+ }
939
+
940
+ .clusterFilters {
941
+ display: grid;
942
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
943
+ gap: 10px;
944
+ }
945
+
946
+ .commandInput {
947
+ min-height: 96px;
948
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
949
+ }
950
+
951
+ .cellDetails summary {
952
+ cursor: pointer;
953
+ font-size: 12px;
954
+ color: var(--dsw-alias-label-secondary);
955
+ }
956
+
957
+ .cellPre {
958
+ margin: 4px 0 0;
959
+ padding: 6px 8px;
960
+ max-height: 180px;
961
+ overflow: auto;
962
+ background: var(--dsw-alias-bg-layer-2);
963
+ border: 1px solid var(--dsw-alias-border-l2);
964
+ border-radius: 6px;
965
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
966
+ font-size: 11.5px;
967
+ white-space: pre-wrap;
968
+ word-break: break-all;
969
+ }
970
+
971
+ /* narrow viewport: collapse form rows to a single column so the dialog
972
+ never overflows horizontally */
973
+ @media (max-width: 420px) {
974
+ .formRow {
975
+ grid-template-columns: 1fr;
976
+ }
977
+ }
978
+
979
+ /* --- host fingerprint confirm dialog ---------------------------------------- */
980
+
981
+ .fingerprintIntro {
982
+ margin: 0 0 10px;
983
+ font-size: 13px;
984
+ line-height: 1.5;
985
+ color: #000;
986
+ }
987
+
988
+ .fingerprintCode {
989
+ display: block;
990
+ padding: 10px 12px;
991
+ border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
992
+ border-radius: 6px;
993
+ background: var(--dsw-specific-input-major, #f2f3f5);
994
+ color: #1f2229;
995
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
996
+ font-size: 13px;
997
+ word-break: break-all;
998
+ user-select: text;
999
+ }
1000
+
1001
+ .fingerprintWarn {
1002
+ margin: 10px 0 0;
1003
+ font-size: 12px;
1004
+ color: var(--dsw-alias-state-error-primary, #d03050);
1005
+ line-height: 1.5;
1006
+ }