Compare commits

..

6 Commits

Author SHA1 Message Date
allcontributors[bot]
5d0da65360 update README.id-ID.md [skip ci] 2025-02-24 23:15:14 +00:00
allcontributors[bot]
295d0618ec update README.de-DE.md [skip ci] 2025-02-24 23:15:03 +00:00
allcontributors[bot]
7d8e3fd6ce update README.ko-KR.md [skip ci] 2025-02-24 23:15:01 +00:00
allcontributors[bot]
b3d7226522 update README.ru-RU.md [skip ci] 2025-02-24 23:15:00 +00:00
allcontributors[bot]
1eb6c91eb9 update README.zh-CN.md [skip ci] 2025-02-24 23:14:59 +00:00
allcontributors[bot]
e1df0d613c update README.md [skip ci] 2025-02-24 23:14:58 +00:00
82 changed files with 278 additions and 825 deletions

View File

@@ -6,12 +6,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Installing Node
uses: actions/setup-node@v4.4.0
uses: actions/setup-node@v3.7.0
with:
node-version: 22
@@ -49,12 +49,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Installing Node
uses: actions/setup-node@v4.4.0
uses: actions/setup-node@v3.7.0
with:
node-version: 22
@@ -161,12 +161,12 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Node
uses: actions/setup-node@v4.4.0
uses: actions/setup-node@v3.7.0
with:
node-version: 22
@@ -258,7 +258,7 @@ jobs:
repo: 'eugeny/tabby'
dir: 'dist'
rpmvers: 'el/9 el/8 ol/6 ol/7'
debvers: 'ubuntu/bionic ubuntu/focal ubuntu/hirsute ubuntu/impish ubuntu/jammy ubuntu/kinetic ubuntu/noble ubuntu/oracular debian/jessie debian/stretch debian/buster debian/bullseye debian/bookworm debian/trixie debian/testing debian/unstable'
debvers: 'ubuntu/bionic ubuntu/focal ubuntu/hirsute ubuntu/impish ubuntu/jammy ubuntu/kinetic ubuntu/noble ubuntu/oracular debian/jessie debian/stretch debian/buster debian/bullseye debian/bookworm debian/trixie'
- uses: actions/upload-artifact@master
name: Upload AppImage (${{matrix.arch}})
@@ -315,7 +315,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
@@ -324,7 +324,7 @@ jobs:
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags'))
- name: Installing Node
uses: actions/setup-node@v4.4.0
uses: actions/setup-node@v3.7.0
with:
node-version: 22

View File

@@ -38,7 +38,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@@ -7,14 +7,14 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Installing Node
uses: actions/setup-node@v4.4.0
uses: actions/setup-node@v3.7.0
with:
node-version: 22
node-version: 20
- name: Build
run: |

View File

@@ -60,7 +60,7 @@ tabby
| ├─ src # Electron renderer code
| └─ main.js # Electron main entry point
├─ build
├─ clink # Clink distribution, for Windows
├─ clink # Clink distributive, for Windows
├─ scripts # Maintenance scripts
├─ tabby-community-color-schemes # Plugin that provides color schemes
├─ tabby-core # Plugin that provides base UI and tab management

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017 Tabby Developers
Copyright (c) 2017 Eugene Pankov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -119,9 +119,7 @@ Plugins und Themen können direkt aus der Ansicht "Einstellungen" in Tabby insta
* [clippy](https://github.com/Eugeny/tabby-clippy) - ein Beispiel-Plugin, das einen die ganze Zeit nervt
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - ermöglicht das Erstellen eigener Workspace-Profile auf Basis der angegebenen Konfiguration
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - öffnet den Standard-Systembrowser mit einem Text, der aus dem Tabby Tab ausgewählt wurde
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - Öffnet ein SFTP-Tab für SSH-Verbindungen ähnlich wie SecureCRT
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - In-App-Web-Authentifizierungspopups (Hauptsächlich für die in-Browser-Authentifizierung von Warpgate entwickelt)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Leistungsstarke Model Context Protocol Server-Integration für Tabby, die sich nahtlos mit KI-Assistenten über MCP-Clients wie Cursor und Windsurf verbindet und Ihren Terminal-Workflow mit intelligenten KI-Funktionen verbessert.
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
<a name="themes"></a>
@@ -349,6 +347,7 @@ Dank geht an diese wunderbaren Menschen ([emoji key](https://allcontributors.org
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ianaflous"><img src="https://avatars.githubusercontent.com/u/42301579?v=4?s=100" width="100px;" alt="ianaflous"/><br /><sub><b>ianaflous</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ianaflous" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -120,9 +120,7 @@ Los plugins y los temas se pueden instalar directamente desde la vista de Config
* [clippy](https://github.com/Eugeny/tabby-clippy) - un ejemplo de plugin que te molesta todo el tiempo
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite crear perfiles de espacio de trabajo personalizados basados en la configuración dada
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre el navegador del sistema por defecto con un texto seleccionado en la pestaña de Tabby's
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - abre una pestaña sftp para la conexión ssh como SecureCRT
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - Ventanas emergentes de autenticación web dentro de la app (Construidas principalmente para la autenticación en el navegador de warpgate)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Potente integración del servidor de Protocolo de Contexto de Modelo para Tabby que se conecta sin problemas con asistentes de IA a través de clientes MCP como Cursor y Windsurf, mejorando tu flujo de trabajo en terminal con capacidades inteligentes de IA.
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
<a name="themes"></a>
# Temas

View File

@@ -120,9 +120,8 @@ Tema dan Plugin bisa langsung di install dari Pengaturan di dalam Tabby.
* [clippy](https://github.com/Eugeny/tabby-clippy) - suatu contoh plugin yang akan mengganggu anda setiap saat
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - memperbolehkan membuat kustom profil workspace dari konfigurasi yang diberikan
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - membuka browser default dengan text yang dipilih dari Tab Tabby
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - membuka tab sftp untuk koneksi ssh seperti SecureCRT
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - Pop-up otentikasi web di dalam aplikasi (Dibangun terutama untuk otentikasi in-browser warpgate)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Integrasi server Model Context Protocol yang kuat untuk Tabby yang terhubung secara mulus dengan asisten AI melalui klien MCP seperti Cursor dan Windsurf, meningkatkan alur kerja terminal Anda dengan kemampuan AI yang cerdas.
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
<a name="themes"></a>
# Tema
@@ -347,6 +346,7 @@ Terima kasih kepada mereka yang telah membantu ([emoji key](https://allcontribut
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ianaflous"><img src="https://avatars.githubusercontent.com/u/42301579?v=4?s=100" width="100px;" alt="ianaflous"/><br /><sub><b>ianaflous</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ianaflous" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -107,19 +107,18 @@ Tabby può essere eseguito come app portatile su Windows, se crei una cartella `
<a name="plugins"></a>
# Plugin
I plugin e i temi possono essere installati direttamente dalla vista Impostazioni all'interno di Tabby.
Plugins and themes can be installed directly from the Settings view inside Tabby.
* [docker](https://github.com/Eugeny/tabby-docker) - connect to Docker containers
* [title-control](https://github.com/kbjr/terminus-title-control) - allows modifying the title of the terminal tabs by providing a prefix, suffix, and/or strings to be removed
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - quickly send commands to one or all terminal tabs
* [save-output](https://github.com/Eugeny/tabby-save-output) - record terminal output into a file
* [sync-config](https://github.com/starxg/terminus-sync-config) - sync the config to Gist or Gitee
* [clippy](https://github.com/Eugeny/tabby-clippy) - an example plugin which annoys you all the time
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - allows creating custom workspace profiles based on the given config
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - opens default system browser with a text selected from the Tabby's tab
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
* [docker](https://github.com/Eugeny/tabby-docker) - connessione ai container Docker
* [title-control](https://github.com/kbjr/terminus-title-control) - consente di modificare il titolo delle schede del terminale fornendo un prefisso, un suffisso e/o stringhe da rimuovere
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - invia rapidamente comandi a una o tutte le schede del terminale
* [save-output](https://github.com/Eugeny/tabby-save-output) - registra l'output del terminale in un file
* [sync-config](https://github.com/starxg/terminus-sync-config) - sincronizza la configurazione con Gist o Gitee
* [clippy](https://github.com/Eugeny/tabby-clippy) - un esempio di plugin che ti infastidisce tutto il tempo
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - consente di creare profili di spazio di lavoro personalizzati basati sulla configurazione fornita
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - apre il browser di sistema predefinito con un testo selezionato dalla scheda di Tabby
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - apre una scheda SFTP per la connessione SSH come SecureCRT
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - Popup di autenticazione web in-app (costruito principalmente per l'autenticazione in-browser di Warpgate)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Potente integrazione del server Model Context Protocol per Tabby che si connette perfettamente con assistenti AI attraverso client MCP come Cursor e Windsurf, migliorando il tuo flusso di lavoro del terminale con capacità AI intelligenti.
<a name="themes"></a>
# Temi

View File

@@ -127,9 +127,8 @@ Windows上では、`Tabby.exe`がある場所と同じ場所に`data`フォル
* [clippy](https://github.com/Eugeny/tabby-clippy) - プラグインの作例として、いつも厄介なあいつが出てくるプラグイン
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 指定された設定からカスタマイズされたワークスペースを作成することができます
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby内の端末で選択したテキストを既定ブラウザで開くことができます。
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - SecureCRTのようにSSH接続のSFTPタブを開く
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - アプリ内ウェブ認証ポップアップ主にwarpgateのブラウザ認証用に構築
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - TabbyのためのパワフルなModel Context Protocolサーバー統合機能で、CursorやWindsurfなどのMCPクライアントを通じてAIアシスタントとシームレスに接続し、インテリジェントなAI機能によってターミナルワークフローを強化します。
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
<a name="themes"></a>
# テーマ

View File

@@ -107,7 +107,7 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
플러그인과 테마는 Tabby 내부의 설정에서 직접 설치할 수 있습니다.
* [clickable-links](https://github.com/Eugeny/tabby-clickable-links) - 터미널의 경로 및 URL을 클릭 가능하게
* [clickable-links](https://github.com/Eugeny/tabby-clickable-links) - m터미널의 경로 및 URL을 클릭 가능하게
* [docker](https://github.com/Eugeny/tabby-docker) - Docker 컨테이너에 연결
* [title-control](https://github.com/kbjr/terminus-title-control) - 접두사, 접미사 및/또는 문자열 제거를 제공하여 터미널 탭의 제목을 수정
* [quick-cmds](https://github.com/Domain/terminus-quick-cmds) - 하나 또는 모든 터미널 탭에 신속한 명령 전송
@@ -116,9 +116,8 @@ This README is also available in: <a href="./README.md">:gb: English</a> · <a
* [clippy](https://github.com/Eugeny/tabby-clippy) - 항상 당신을 귀찮게 하는 예제 플러그인
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 주어진 구성을 기반으로 사용자 정의 작업 공간 프로필을 생성할 수 있습니다
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - Tabby의 탭에서 선택한 텍스트로 기본 시스템 브라우저를 엽니다
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - SecureCRT와 유사하게 SSH 연결에 대한 SFTP 탭을 엽니다.
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - 앱 내 웹 인증 팝업 (주로 warpgate 브라우저 인증을 위해 구축)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Cursor 및 Windsurf와 같은 MCP 클라이언트를 통해 AI 어시스턴트와 원활하게 연결되는 Tabby용 강력한 모델 컨텍스트 프로토콜 서버 통합으로, 지능형 AI 기능으로 터미널 워크플로우를 향상시킵니다.
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
<a name="themes"></a>
# 테마
@@ -144,7 +143,7 @@ Pull requests and plugins are welcome!
---
<a name="contributors"></a>
여기 있는 멋진 사람들에게 진심으로 감사합니다. ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
여기있는 멋진 사람들에게 진심으로 감사합니다. ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
@@ -342,6 +341,7 @@ Pull requests and plugins are welcome!
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ianaflous"><img src="https://avatars.githubusercontent.com/u/42301579?v=4?s=100" width="100px;" alt="ianaflous"/><br /><sub><b>ianaflous</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ianaflous" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -129,7 +129,6 @@ Plugins and themes can be installed directly from the Settings view inside Tabby
* [background](https://github.com/moemoechu/tabby-background) - change Tabby background image and more...
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - In-app web authentication popups (Built primarily for warpgate in-browser auth)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Powerful Model Context Protocol server integration for Tabby that seamlessly connects with AI assistants through MCP clients like Cursor and Windsurf, enhancing your terminal workflow with intelligent AI capabilities.
<a name="themes"></a>
@@ -366,6 +365,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ianaflous"><img src="https://avatars.githubusercontent.com/u/42301579?v=4?s=100" width="100px;" alt="ianaflous"/><br /><sub><b>ianaflous</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ianaflous" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -132,7 +132,6 @@ Wtyczki (jak i motywy) mogą być instalowane bezpośrednio z widoku ustawień w
* [background](https://github.com/moemoechu/tabby-background) - zmień tło Tabby oraz wiele więcej
* [highlight](https://github.com/moemoechu/tabby-highlight) - Tabby terminal keyword highlight plugin
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - okienka autoryzacji wewnątrz konsoli (Zbudowany głównie pod autoryzację projektu Warpgate w przeglądarce)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Potężna integracja serwera Model Context Protocol dla Tabby, która bezproblemowo łączy się z asystentami AI poprzez klientów MCP, takich jak Cursor i Windsurf, usprawniając przepływ pracy w terminalu dzięki inteligentnym możliwościom AI.
<a name="themes"></a>

View File

@@ -120,9 +120,8 @@ Plugins e temas podem ser instalados durante a execução na pagina de configura
* [clippy](https://github.com/Eugeny/tabby-clippy) - um plugin de exemplo que te incomoda o tempo todo
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - permite criar perfis de espaço de trabalho personalizados com base na configuração fornecida
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - abre o navegador padrão do sistema com um texto selecionado na guia do Tabby
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - abre uma guia SFTP para conexão SSH como o SecureCRT
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - pop-ups de autenticação web dentro do aplicativo (Construído principalmente para autenticação in-browser do warpgate)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Integração poderosa do servidor Model Context Protocol para Tabby que se conecta perfeitamente com assistentes de IA através de clientes MCP como Cursor e Windsurf, aprimorando seu fluxo de trabalho no terminal com recursos inteligentes de IA.
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - open sftp tab for ssh connection like SecureCRT
<a name="themes"></a>
# Temas

View File

@@ -31,7 +31,7 @@
* Встроенный SSH- и Telnet-клиент и менеджер подключений;
* Встроенный последовательный терминал;
* Темы и цветовые схемы;
* Полностью настраиваемые сочетания клавиш;
* Полностью настраеваемые сочетания клавиш;
* Панели;
* Запоминание вкладок;
* Поддержка PowerShell (and PS Core), WSL, Git-Bash, Cygwin, MSYS2, Cmder и CMD;
@@ -118,8 +118,7 @@
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) — позволяет создавать пользовательские профили рабочего окружения на основе конфига;
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) — открывает браузер по умолчанию с текстом, выделенном во вкладке Tabby.
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - открывает sftp вкладку для ssh соединения, похож на SecureCRT
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - Встроенные всплывающие окна веб-аутентификации (Основано в основном для аутентификации в браузере warpgate)
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - Мощная интеграция сервера протокола Model Context Protocol для Tabby, которая беспрепятственно соединяется с ИИ-ассистентами через MCP-клиенты, такие как Cursor и Windsurf, улучшая рабочий процесс в терминале с помощью интеллектуальных возможностей искусственного интеллекта.
<a name="themes"></a>
# Темы
@@ -343,6 +342,7 @@ Pull-запросы и плагины приветствуются!
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ianaflous"><img src="https://avatars.githubusercontent.com/u/42301579?v=4?s=100" width="100px;" alt="ianaflous"/><br /><sub><b>ianaflous</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ianaflous" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -117,8 +117,7 @@
* [workspace-manager](https://github.com/composer404/tabby-workspace-manager) - 允许根据给定的配置创建自定义工作区配置文件
* [search-in-browser](https://github.com/composer404/tabby-search-in-browser) - 从 Tabby 标签页带有选中的文本来打开系统默认浏览器
* [sftp-tab](https://github.com/wljince007/tabby-sftp-tab) - 为ssh连接打开类似SecureCRT的sftp标签页
* [web-auth-handler](https://github.com/Jazzmoon/tabby-web-auth-handler) - 应用内网页认证弹出窗口主要为warpgate浏览器认证而建
* [mcp-server](https://github.com/thuanpham582002/tabby-mcp-server) - 为 Tabby 提供强大的模型上下文协议服务器集成,可通过 Cursor 和 Windsurf 等 MCP 客户端无缝连接 AI 助手,利用智能 AI 功能增强您的终端工作流程。
<a name="themes"></a>
# 主题
@@ -342,6 +341,7 @@
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/geodic"><img src="https://avatars.githubusercontent.com/u/64704703?v=4?s=100" width="100px;" alt="geodic"/><br /><sub><b>geodic</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=geodic" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ianaflous"><img src="https://avatars.githubusercontent.com/u/42301579?v=4?s=100" width="100px;" alt="ianaflous"/><br /><sub><b>ianaflous</b></sub></a><br /><a href="https://github.com/Eugeny/tabby/commits?author=ianaflous" title="Code">💻</a></td>
</tr>
</tbody>
</table>

View File

@@ -4,7 +4,7 @@
"private": true,
"repository": "https://github.com/Eugeny/tabby",
"author": {
"name": "Tabby Developers",
"name": "Eugene Pankov",
"email": "e@ajenti.org"
},
"main": "dist/main.js",
@@ -30,7 +30,7 @@
"native-process-working-directory": "^1.0.2",
"npm": "6",
"rxjs": "^7.5.7",
"russh": "0.1.24",
"russh": "0.1.21",
"source-map-support": "^0.5.20",
"v8-compile-cache": "^2.3.0",
"yargs": "^17.7.2"
@@ -64,9 +64,9 @@
"tabby-terminal": "*"
},
"resolutions": {
"node-abi": "4.9.0",
"*/node-abi": "^3",
"node-gyp": "^10.0.0",
"nan": "2.22.2",
"nan": "2.22.0",
"node-addon-api": "^8.3.0"
}
}

View File

@@ -6,6 +6,4 @@ export const PLUGIN_BLACKLIST = [
'terminus-clickable-ips', // broken, functionality now bundled with Tabby
'terminus-elastic-quick-commands', // broken and abandoned, fork of quick-commands
'terminus-elastic-quick-cmds', // broken and abandoned, fork of quick-commands
'tabby-fig', // abandoned,
'tabby-plugin-fig-integration', // abandoned,
]

View File

@@ -2607,10 +2607,10 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@2.22.2, nan@^2.17.0:
version "2.22.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.2.tgz#6b504fd029fb8f38c0990e52ad5c26772fdacfbb"
integrity sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==
nan@2.22.0, nan@^2.17.0:
version "2.22.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3"
integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==
napi-build-utils@^1.0.1:
version "1.0.2"
@@ -2641,12 +2641,19 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-abi@4.9.0, node-abi@^3.3.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-4.9.0.tgz#ca6dabf7991e54bf3ba6d8d32641e1b84f305263"
integrity sha512-0isb3h+AXUblx5Iv0mnYy2WsErH+dk2e9iXJXdKAtS076Q5hP+scQhp6P4tvDeVlOBlG3ROKvkpQHtbORllq2A==
node-abi@^3:
version "3.65.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.65.0.tgz#ca92d559388e1e9cab1680a18c1a18757cdac9d3"
integrity sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==
dependencies:
semver "^7.6.3"
semver "^7.3.5"
node-abi@^3.3.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.8.0.tgz#679957dc8e7aa47b0a02589dbfde4f77b29ccb32"
integrity sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==
dependencies:
semver "^7.3.5"
node-addon-api@3.1.0, node-addon-api@6.1.0, node-addon-api@7.1.0, node-addon-api@^3.0.2, node-addon-api@^3.1.0, node-addon-api@^4.0.0, node-addon-api@^4.3.0, node-addon-api@^8.3.0:
version "8.3.0"
@@ -3621,10 +3628,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
russh@0.1.24:
version "0.1.24"
resolved "https://registry.yarnpkg.com/russh/-/russh-0.1.24.tgz#dce27a3bc63eb78024db60e6767bc80cbf523b9a"
integrity sha512-lLMtXHJKL5uwRxwoFNDx71T7+qCXiL80qyGCRgQjYMV10gaW2AlI6mqcz3FVH8dXvdgK2ZE8DuSwlhCBK7schA==
russh@0.1.21:
version "0.1.21"
resolved "https://registry.yarnpkg.com/russh/-/russh-0.1.21.tgz#857b20c298a50a6657d1f1653ce9d149c68d6b5b"
integrity sha512-2zjOHTTDqaa3/pHUU+VCkoEqOXLpIpk9WATUaudtLGqy3n8Duz3WlhvyJzEmd+S+9eVGnQvyktpjtZziXLVHRA==
dependencies:
"@napi-rs/cli" "^2.18.3"
@@ -3674,11 +3681,6 @@ semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
semver@^7.6.3:
version "7.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
serialize-error@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-5.0.0.tgz#a7ebbcdb03a5d71a6ed8461ffe0fc1a1afed62ac"

View File

@@ -8,7 +8,7 @@
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<key>com.apple.security.device.microphone</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>

View File

@@ -12,7 +12,6 @@
"@angular/platform-browser-dynamic": "^15.2.6",
"@biesbjerg/ngx-translate-extract-marker": "^1.0.0",
"@electron/notarize": "^1.2.3",
"@electron/rebuild": "^4",
"@fortawesome/fontawesome-free": "^6.4.0",
"@ng-bootstrap/ng-bootstrap": "^14.1.0",
"@ngtools/webpack": "^15.2.5",
@@ -40,10 +39,11 @@
"cross-env": "7.0.3",
"css-loader": "^6.7.3",
"deep-equal": "2.0.5",
"electron": "^36.4",
"electron-builder": "^26.0",
"electron": "^32.2.7",
"electron-builder": "^26.0.0-alpha.10",
"electron-download": "^4.1.1",
"electron-installer-snap": "^5.1.0",
"@electron/rebuild": "^3.7.1",
"eslint": "^8.48.0",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.28.1",
@@ -55,7 +55,7 @@
"lru-cache": "^6.0.0",
"macos-release": "^3.3.0",
"ngx-toastr": "^16.0.2",
"node-abi": "^4",
"node-abi": "^3.71.0",
"npmlog": "6.0.2",
"npx": "^10.2.2",
"patch-package": "^6.4.7",
@@ -96,8 +96,7 @@
"*/pug": "^3",
"lzma-native": "^8.0.6",
"**/graceful-fs": "^4.2.4",
"nan": "2.22.2",
"node-abi": "4.9.0",
"nan": "2.22.0",
"node-gyp": "^10.0.0"
},
"scripts": {

View File

@@ -1,5 +1,5 @@
diff --git a/node_modules/app-builder-lib/out/appInfo.js b/node_modules/app-builder-lib/out/appInfo.js
index d159c17..eb48466 100644
index 7fbbef7..0821807 100644
--- a/node_modules/app-builder-lib/out/appInfo.js
+++ b/node_modules/app-builder-lib/out/appInfo.js
@@ -116,9 +116,7 @@ class AppInfo {

View File

@@ -31,7 +31,6 @@ export const builtinPlugins = [
'tabby-electron',
'tabby-plugin-manager',
'tabby-linkifier',
'tabby-auto-sudo-password',
]
export const packagesWithDocs = [

View File

@@ -1,23 +0,0 @@
{
"name": "tabby-auto-sudo-password",
"version": "1.0.197-nightly.1",
"description": "Offers to automatically paste saved sudo password in SSH sessions",
"keywords": [
"tabby-builtin-plugin"
],
"main": "dist/index.js",
"typings": "typings/index.d.ts",
"scripts": {
"build": "webpack --progress --color --display-modules",
"watch": "webpack --progress --color --watch"
},
"files": [
"dist",
"typings"
],
"devDependencies": {
"ansi-colors": "^4.1.1"
},
"author": "Tabby Developers",
"license": "MIT"
}

View File

@@ -1,89 +0,0 @@
import colors from 'ansi-colors'
import { Injectable } from '@angular/core'
import { TerminalDecorator, BaseTerminalTabComponent, XTermFrontend, SessionMiddleware } from 'tabby-terminal'
import { SSHProfile, SSHTabComponent, PasswordStorageService } from 'tabby-ssh'
const SUDO_PROMPT_REGEX = /^\[sudo\] password for ([^:]+):\s*$/im
export class AutoSudoPasswordMiddleware extends SessionMiddleware {
private pendingPasswordToPaste: string | null = null
private pasteHint = `${colors.black.bgBlackBright(' Tabby ')} ${colors.gray('Press Enter to paste saved password')}`
private pasteHintLength = colors.stripColor(this.pasteHint).length
constructor (
private profile: SSHProfile,
private ps: PasswordStorageService,
) { super() }
feedFromSession (data: Buffer): void {
const text = data.toString('utf-8')
const match = SUDO_PROMPT_REGEX.exec(text)
if (match) {
const username = match[1]
this.handlePrompt(username)
}
this.outputToTerminal.next(data)
}
feedFromTerminal (data: Buffer): void {
if (this.pendingPasswordToPaste) {
const backspaces = Buffer.alloc(this.pasteHintLength, 8) // backspace
const spaces = Buffer.alloc(this.pasteHintLength, 32) // space
const clear = Buffer.concat([backspaces, spaces, backspaces])
this.outputToTerminal.next(clear)
if (data.length === 1 && data[0] === 13) { // Enter key
this.outputToSession.next(Buffer.from(this.pendingPasswordToPaste + '\n'))
this.pendingPasswordToPaste = null
return
} else {
this.pendingPasswordToPaste = null
}
}
this.outputToSession.next(data)
}
async handlePrompt (username: string): Promise<void> {
console.log(`Detected sudo prompt for user: ${username}`)
const pw = await this.ps.loadPassword(this.profile)
if (pw) {
this.outputToTerminal.next(Buffer.from(this.pasteHint))
this.pendingPasswordToPaste = pw
}
}
async loadPassword (username: string): Promise<string| null> {
if (this.profile.options.user !== username) {
return null
}
return this.ps.loadPassword(this.profile)
}
}
@Injectable()
export class AutoSudoPasswordDecorator extends TerminalDecorator {
constructor (
private ps: PasswordStorageService,
) {
super()
}
private attachToSession (tab: SSHTabComponent) {
if (!tab.session) {
return
}
tab.session.middleware.unshift(new AutoSudoPasswordMiddleware(tab.profile, this.ps))
}
attach (tab: BaseTerminalTabComponent<any>): void {
if (!(tab.frontend instanceof XTermFrontend) || !(tab instanceof SSHTabComponent)) {
return
}
setTimeout(() => {
this.attachToSession(tab)
this.subscribeUntilDetached(tab, tab.sessionChanged$.subscribe(() => {
this.attachToSession(tab)
}))
})
}
}

View File

@@ -1,16 +0,0 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { NgModule } from '@angular/core'
import { ToastrModule } from 'ngx-toastr'
import { TerminalDecorator } from 'tabby-terminal'
import { AutoSudoPasswordDecorator } from './decorator'
@NgModule({
imports: [
ToastrModule,
],
providers: [
{ provide: TerminalDecorator, useClass: AutoSudoPasswordDecorator, multi: true },
],
})
export default class AutoSudoPasswordModule { }

View File

@@ -1,7 +0,0 @@
{
"extends": "../tsconfig.json",
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"baseUrl": "src",
}
}

View File

@@ -1,14 +0,0 @@
{
"extends": "../tsconfig.json",
"exclude": ["node_modules", "dist", "typings"],
"compilerOptions": {
"baseUrl": "src",
"emitDeclarationOnly": true,
"declaration": true,
"declarationDir": "./typings",
"paths": {
"tabby-*": ["../../tabby-*"],
"*": ["../../app/node_modules/*"]
}
}
}

View File

@@ -1,10 +0,0 @@
import * as path from 'path'
import * as url from 'url'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
import config from '../webpack.plugin.config.mjs'
export default () => config({
name: 'auto-sudo-password',
dirname: __dirname,
})

View File

@@ -1,8 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
ansi-colors@^4.1.1:
version "4.1.3"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==

View File

@@ -14,7 +14,7 @@
"files": [
"dist"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"peerDependencies": {
"@angular/core": "^15",

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"bootstrap": "^5.3.0-alpha.1",

View File

@@ -10,7 +10,7 @@ export { Theme } from './theme'
export { TabContextMenuItemProvider } from './tabContextMenuProvider'
export { SelectorOption } from './selector'
export { CLIHandler, CLIEvent } from './cli'
export { PlatformService, ClipboardContent, MessageBoxResult, MessageBoxOptions, FileDownload, FileUpload, FileTransfer, HTMLFileUpload, FileUploadOptions, DirectoryUpload, DirectoryDownload, PlatformTheme } from './platform'
export { PlatformService, ClipboardContent, MessageBoxResult, MessageBoxOptions, FileDownload, FileUpload, FileTransfer, HTMLFileUpload, FileUploadOptions, DirectoryUpload } from './platform'
export { MenuItemOptions } from './menu'
export { BootstrapData, PluginInfo, BOOTSTRAP_DATA } from './mainProcess'
export { HostWindowService } from './hostWindow'
@@ -36,7 +36,7 @@ export { TabsService, NewTabParameters, TabComponentType } from '../services/tab
export { UpdaterService } from '../services/updater.service'
export { VaultService, Vault, VaultSecret, VaultFileSecret, VAULT_SECRET_TYPE_FILE, StoredVault, VaultSecretKey } from '../services/vault.service'
export { FileProvidersService } from '../services/fileProviders.service'
export { LocaleService, TabbyFormatedDatePipe } from '../services/locale.service'
export { LocaleService } from '../services/locale.service'
export { TranslateService } from '@ngx-translate/core'
export * from '../utils'
export { UTF8Splitter } from '../utfSplitter'

View File

@@ -22,6 +22,7 @@ export interface MessageBoxResult {
export abstract class FileTransfer {
abstract getName (): string
abstract getMode (): number
abstract getSize (): number
abstract close (): void
@@ -33,16 +34,8 @@ export abstract class FileTransfer {
return this.completedBytes
}
getStatus (): string {
return this.status
}
getTotalSize (): number {
return this.totalSize
}
isComplete (): boolean {
return this.completed
return this.completedBytes >= this.getSize()
}
isCancelled (): boolean {
@@ -54,18 +47,6 @@ export abstract class FileTransfer {
this.close()
}
setStatus (status: string): void {
this.status = status
}
setTotalSize (size: number): void {
this.totalSize = size
}
setCompleted (completed: boolean): void {
this.completed = completed
}
protected increaseProgress (bytes: number): void {
if (!bytes) {
return
@@ -76,26 +57,16 @@ export abstract class FileTransfer {
}
private completedBytes = 0
private totalSize = 0
private lastChunkStartTime = Date.now()
private lastChunkSpeed = 0
private cancelled = false
private completed = false
private status = ''
}
export abstract class FileDownload extends FileTransfer {
abstract write (buffer: Uint8Array): Promise<void>
}
export abstract class DirectoryDownload extends FileTransfer {
abstract createDirectory (relativePath: string): Promise<void>
abstract createFile (relativePath: string, mode: number, size: number): Promise<FileDownload>
}
export abstract class FileUpload extends FileTransfer {
abstract getMode (): number
abstract read (): Promise<Uint8Array>
async readAll (): Promise<Uint8Array> {
@@ -156,7 +127,6 @@ export abstract class PlatformService {
abstract saveConfig (content: string): Promise<void>
abstract startDownload (name: string, mode: number, size: number): Promise<FileDownload|null>
abstract startDownloadDirectory (name: string, estimatedSize?: number): Promise<DirectoryDownload|null>
abstract startUpload (options?: FileUploadOptions): Promise<FileUpload[]>
abstract startUploadDirectory (paths?: string[]): Promise<DirectoryUpload>
@@ -267,7 +237,7 @@ export abstract class PlatformService {
abstract setErrorHandler (handler: (_: any) => void): void
abstract popupContextMenu (menu: MenuItemOptions[], event?: MouseEvent): void
abstract showMessageBox (options: MessageBoxOptions): Promise<MessageBoxResult>
abstract pickDirectory (): Promise<string | null>
abstract pickDirectory (): Promise<string>
abstract quit (): void
}

View File

@@ -35,8 +35,7 @@ title-bar(
[@animateTab]='{value: "in", params: {size: targetTabSize}}',
[@.disabled]='hasVerticalTabs() || !config.store.accessibility.animations',
(click)='app.selectTab(tab)',
[class.fully-draggable]='hostApp.platform !== Platform.macOS',
[ngbTooltip]='tab.customTitle || tab.title'
[class.fully-draggable]='hostApp.platform !== Platform.macOS'
)
.btn-group.background
@@ -44,7 +43,7 @@ title-bar(
*ngFor='let button of leftToolbarButtons'
)
button.btn.btn-secondary.btn-tab-bar(
[ngbTooltip]='button.label',
[title]='button.label',
(click)='button.run && button.run()',
[fastHtmlBind]='button.icon'
)
@@ -56,7 +55,7 @@ title-bar(
)
button.btn.btn-secondary.btn-tab-bar(
[hidden]='activeTransfers.length == 0',
[ngbTooltip]='"File transfers"|translate',
title='File transfers',
ngbDropdownToggle
) !{require('../icons/transfers.svg')}
transfers-menu(
@@ -76,14 +75,14 @@ title-bar(
*ngFor='let button of rightToolbarButtons'
)
button.btn.btn-secondary.btn-tab-bar(
[ngbTooltip]='button.label',
[title]='button.label',
(click)='button.run && button.run()',
[fastHtmlBind]='button.icon'
)
button.btn.btn-secondary.btn-tab-bar.btn-update(
*ngIf='updatesAvailable',
[ngbTooltip]='"Update available - Click to install"|translate',
title='Update available - Click to install',
(click)='updater.update()'
) !{require('../icons/gift.svg')}

View File

@@ -13,6 +13,7 @@ profile-icon(
)
.name(
[title]='tab.customTitle || tab.title',
[class.no-hover]='config.store.terminal.hideCloseButton && config.store.terminal.hideTabOptionsButton'
cdkDrag,
cdkDragRootElement='tab-header',

View File

@@ -5,9 +5,7 @@
.icon(*ngIf='isDownload(transfer)') !{require('../icons/download.svg')}
.icon(*ngIf='!isDownload(transfer)') !{require('../icons/upload.svg')}
.main
label.no-wrap([ngbTooltip]='transfer.getName()')
| {{transfer.getName()}}
span.ms-2.text-muted(*ngIf='transfer.getStatus()') ({{transfer.getStatus()}})
label.no-wrap([title]='transfer.getName()') {{transfer.getName()}}
ngb-progressbar([type]='transfer.isComplete() ? "success" : transfer.isCancelled() ? "danger" : "info"', [value]='getProgress(transfer)')
.metadata
.size {{transfer.getSize()|filesize}}

View File

@@ -2,7 +2,7 @@ import { NgModule, ModuleWithProviders, LOCALE_ID } from '@angular/core'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { CommonModule } from '@angular/common'
import { FormsModule } from '@angular/forms'
import { NgbModule, NgbTooltipConfig } from '@ng-bootstrap/ng-bootstrap'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { NgxFilesizeModule } from 'ngx-filesize'
import { DragDropModule } from '@angular/cdk/drag-drop'
import { TranslateModule, TranslateCompiler, TranslateService, MissingTranslationHandler } from '@ngx-translate/core'
@@ -43,7 +43,7 @@ import { AppService } from './services/app.service'
import { ConfigService } from './services/config.service'
import { VaultFileProvider } from './services/vault.service'
import { HotkeysService } from './services/hotkeys.service'
import { CustomMissingTranslationHandler, LocaleService, TabbyFormatedDatePipe } from './services/locale.service'
import { CustomMissingTranslationHandler, LocaleService } from './services/locale.service'
import { CommandService } from './services/commands.service'
import { NewTheme } from './theme'
@@ -130,7 +130,6 @@ const PROVIDERS = [
DropZoneDirective,
CdkAutoDropGroup,
ProfileIconComponent,
TabbyFormatedDatePipe,
],
exports: [
AppRootComponent,
@@ -145,7 +144,6 @@ const PROVIDERS = [
TranslateModule,
CdkAutoDropGroup,
ProfileIconComponent,
TabbyFormatedDatePipe,
],
})
export default class AppModule { // eslint-disable-line @typescript-eslint/no-extraneous-class
@@ -155,7 +153,6 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
platform: PlatformService,
hotkeys: HotkeysService,
commands: CommandService,
ngbTooltipConfig: NgbTooltipConfig,
public locale: LocaleService,
private translate: TranslateService,
private profilesService: ProfilesService,
@@ -202,10 +199,6 @@ export default class AppModule { // eslint-disable-line @typescript-eslint/no-ex
commands.run('core:profile-selector', {})
}
})
ngbTooltipConfig.openDelay = 750
ngbTooltipConfig.placement = 'top bottom auto'
ngbTooltipConfig.container = 'body'
}
async showSelector (provider: ProfileProvider<Profile>): Promise<void> {

View File

@@ -1,5 +1,5 @@
import { Injectable, Pipe, PipeTransform } from '@angular/core'
import { formatDate, registerLocaleData } from '@angular/common'
import { Injectable } from '@angular/core'
import { registerLocaleData } from '@angular/common'
import { TranslateService, MissingTranslationHandler } from '@ngx-translate/core'
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler'
@@ -257,15 +257,3 @@ export class LocaleService {
return this.locale
}
}
@Pipe({
name: 'tabbyDate',
})
export class TabbyFormatedDatePipe implements PipeTransform {
constructor (private locale: LocaleService) {}
transform (date: string): string {
return formatDate(date, 'medium', this.locale.getLocale())
}
}

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"peerDependencies": {
"@angular/core": "^15",

View File

@@ -50,7 +50,7 @@ export class DockMenuService {
])
}
if (this.hostApp.platform === Platform.macOS) {
this.electron.app.dock?.setMenu(this.electron.Menu.buildFromTemplate(
this.electron.app.dock.setMenu(this.electron.Menu.buildFromTemplate(
[
...[...this.profilesService.getRecentProfiles(), ...profiles].map(profile => ({
label: profile.name,

View File

@@ -5,11 +5,12 @@ import * as os from 'os'
import promiseIpc, { RendererProcessType } from 'electron-promise-ipc'
import { execFile } from 'mz/child_process'
import { Injectable, NgZone } from '@angular/core'
import { PlatformService, ClipboardContent, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, DirectoryUpload, FileUpload, FileDownload, DirectoryDownload, FileUploadOptions, wrapPromise, TranslateService, FileTransfer, PlatformTheme } from 'tabby-core'
import { PlatformService, ClipboardContent, Platform, MenuItemOptions, MessageBoxOptions, MessageBoxResult, DirectoryUpload, FileUpload, FileDownload, FileUploadOptions, wrapPromise, TranslateService } from 'tabby-core'
import { ElectronService } from '../services/electron.service'
import { ElectronHostWindow } from './hostWindow.service'
import { ShellIntegrationService } from './shellIntegration.service'
import { ElectronHostAppService } from './hostApp.service'
import { PlatformTheme } from '../../../tabby-core/src/api/platform'
import { configPath } from '../../../app/lib/config'
const fontManager = require('fontmanager-redux') // eslint-disable-line
@@ -271,48 +272,19 @@ export class ElectronPlatformService extends PlatformService {
return transfer
}
async startDownloadDirectory (name: string, estimatedSize?: number): Promise<DirectoryDownload|null> {
const selectedFolder = await this.pickDirectory(this.translate.instant('Select destination folder for {name}', { name }), this.translate.instant('Download here'))
if (!selectedFolder) {
return null
}
let downloadPath = path.join(selectedFolder, name)
let counter = 1
while (fsSync.existsSync(downloadPath)) {
downloadPath = path.join(selectedFolder, `${name} (${counter})`)
counter++
}
const transfer = new ElectronDirectoryDownload(downloadPath, name, estimatedSize ?? 0, this.electron, this.zone)
await wrapPromise(this.zone, transfer.open())
this.fileTransferStarted.next(transfer)
return transfer
}
_registerFileTransfer (transfer: FileTransfer): void {
this.fileTransferStarted.next(transfer)
}
setErrorHandler (handler: (_: any) => void): void {
this.electron.ipcRenderer.on('uncaughtException', (_$event, err) => {
handler(err)
})
}
async pickDirectory (title?: string, buttonLabel?: string): Promise<string | null> {
const result = await this.electron.dialog.showOpenDialog(
async pickDirectory (): Promise<string> {
return (await this.electron.dialog.showOpenDialog(
this.hostWindow.getWindow(),
{
title,
buttonLabel,
properties: ['openDirectory', 'showHiddenFiles'],
},
)
if (result.canceled || !result.filePaths.length) {
return null
}
return result.filePaths[0]
)).filePaths[0]
}
getTheme (): PlatformTheme {
@@ -341,7 +313,6 @@ class ElectronFileUpload extends FileUpload {
const stat = await fs.stat(this.filePath)
this.size = stat.size
this.mode = stat.mode
this.setTotalSize(this.size)
this.file = await fs.open(this.filePath, 'r')
}
@@ -360,9 +331,6 @@ class ElectronFileUpload extends FileUpload {
async read (): Promise<Uint8Array> {
const result = await this.file.read(this.buffer, 0, this.buffer.length, null)
this.increaseProgress(result.bytesRead)
if (this.getCompletedBytes() >= this.getSize()) {
this.setCompleted(true)
}
return this.buffer.slice(0, result.bytesRead)
}
@@ -384,7 +352,6 @@ class ElectronFileDownload extends FileDownload {
) {
super()
this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension')
this.setTotalSize(size)
}
async open (): Promise<void> {
@@ -395,6 +362,10 @@ class ElectronFileDownload extends FileDownload {
return path.basename(this.filePath)
}
getMode (): number {
return this.mode
}
getSize (): number {
return this.size
}
@@ -406,9 +377,6 @@ class ElectronFileDownload extends FileDownload {
this.increaseProgress(result.bytesWritten)
pos += result.bytesWritten
}
if (this.getCompletedBytes() >= this.getSize()) {
this.setCompleted(true)
}
}
close (): void {
@@ -416,49 +384,3 @@ class ElectronFileDownload extends FileDownload {
this.file.close()
}
}
class ElectronDirectoryDownload extends DirectoryDownload {
private powerSaveBlocker = 0
constructor (
private basePath: string,
private name: string,
estimatedSize: number,
private electron: ElectronService,
private zone: NgZone,
) {
super()
this.powerSaveBlocker = electron.powerSaveBlocker.start('prevent-app-suspension')
this.setTotalSize(estimatedSize)
}
async open (): Promise<void> {
await fs.mkdir(this.basePath, { recursive: true })
}
getName (): string {
return this.name
}
getSize (): number {
return this.getTotalSize()
}
async createDirectory (relativePath: string): Promise<void> {
const fullPath = path.join(this.basePath, relativePath)
await fs.mkdir(fullPath, { recursive: true })
}
async createFile (relativePath: string, mode: number, size: number): Promise<FileDownload> {
const fullPath = path.join(this.basePath, relativePath)
await fs.mkdir(path.dirname(fullPath), { recursive: true })
const fileDownload = new ElectronFileDownload(fullPath, mode, size, this.electron)
await wrapPromise(this.zone, fileDownload.open())
return fileDownload
}
close (): void {
this.electron.powerSaveBlocker.stop(this.powerSaveBlocker)
}
}

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@xterm/addon-web-links": "^0.10.0",

View File

@@ -13,12 +13,4 @@ export abstract class LinkHandler {
}
abstract handle (uri: string, tab?: BaseTerminalTabComponent<any>): void
private _fullMatchRegex: RegExp | null = null
get fullMatchRegex (): RegExp {
if (!this._fullMatchRegex) {
this._fullMatchRegex = new RegExp(`^${this.regex.source}$`)
}
return this._fullMatchRegex
}
}

View File

@@ -31,7 +31,7 @@ export class LinkHighlighterDecorator extends TerminalDecorator {
const openLink = async uri => {
for (const handler of this.handlers) {
if (!handler.fullMatchRegex.test(uri)) {
if (!handler.regex.test(uri)) {
continue
}
if (!await handler.verify(await handler.convert(uri, tab), tab)) {

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"ansi-colors": "^4.1.1",

View File

@@ -28,10 +28,6 @@ export class LocalProfileSettingsComponent implements ProfileSettingsComponent<L
// return
// }
const cwd = await this.platform.pickDirectory()
if (!cwd) {
return
}
this.profile.options.cwd = cwd
this.profile.options.cwd = await this.platform.pickDirectory()
}
}

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/semver": "^7.1.0",

View File

@@ -100,7 +100,6 @@ export class PluginsSettingsTabComponent {
this.busy.delete(plugin.name)
this.config.requestRestart()
} catch (err) {
console.error('Error installing plugin', plugin.name, err)
this.erroredPlugin = plugin.name
this.errorMessage = err
this.busy.delete(plugin.name)
@@ -115,7 +114,6 @@ export class PluginsSettingsTabComponent {
this.busy.delete(plugin.name)
this.config.requestRestart()
} catch (err) {
console.error('Error uninstalling plugin', plugin.name, err)
this.erroredPlugin = plugin.name
this.errorMessage = err
this.busy.delete(plugin.name)

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/node": "14.14.14",

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/marked": "^5.0.1",

View File

@@ -67,7 +67,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
div {{cfg.name}}
small.text-muted(
translate='Modified on {date}',
[translateParams]='{date: cfg.modified_at|tabbyDate}'
[translateParams]='{date: cfg.modified_at|date:"medium"}'
)
.me-auto
button.btn.btn-link.ms-1(

View File

@@ -145,5 +145,4 @@ export class ConfigSyncSettingsTabComponent extends BaseComponent {
openTabbyWebInfo () {
this.platform.openExternal('https://github.com/Eugeny/tabby-web')
}
}

View File

@@ -8,5 +8,5 @@
)
div(*ngFor='let release of releases')
h1 {{release.name}}
.text-muted {{release.version}} / {{release.date|tabbyDate}}
.text-muted {{release.version}} / {{release.date|date:'mediumDate'}}
section([fastHtmlBind]='release.content')

View File

@@ -45,5 +45,4 @@ export class ReleaseNotesComponent extends BaseTabComponent {
onScrolled () {
this.loadReleases(this.lastPage + 1)
}
}

View File

@@ -17,7 +17,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/node": "20.3.1",

View File

@@ -6,7 +6,6 @@ export const supportedAlgorithms = {
[SSHAlgorithmType.HOSTKEY]: russh.getSupportedKeyTypes().filter(x => x !== 'none'),
[SSHAlgorithmType.CIPHER]: russh.getSupportedCiphers().filter(x => x !== 'clear'),
[SSHAlgorithmType.HMAC]: russh.getSupportedMACs().filter(x => x !== 'none'),
[SSHAlgorithmType.COMPRESSION]: russh.getSupportedCompressionAlgorithms().reverse(),
}
export const defaultAlgorithms = {
@@ -43,9 +42,4 @@ export const defaultAlgorithms = {
'hmac-sha1-etm@openssh.com',
'hmac-sha1',
],
[SSHAlgorithmType.COMPRESSION]: [
'zlib@openssh.com',
'zlib',
'none',
],
}

View File

@@ -5,8 +5,6 @@ export enum SSHAlgorithmType {
KEX = 'kex',
CIPHER = 'cipher',
HOSTKEY = 'serverHostKey',
COMPRESSION = 'compression',
}
export interface SSHProfile extends ConnectableTerminalProfile {

View File

@@ -17,10 +17,6 @@
.breadcrumb-spacer.flex-grow-1.h-100((dblclick)='editPath()')
button.btn.btn-link.btn-sm.flex-shrink-0.d-flex(*ngIf='!showFilter', (click)='showFilter = true')
i.fas.fa-filter.me-1
div(translate) Filter
button.btn.btn-link.btn-sm.flex-shrink-0.d-flex((click)='openCreateDirectoryModal()')
i.fas.fa-plus.me-1
div(translate) Create directory
@@ -35,19 +31,6 @@
button.btn.btn-link.text-decoration-none((click)='close()') !{require('../../../tabby-core/src/icons/times.svg')}
.filter-bar.px-3.py-2.border-bottom(*ngIf='showFilter')
.input-group
input.form-control(
type='text',
placeholder='Filter...',
autofocus,
[(ngModel)]='filterText',
(input)='onFilterChange()',
(keydown.escape)='clearFilter()'
)
button.btn.btn-secondary((click)='clearFilter()')
i.fas.fa-times
.body(dropZone, (transfer)='uploadOneFolder($event)')
a.alert.alert-info.d-flex.align-items-center(
*ngIf='shouldShowCWDTip && !cwdDetectionAvailable',
@@ -64,13 +47,13 @@
div(*ngIf='fileList === null', translate) Loading
.list-group.list-group-light(*ngIf='fileList !== null')
.list-group-item.list-group-item-action.d-flex.align-items-center(
*ngIf='path !== "/" && (!showFilter || filterText.trim() === "")',
*ngIf='path !== "/"',
(click)='goUp()'
)
i.fas.fa-fw.fa-level-up-alt
div(translate) Go up
.list-group-item.list-group-item-action.d-flex.align-items-center(
*ngFor='let item of filteredFileList',
*ngFor='let item of fileList',
(contextmenu)='showContextMenu(item, $event)',
(click)='open(item)'
)
@@ -78,8 +61,5 @@
div {{item.name}}
.me-auto
.size(*ngIf='!item.isDirectory') {{item.size|filesize}}
.date {{item.modified|tabbyDate}}
.date {{item.modified|date:'medium'}}
.mode {{getModeString(item)}}
.alert.alert-info.text-center.mt-3(*ngIf='fileList !== null && filteredFileList.length === 0 && showFilter && filterText.trim() !== ""')
i.fas.fa-search.me-2
span(translate) No files match the filter "{{filterText}}"

View File

@@ -9,10 +9,6 @@
flex: none;
}
> .filter-bar {
flex: none;
}
> .body {
padding: 10px 20px;
flex: 1 1 0;

View File

@@ -1,7 +1,7 @@
import * as C from 'constants'
import { posix as path } from 'path'
import { Component, Input, Output, EventEmitter, Inject, Optional } from '@angular/core'
import { FileUpload, DirectoryUpload, DirectoryDownload, MenuItemOptions, NotificationsService, PlatformService } from 'tabby-core'
import { FileUpload, DirectoryUpload, MenuItemOptions, NotificationsService, PlatformService } from 'tabby-core'
import { SFTPSession, SFTPFile } from '../session/sftp'
import { SSHSession } from '../session/ssh'
import { SFTPContextMenuItemProvider } from '../api'
@@ -23,14 +23,11 @@ export class SFTPPanelComponent {
@Output() closed = new EventEmitter<void>()
sftp: SFTPSession
fileList: SFTPFile[]|null = null
filteredFileList: SFTPFile[] = []
@Input() path = '/'
@Output() pathChange = new EventEmitter<string>()
pathSegments: PathSegment[] = []
@Input() cwdDetectionAvailable = false
editingPath: string|null = null
showFilter = false
filterText = ''
constructor (
private ngbModal: NgbModal,
@@ -57,8 +54,6 @@ export class SFTPPanelComponent {
this.path = newPath
this.pathChange.next(this.path)
this.clearFilter()
let p = newPath
this.pathSegments = []
while (p !== '/') {
@@ -70,7 +65,6 @@ export class SFTPPanelComponent {
}
this.fileList = null
this.filteredFileList = []
try {
this.fileList = await this.sftp.readdir(this.path)
} catch (error) {
@@ -85,8 +79,6 @@ export class SFTPPanelComponent {
this.fileList.sort((a, b) =>
dirKey(b) - dirKey(a) ||
a.name.localeCompare(b.name))
this.updateFilteredList()
}
getFileType (fileExtension: string): string {
@@ -228,68 +220,6 @@ export class SFTPPanelComponent {
this.sftp.download(itemPath, transfer)
}
async downloadFolder (folder: SFTPFile): Promise<void> {
try {
const transfer = await this.platform.startDownloadDirectory(folder.name, 0)
if (!transfer) {
return
}
// Start background size calculation and download simultaneously
const sizeCalculationPromise = this.calculateFolderSizeAndUpdate(folder, transfer)
const downloadPromise = this.downloadFolderRecursive(folder, transfer, '')
try {
await Promise.all([sizeCalculationPromise, downloadPromise])
transfer.setStatus('')
transfer.setCompleted(true)
} catch (error) {
transfer.cancel()
throw error
} finally {
transfer.close()
}
} catch (error) {
this.notifications.error(`Failed to download folder: ${error.message}`)
throw error
}
}
private async calculateFolderSizeAndUpdate (folder: SFTPFile, transfer: DirectoryDownload) {
let totalSize = 0
const items = await this.sftp.readdir(folder.fullPath)
for (const item of items) {
if (item.isDirectory) {
totalSize += await this.calculateFolderSizeAndUpdate(item, transfer)
} else {
totalSize += item.size
}
transfer.setTotalSize(totalSize)
}
return totalSize
}
private async downloadFolderRecursive (folder: SFTPFile, transfer: DirectoryDownload, relativePath: string): Promise<void> {
const items = await this.sftp.readdir(folder.fullPath)
for (const item of items) {
if (transfer.isCancelled()) {
throw new Error('Download cancelled')
}
const itemRelativePath = relativePath ? `${relativePath}/${item.name}` : item.name
transfer.setStatus(itemRelativePath)
if (item.isDirectory) {
await transfer.createDirectory(itemRelativePath)
await this.downloadFolderRecursive(item, transfer, itemRelativePath)
} else {
const fileDownload = await transfer.createFile(itemRelativePath, item.mode, item.size)
await this.sftp.download(item.fullPath, fileDownload)
}
}
}
getModeString (item: SFTPFile): string {
const s = 'SGdrwxrwxrwx'
const e = ' ---------'
@@ -343,30 +273,4 @@ export class SFTPPanelComponent {
close (): void {
this.closed.emit()
}
clearFilter (): void {
this.showFilter = false
this.filterText = ''
this.updateFilteredList()
}
onFilterChange (): void {
this.updateFilteredList()
}
private updateFilteredList (): void {
if (!this.fileList) {
this.filteredFileList = []
return
}
if (!this.showFilter || this.filterText.trim() === '') {
this.filteredFileList = this.fileList
return
}
this.filteredFileList = this.fileList.filter(item =>
item.name.toLowerCase().includes(this.filterText.toLowerCase()),
)
}
}

View File

@@ -285,13 +285,7 @@ ul.nav-tabs(ngbNav, #nav='ngbNav')
.w-75
div(*ngFor='let alg of supportedAlgorithms.serverHostKey')
checkbox([text]='alg', [(ngModel)]='algorithms.serverHostKey[alg]')
.form-line.align-items-start
.header
.title Compression
.w-75
div(*ngFor='let alg of supportedAlgorithms.compression')
checkbox([text]='alg', [(ngModel)]='algorithms.compression[alg]')
li(ngbNavItem)
a(ngbNavLink, translate) Colors
ng-template(ngbNavContent)

View File

@@ -107,7 +107,7 @@ export class SSHProfileSettingsComponent {
this.profile.options.algorithms![k] = Object.entries(this.algorithms[k])
.filter(([_, v]) => !!v)
.map(([key, _]) => key)
if(k !== SSHAlgorithmType.COMPRESSION) { this.profile.options.algorithms![k].sort() }
this.profile.options.algorithms![k].sort()
}
if (this.connectionMode !== 'jumpHost') {

View File

@@ -179,7 +179,6 @@ export class SSHTabComponent extends ConnectableTerminalTabComponent<SSHProfile>
try {
await this.initializeSessionMaybeMultiplex(false)
} catch (e) {
console.error('SSH session initialization failed', e)
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
return
}

View File

@@ -66,5 +66,4 @@ export default class SSHModule { }
export * from './api'
export { SFTPFile, SFTPSession } from './session/sftp'
export { SFTPPanelComponent, SSHTabComponent }
export { PasswordStorageService } from './services/passwordStorage.service'
export { SFTPPanelComponent }

View File

@@ -20,7 +20,7 @@ export class SSHProfilesService extends QuickConnectProfileProvider<SSHProfile>
auth: null,
password: null,
privateKeys: [],
keepaliveInterval: null,
keepaliveInterval: 5000,
keepaliveCountMax: 10,
readyTimeout: null,
x11: false,
@@ -55,7 +55,7 @@ export class SSHProfilesService extends QuickConnectProfileProvider<SSHProfile>
super()
for (const k of Object.values(SSHAlgorithmType)) {
this.configDefaults.options.algorithms[k] = [...defaultAlgorithms[k]]
if (k !== SSHAlgorithmType.COMPRESSION) { this.configDefaults.options.algorithms[k].sort() }
this.configDefaults.options.algorithms[k].sort()
}
}

View File

@@ -162,11 +162,9 @@ export class SSHSession {
this.allAuthMethods = [{ type: 'none' }]
if (!this.profile.options.auth || this.profile.options.auth === 'publicKey') {
if (this.profile.options.privateKeys?.length) {
for (let pk of this.profile.options.privateKeys) {
for (const pk of this.profile.options.privateKeys) {
// eslint-disable-next-line @typescript-eslint/init-declarations
let contents: Buffer
pk = pk.replace('%h', this.profile.options.host)
pk = pk.replace('%r', this.profile.options.user)
try {
contents = await this.fileProviders.retrieveFile(pk)
} catch (error) {
@@ -315,9 +313,8 @@ export class SSHSession {
kex: this.profile.options.algorithms?.[SSHAlgorithmType.KEX]?.filter(x => supportedAlgorithms[SSHAlgorithmType.KEX].includes(x)),
mac: this.profile.options.algorithms?.[SSHAlgorithmType.HMAC]?.filter(x => supportedAlgorithms[SSHAlgorithmType.HMAC].includes(x)),
key: this.profile.options.algorithms?.[SSHAlgorithmType.HOSTKEY]?.filter(x => supportedAlgorithms[SSHAlgorithmType.HOSTKEY].includes(x)),
compression: this.profile.options.algorithms?.[SSHAlgorithmType.COMPRESSION]?.filter(x => supportedAlgorithms[SSHAlgorithmType.COMPRESSION].includes(x)),
},
keepaliveIntervalSeconds: this.profile.options.keepaliveInterval ? Math.round(this.profile.options.keepaliveInterval / 1000) : undefined,
keepaliveIntervalSeconds: Math.round((this.profile.options.keepaliveInterval ?? 15000) / 1000),
keepaliveCountMax: this.profile.options.keepaliveCountMax,
connectionTimeoutSeconds: this.profile.options.readyTimeout ? Math.round(this.profile.options.readyTimeout / 1000) : undefined,
},

View File

@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { MenuItemOptions, PlatformService, TranslateService, HostAppService, Platform } from 'tabby-core'
import { MenuItemOptions, PlatformService, TranslateService } from 'tabby-core'
import { SFTPSession, SFTPFile } from './session/sftp'
import { SFTPContextMenuItemProvider } from './api'
import { SFTPDeleteModalComponent } from './components/sftpDeleteModal.component'
@@ -16,49 +16,37 @@ export class CommonSFTPContextMenu extends SFTPContextMenuItemProvider {
private platform: PlatformService,
private ngbModal: NgbModal,
private translate: TranslateService,
private hostApp: HostAppService,
) {
super()
}
async getItems (item: SFTPFile, panel: SFTPPanelComponent): Promise<MenuItemOptions[]> {
const items: MenuItemOptions[] = [
return [
{
click: async () => {
await panel.openCreateDirectoryModal()
},
label: this.translate.instant('Create directory'),
},
]
// Add download folder option for directories (only in electron)
if (item.isDirectory && this.hostApp.platform !== Platform.Web) {
items.push({
click: () => panel.downloadFolder(item),
label: this.translate.instant('Download directory'),
})
}
items.push({
click: async () => {
if ((await this.platform.showMessageBox({
type: 'warning',
message: this.translate.instant('Delete {fullPath}?', item),
defaultId: 0,
cancelId: 1,
buttons: [
this.translate.instant('Delete'),
this.translate.instant('Cancel'),
],
})).response === 0) {
await this.deleteItem(item, panel.sftp)
panel.navigate(panel.path)
}
{
click: async () => {
if ((await this.platform.showMessageBox({
type: 'warning',
message: this.translate.instant('Delete {fullPath}?', item),
defaultId: 0,
cancelId: 1,
buttons: [
this.translate.instant('Delete'),
this.translate.instant('Cancel'),
],
})).response === 0) {
await this.deleteItem(item, panel.sftp)
panel.navigate(panel.path)
}
},
label: this.translate.instant('Delete'),
},
label: this.translate.instant('Delete'),
})
return items
]
}
async deleteItem (item: SFTPFile, session: SFTPSession): Promise<void> {

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"ansi-colors": "^4.1.1",

View File

@@ -16,7 +16,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@xterm/addon-canvas": "^0.6.0",

View File

@@ -17,8 +17,6 @@ import { getTerminalBackgroundColor } from '../helpers'
const INACTIVE_TAB_UNLOAD_DELAY = 1000 * 30
const OSC_FOCUS_IN = Buffer.from('\x1b[I')
const OSC_FOCUS_OUT = Buffer.from('\x1b[O')
/**
* A class to base your custom terminal tabs on
@@ -311,16 +309,10 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
case 'scroll-to-top':
this.frontend?.scrollToTop()
break
case 'scroll-page-up':
case 'scroll-up':
this.frontend?.scrollPages(-1)
break
case 'scroll-up':
this.frontend?.scrollLines(-1)
break
case 'scroll-down':
this.frontend?.scrollLines(1)
break
case 'scroll-page-down':
this.frontend?.scrollPages(1)
break
case 'scroll-to-bottom':
@@ -496,7 +488,7 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
data = Buffer.from(data, 'utf-8')
}
this.session?.feedFromTerminal(data)
if (this.config.store.terminal.scrollOnInput && !data.equals(OSC_FOCUS_IN) && !data.equals(OSC_FOCUS_OUT)) {
if (this.config.store.terminal.scrollOnInput) {
this.frontend?.scrollToBottom()
}
}
@@ -544,7 +536,7 @@ export class BaseTerminalTabComponent<P extends BaseTerminalProfile> extends Bas
}
if (!this.alternateScreenActive) {
if ((data.includes('\r') || data.includes('\n')) && this.config.store.terminal.warnOnMultilinePaste) {
if (data.includes('\r') && this.config.store.terminal.warnOnMultilinePaste) {
const buttons = [
this.translate.instant('Paste'),
this.translate.instant('Cancel'),

View File

@@ -6,8 +6,6 @@
[class.text-danger]='state.resultCount == 0',
(click)='$event.stopPropagation()',
(keyup.enter)='findPrevious()',
(keyup.up)='findPrevious()',
(keyup.down)='findNext()',
(keyup.esc)='close.emit()',
[placeholder]='"Search"|translate'
)
@@ -16,14 +14,14 @@
ng-container(*ngIf='state.resultCount > 0')
button.btn.btn-link(
(click)='findPrevious()',
[ngbTooltip]='"Search up"|translate',
ngbTooltip='Search up',
placement='bottom',
[fastHtmlBind]='icons.arrowUp'
)
button.btn.btn-link(
(click)='findNext()',
[ngbTooltip]='"Search down"|translate',
ngbTooltip='Search down',
placement='bottom',
[fastHtmlBind]='icons.arrowDown'
)
@@ -34,7 +32,7 @@ button.btn(
(click)='options.caseSensitive = !options.caseSensitive; saveSearchOptions()',
[class.btn-link]='!options.caseSensitive',
[class.btn-info]='options.caseSensitive',
[ngbTooltip]='"Case sensitivity"|translate',
ngbTooltip='Case sensitivity',
placement='bottom',
[fastHtmlBind]='icons.case'
)
@@ -43,7 +41,7 @@ button.btn(
(click)='options.regex = !options.regex; saveSearchOptions()',
[class.btn-link]='!options.regex',
[class.btn-info]='options.regex',
[ngbTooltip]='"Regular expression"|translate',
ngbTooltip='Regular expression',
placement='bottom',
[fastHtmlBind]='icons.regexp'
)
@@ -52,7 +50,7 @@ button.btn(
(click)='options.wholeWord = !options.wholeWord; saveSearchOptions()',
[class.btn-link]='!options.wholeWord',
[class.btn-info]='options.wholeWord',
[ngbTooltip]='"Whole word"|translate',
ngbTooltip='Whole word',
placement='bottom',
[fastHtmlBind]='icons.wholeWord'
)

View File

@@ -101,10 +101,8 @@ export class TerminalConfigProvider extends ConfigProvider {
'⌘-⌥-Shift-I',
],
'scroll-to-top': ['Shift-PageUp'],
'scroll-page-up': ['⌥-PageUp'],
'scroll-up': ['Ctrl-Shift-Up'],
'scroll-down': ['Ctrl-Shift-Down'],
'scroll-page-down': ['⌥-PageDown'],
'scroll-up': ['⌥-PageUp'],
'scroll-down': ['⌥-PageDown'],
'scroll-to-bottom': ['Shift-PageDown'],
},
},
@@ -154,10 +152,8 @@ export class TerminalConfigProvider extends ConfigProvider {
'Ctrl-Alt-Shift-I',
],
'scroll-to-top': ['Ctrl-PageUp'],
'scroll-page-up': ['Alt-PageUp'],
'scroll-up': ['Ctrl-Shift-Up'],
'scroll-down': ['Ctrl-Shift-Down'],
'scroll-page-down': ['Alt-PageDown'],
'scroll-up': ['Alt-PageUp'],
'scroll-down': ['Alt-PageDown'],
'scroll-to-bottom': ['Ctrl-PageDown'],
},
},
@@ -205,10 +201,8 @@ export class TerminalConfigProvider extends ConfigProvider {
'Ctrl-Alt-Shift-I',
],
'scroll-to-top': ['Ctrl-PageUp'],
'scroll-page-up': ['Alt-PageUp'],
'scroll-up': ['Ctrl-Shift-Up'],
'scroll-down': ['Ctrl-Shift-Down'],
'scroll-page-down': ['Alt-PageDown'],
'scroll-up': ['Alt-PageUp'],
'scroll-down': ['Alt-PageDown'],
'scroll-to-bottom': ['Ctrl-PageDown'],
},
},

View File

@@ -27,7 +27,7 @@ class ZModemMiddleware extends SessionMiddleware {
this.logger = log.create('zmodem')
this.sentry = new ZModem.Sentry({
to_terminal: data => {
if (this.isActive && this.activeSession) {
if (this.isActive) {
this.outputToTerminal.next(Buffer.from(data))
}
},
@@ -42,32 +42,25 @@ class ZModemMiddleware extends SessionMiddleware {
},
on_retract: () => {
this.showMessage('transfer cancelled')
this.activeSession = null
this.isActive = false
},
})
}
feedFromSession (data: Buffer): void {
if (this.isActive || this.activeSession) {
const chunkSize = 1024
for (let i = 0; i <= Math.floor(data.length / chunkSize); i++) {
try {
this.sentry.consume(data)
this.sentry.consume(Buffer.from(data.slice(i * chunkSize, (i + 1) * chunkSize)))
} catch (e) {
this.showMessage(colors.bgRed.black(' Error ') + ' ' + e)
this.logger.error('protocol error', e)
this.activeSession?.abort()
this.activeSession.abort()
this.activeSession = null
this.isActive = false
// Don't forward the problematic data to terminal
return
}
} else {
try {
this.sentry.consume(data)
} catch (e) {
this.logger.error('zmodem detection error', e)
}
}
if (!this.isActive) {
this.outputToTerminal.next(data)
}
}
@@ -80,35 +73,25 @@ class ZModemMiddleware extends SessionMiddleware {
this.activeSession = zsession
this.logger.info('new session', zsession)
try {
if (zsession.type === 'send') {
const transfers = await this.platform.startUpload({ multiple: true })
let filesRemaining = transfers.length
let sizeRemaining = transfers.reduce((a, b) => a + b.getSize(), 0)
for (const transfer of transfers) {
await this.sendFile(zsession, transfer, filesRemaining, sizeRemaining)
filesRemaining--
sizeRemaining -= transfer.getSize()
}
await zsession.close()
} else {
zsession.on('offer', xfer => {
this.receiveFile(xfer, zsession)
})
zsession.start()
await new Promise(resolve => zsession.on('session_end', resolve))
if (zsession.type === 'send') {
const transfers = await this.platform.startUpload({ multiple: true })
let filesRemaining = transfers.length
let sizeRemaining = transfers.reduce((a, b) => a + b.getSize(), 0)
for (const transfer of transfers) {
await this.sendFile(zsession, transfer, filesRemaining, sizeRemaining)
filesRemaining--
sizeRemaining -= transfer.getSize()
}
this.activeSession = null
await zsession.close()
} else {
zsession.on('offer', xfer => {
this.receiveFile(xfer, zsession)
})
this.showMessage(colors.bgBlue.black(' ZMODEM ') + ' Complete')
} catch (error) {
this.logger.error('ZMODEM session error', error)
this.showMessage(colors.bgRed.black(' ZMODEM ') + ` Session failed: ${error.message}`)
try {
zsession.abort()
} catch { }
} finally {
zsession.start()
await new Promise(resolve => zsession.on('session_end', resolve))
this.activeSession = null
}
}

View File

@@ -77,7 +77,6 @@ export abstract class Frontend {
abstract visualBell (): void
abstract scrollToTop (): void
abstract scrollLines (amount: number): void
abstract scrollPages (pages: number): void
abstract scrollToBottom (): void

View File

@@ -357,10 +357,6 @@ export class XTermFrontend extends Frontend {
this.xterm.scrollPages(pages)
}
scrollLines (amount: number): void {
this.xterm.scrollLines(amount)
}
scrollToBottom (): void {
this.xtermCore._scrollToBottom()
}

View File

@@ -86,19 +86,11 @@ export class TerminalHotkeyProvider extends HotkeyProvider {
name: this.translate.instant('Scroll terminal to top'),
},
{
id: 'scroll-page-up',
id: 'scroll-up',
name: this.translate.instant('Scroll terminal one page up'),
},
{
id: 'scroll-up',
name: this.translate.instant('Scroll terminal one line up'),
},
{
id: 'scroll-down',
name: this.translate.instant('Scroll terminal one line down'),
},
{
id: 'scroll-page-down',
name: this.translate.instant('Scroll terminal one page down'),
},
{
@@ -121,4 +113,3 @@ export class TerminalHotkeyProvider extends HotkeyProvider {
return this.hotkeys
}
}

View File

@@ -3,7 +3,7 @@ import { Subject, Observable } from 'rxjs'
import { SessionMiddleware } from '../api/middleware'
const OSCPrefix = Buffer.from('\x1b]')
const OSCSuffixes = [Buffer.from('\x07'), Buffer.from('\x1b\\')]
const OSCSuffix = Buffer.from('\x07')
export class OSCProcessor extends SessionMiddleware {
get cwdReported$ (): Observable<string> { return this.cwdReported }
@@ -14,22 +14,11 @@ export class OSCProcessor extends SessionMiddleware {
feedFromSession (data: Buffer): void {
let startIndex = 0
while (data.includes(OSCPrefix, startIndex)) {
const si = startIndex
if (!OSCSuffixes.some(s => data.includes(s, si))) {
break
}
while (data.includes(OSCPrefix, startIndex) && data.includes(OSCSuffix, startIndex)) {
const params = data.subarray(data.indexOf(OSCPrefix, startIndex) + OSCPrefix.length)
const oscString = params.subarray(0, params.indexOf(OSCSuffix)).toString()
const [closesSuffix, closestSuffixIndex] = OSCSuffixes
.map((suffix): [Buffer, number] => [suffix, params.indexOf(suffix)])
.filter(([_, index]) => index !== -1)
.sort(([_, a], [__, b]) => a - b)[0]
const oscString = params.subarray(0, closestSuffixIndex).toString()
startIndex = data.indexOf(closesSuffix, startIndex) + closesSuffix.length
startIndex = data.indexOf(OSCSuffix, startIndex) + OSCSuffix.length
const [oscCodeString, ...oscParams] = oscString.split(';')
const oscCode = parseInt(oscCodeString)

View File

@@ -11,7 +11,7 @@
"data",
"dist"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"devDependencies": {
"@types/webpack-env": "^1.16.0"

View File

@@ -15,7 +15,7 @@
"dist",
"typings"
],
"author": "Tabby Developers",
"author": "Eugene Pankov",
"license": "MIT",
"peerDependencies": {
"@angular/core": "^15"

View File

@@ -2,7 +2,7 @@ import '@vaadin/vaadin-context-menu'
import copyToClipboard from 'copy-text-to-clipboard'
import { Injectable, Inject } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { PlatformService, ClipboardContent, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileUploadOptions, FileDownload, DirectoryDownload, HTMLFileUpload, DirectoryUpload } from 'tabby-core'
import { PlatformService, ClipboardContent, MenuItemOptions, MessageBoxOptions, MessageBoxResult, FileUpload, FileUploadOptions, FileDownload, HTMLFileUpload, DirectoryUpload } from 'tabby-core'
// eslint-disable-next-line no-duplicate-imports
import type { ContextMenuElement, ContextMenuItem } from '@vaadin/vaadin-context-menu'
@@ -114,10 +114,6 @@ export class WebPlatformService extends PlatformService {
return transfer
}
async startDownloadDirectory (_name: string, _estimatedSize?: number): Promise<DirectoryDownload|null> {
throw new Error('Unsupported')
}
startUpload (options?: FileUploadOptions): Promise<FileUpload[]> {
return new Promise(resolve => {
this.fileSelector.onchange = () => {

177
yarn.lock
View File

@@ -418,20 +418,20 @@
tar "^6.0.5"
yargs "^17.0.1"
"@electron/rebuild@^4":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-4.0.1.tgz#0620d5bb71a0b8b09a86fb9fa979244e1fcc10bf"
integrity sha512-iMGXb6Ib7H/Q3v+BKZJoETgF9g6KMNZVbsO4b7Dmpgb5qTFqyFTzqW9F3TOSHdybv2vKYKzSS9OiZL+dcJb+1Q==
"@electron/rebuild@^3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@electron/rebuild/-/rebuild-3.7.1.tgz#27ed124f7f1dbed92b222aabe68c0e4a3e6c5cea"
integrity sha512-sKGD+xav4Gh25+LcLY0rjIwcCFTw+f/HU1pB48UVbwxXXRGaXEqIH0AaYKN46dgd/7+6kuiDXzoyAEvx1zCsdw==
dependencies:
"@electron/node-gyp" "https://github.com/electron/node-gyp#06b29aafb7708acef8b3669835c8a7857ebc92d2"
"@malept/cross-spawn-promise" "^2.0.0"
chalk "^4.0.0"
debug "^4.1.1"
detect-libc "^2.0.1"
fs-extra "^10.0.0"
got "^11.7.0"
graceful-fs "^4.2.11"
node-abi "^4.2.0"
node-api-version "^0.2.1"
node-gyp "^11.2.0"
node-abi "^3.45.0"
node-api-version "^0.2.0"
ora "^5.1.0"
read-binary-file-arch "^1.0.6"
semver "^7.3.5"
@@ -961,12 +961,12 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.1.tgz#e8a83f1aa8b649377bb1fb5d7bac5cb90e784dfe"
integrity sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==
"@types/node@^22.7.7":
version "22.15.21"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.21.tgz#196ef14fe20d87f7caf1e7b39832767f9a995b77"
integrity sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==
"@types/node@^20.9.0":
version "20.14.14"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.14.tgz#6b655d4a88623b0edb98300bb9dd2107225f885e"
integrity sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==
dependencies:
undici-types "~6.21.0"
undici-types "~5.26.4"
"@types/parse5@^5":
version "5.0.3"
@@ -1476,10 +1476,10 @@ app-builder-bin@5.0.0-alpha.12:
resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz#2daf82f8badc698e0adcc95ba36af4ff0650dc80"
integrity sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==
app-builder-lib@26.0.12:
version "26.0.12"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.0.12.tgz#2e33df936e0f78d4266b058ece90308ea981eefb"
integrity sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==
app-builder-lib@26.0.0-alpha.10:
version "26.0.0-alpha.10"
resolved "https://registry.yarnpkg.com/app-builder-lib/-/app-builder-lib-26.0.0-alpha.10.tgz#3eb3f64ffa5e995595ad61497c5e7a0c2d64b817"
integrity sha512-9K3MulGK7j+En4KjH3aq7AzDqe8nn35x7O9l5kwl16nWFdBthcdy1IKsx9CgjMSF+eTNctOZlXwnYiPiGzY+GQ==
dependencies:
"@develar/schema-utils" "~2.6.5"
"@electron/asar" "3.2.18"
@@ -1491,15 +1491,16 @@ app-builder-lib@26.0.12:
"@malept/flatpak-bundler" "^0.4.0"
"@types/fs-extra" "9.0.13"
async-exit-hook "^2.0.1"
builder-util "26.0.11"
builder-util-runtime "9.3.1"
bluebird-lst "^1.0.9"
builder-util "26.0.0-alpha.10"
builder-util-runtime "9.3.0-alpha.0"
chromium-pickle-js "^0.2.0"
config-file-ts "0.2.8-rc1"
debug "^4.3.4"
dotenv "^16.4.5"
dotenv-expand "^11.0.6"
ejs "^3.1.8"
electron-publish "26.0.11"
electron-publish "26.0.0-alpha.10"
fs-extra "^10.1.0"
hosted-git-info "^4.1.0"
is-ci "^3.0.0"
@@ -1508,12 +1509,10 @@ app-builder-lib@26.0.12:
json5 "^2.2.3"
lazy-val "^1.0.5"
minimatch "^10.0.0"
plist "3.1.0"
resedit "^1.7.0"
semver "^7.3.8"
tar "^6.1.12"
temp-file "^3.4.0"
tiny-async-pool "1.3.0"
apply-loader@2.0.0:
version "2.0.0"
@@ -1845,7 +1844,14 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@^3.5.0:
bluebird-lst@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/bluebird-lst/-/bluebird-lst-1.0.9.tgz#a64a0e4365658b9ab5fe875eb9dfb694189bb41c"
integrity sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==
dependencies:
bluebird "^3.5.5"
bluebird@^3.5.0, bluebird@^3.5.5:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
@@ -2016,23 +2022,24 @@ buffer@^5.1.0:
base64-js "^1.3.1"
ieee754 "^1.1.13"
builder-util-runtime@9.3.1:
version "9.3.1"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
integrity sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==
builder-util-runtime@9.3.0-alpha.0:
version "9.3.0-alpha.0"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.0-alpha.0.tgz#c4639ae24a74d2e0f4eb324100af3040300bae62"
integrity sha512-EriE6Uf15niqdkyjBOS09OrXlhEV0HKhnATlI9n63vCoisnvvRTQNgoR2MV9vnBmNGhavBPZXPWPItv4QMDVfw==
dependencies:
debug "^4.3.4"
sax "^1.2.4"
builder-util@26.0.11:
version "26.0.11"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.0.11.tgz#ad85b92c93f2b976b973e1d87337e0c6813fcb8f"
integrity sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==
builder-util@26.0.0-alpha.10:
version "26.0.0-alpha.10"
resolved "https://registry.yarnpkg.com/builder-util/-/builder-util-26.0.0-alpha.10.tgz#f445a530c28da6e3650b93e92263c06c6f89a2cc"
integrity sha512-RMVOAgdd+tzwpyF5C8gx9KjzwdUvkUEubpsHTvb2JwlQnBcyBc6hyVCU2gt2MivQCLbjCOEgsUX1/zHrWDqGfg==
dependencies:
"7zip-bin" "~5.2.0"
"@types/debug" "^4.1.6"
app-builder-bin "5.0.0-alpha.12"
builder-util-runtime "9.3.1"
bluebird-lst "^1.0.9"
builder-util-runtime "9.3.0-alpha.0"
chalk "^4.1.2"
cross-spawn "^7.0.6"
debug "^4.3.4"
@@ -2045,7 +2052,6 @@ builder-util@26.0.11:
source-map-support "^0.5.19"
stat-mode "^1.0.0"
temp-file "^3.4.0"
tiny-async-pool "1.3.0"
builtin-modules@^1.0.0:
version "1.1.1"
@@ -2932,14 +2938,14 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
dmg-builder@26.0.12:
version "26.0.12"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.0.12.tgz#6996ad0bab80a861c9a7b33ee9734d4f60566b46"
integrity sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==
dmg-builder@26.0.0-alpha.10:
version "26.0.0-alpha.10"
resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-26.0.0-alpha.10.tgz#d4d908922005a0c852d0919a7dd0b8f77d3c4bd0"
integrity sha512-RWzCNLLu4dGIvBf8kBzjF/zI5aMOSA149S1V2NgAA4La8f8ghdJAm/DI5crSb2zDijFLyTNmUGTtvU6eHgiZyQ==
dependencies:
app-builder-lib "26.0.12"
builder-util "26.0.11"
builder-util-runtime "9.3.1"
app-builder-lib "26.0.0-alpha.10"
builder-util "26.0.0-alpha.10"
builder-util-runtime "9.3.0-alpha.0"
fs-extra "^10.1.0"
iconv-lite "^0.6.2"
js-yaml "^4.1.0"
@@ -3061,16 +3067,16 @@ ejs@^3.1.8:
dependencies:
jake "^10.8.5"
electron-builder@^26.0:
version "26.0.12"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.12.tgz#797af2e70efdd96c9ea5d8a8164b8728c90d65ff"
integrity sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==
electron-builder@^26.0.0-alpha.10:
version "26.0.0-alpha.10"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-26.0.0-alpha.10.tgz#6f629f5f1f3340286af71cabd12d94edc53f15ea"
integrity sha512-QTitqOlP5aZ/8zhnxqjRb6BxSR7Kvwv07PoBGeIXADwSPHQhKhZ+S+GRFzUSYQrMTTJLGzUHbnAes6fZ3uThEA==
dependencies:
app-builder-lib "26.0.12"
builder-util "26.0.11"
builder-util-runtime "9.3.1"
app-builder-lib "26.0.0-alpha.10"
builder-util "26.0.0-alpha.10"
builder-util-runtime "9.3.0-alpha.0"
chalk "^4.1.2"
dmg-builder "26.0.12"
dmg-builder "26.0.0-alpha.10"
fs-extra "^10.1.0"
is-ci "^3.0.0"
lazy-val "^1.0.5"
@@ -3160,14 +3166,14 @@ electron-localshortcut@^3.1.0:
keyboardevent-from-electron-accelerator "^2.0.0"
keyboardevents-areequal "^0.2.1"
electron-publish@26.0.11:
version "26.0.11"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.0.11.tgz#92c9329a101af2836d9d228c82966eca1eee9a7b"
integrity sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==
electron-publish@26.0.0-alpha.10:
version "26.0.0-alpha.10"
resolved "https://registry.yarnpkg.com/electron-publish/-/electron-publish-26.0.0-alpha.10.tgz#16ac95acca2d796ca00c7a90ca27ebf31855f284"
integrity sha512-yUkCJD7MLN57d6PJ8PMcBCR35xytA+jHyrOiS/H0hlmTOWq1sXN+tIBylX4h0dD/C6mn75/y5eE156Pe2nccPw==
dependencies:
"@types/fs-extra" "^9.0.11"
builder-util "26.0.11"
builder-util-runtime "9.3.1"
builder-util "26.0.0-alpha.10"
builder-util-runtime "9.3.0-alpha.0"
chalk "^4.1.2"
form-data "^4.0.0"
fs-extra "^10.1.0"
@@ -3179,13 +3185,13 @@ electron-to-chromium@^1.4.284:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.286.tgz#0e039de59135f44ab9a8ec9025e53a9135eba11f"
integrity sha512-Vp3CVhmYpgf4iXNKAucoQUDcCrBQX3XLBtwgFqP9BUXuucgvAV9zWp1kYU7LL9j4++s9O+12cb3wMtN4SJy6UQ==
electron@^36.4:
version "36.7.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-36.7.1.tgz#73bbb460c60f529e00b9d3eff78fd135c42172ea"
integrity sha512-vkih7vbmWT6O8+VWFt3a9FMLUZn0O4piR20nTX0IL/d9tz9RjpzoMvHqpI2CE1Rxew9bCzrg7FpgtcTdY6dlyw==
electron@^32.2.7:
version "32.2.7"
resolved "https://registry.yarnpkg.com/electron/-/electron-32.2.7.tgz#4eaf78534c99ba060da5bb002c737206be33f225"
integrity sha512-y8jbQRG3xogF70XPlk5c+dWe5iRfUBo28o2NMpKd/CcW7ENIaWtBlGima8/8nmRdAaYTy1+yIt6KB0Lon9H8cA==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^22.7.7"
"@types/node" "^20.9.0"
extract-zip "^2.0.1"
elliptic@^6.5.3:
@@ -4433,7 +4439,7 @@ got@^6.7.1:
unzip-response "^2.0.1"
url-parse-lax "^1.0.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9, graceful-fs@~4.1.11:
graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9, graceful-fs@~4.1.11:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
@@ -6216,10 +6222,10 @@ mute-stream@~0.0.4:
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
nan@2.22.2:
version "2.22.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.2.tgz#6b504fd029fb8f38c0990e52ad5c26772fdacfbb"
integrity sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==
nan@2.22.0:
version "2.22.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3"
integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==
nanoid@^3.3.4:
version "3.3.4"
@@ -6261,12 +6267,12 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-abi@4.9.0, node-abi@^3.45.0, node-abi@^4, node-abi@^4.2.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-4.9.0.tgz#ca6dabf7991e54bf3ba6d8d32641e1b84f305263"
integrity sha512-0isb3h+AXUblx5Iv0mnYy2WsErH+dk2e9iXJXdKAtS076Q5hP+scQhp6P4tvDeVlOBlG3ROKvkpQHtbORllq2A==
node-abi@^3.45.0, node-abi@^3.71.0:
version "3.71.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.71.0.tgz#52d84bbcd8575efb71468fbaa1f9a49b2c242038"
integrity sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==
dependencies:
semver "^7.6.3"
semver "^7.3.5"
node-addon-api@^1.6.3:
version "1.7.2"
@@ -6285,13 +6291,6 @@ node-api-version@^0.2.0:
dependencies:
semver "^7.3.5"
node-api-version@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.1.tgz#19bad54f6d65628cbee4e607a325e4488ace2de9"
integrity sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==
dependencies:
semver "^7.3.5"
node-fetch-npm@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.1.tgz"
@@ -6313,7 +6312,7 @@ node-gyp-build@^4.2.1:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739"
integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==
node-gyp@^10.0.0, node-gyp@^11.2.0, node-gyp@~3.6.2:
node-gyp@^10.0.0, node-gyp@~3.6.2:
version "10.3.1"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.3.1.tgz#1dd1a1a1c6c5c59da1a76aea06a062786b2c8a1a"
integrity sha512-Pp3nFHBThHzVtNY7U6JfPjvT/DTE8+o/4xKsLQtBoU+j2HLsGlhcfzflAoUreaJbNmYnX+LlLi0qjV8kpyO6xQ==
@@ -7154,7 +7153,7 @@ pkg-up@^2.0.0:
dependencies:
find-up "^2.1.0"
plist@3.1.0, plist@^3.0.4, plist@^3.0.5, plist@^3.1.0:
plist@^3.0.4, plist@^3.0.5, plist@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9"
integrity sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==
@@ -8144,7 +8143,7 @@ semver@^6.2.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.8:
semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.8:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
@@ -8158,11 +8157,6 @@ semver@^7.3.2, semver@^7.5.3, semver@^7.5.4:
dependencies:
lru-cache "^6.0.0"
semver@^7.3.5, semver@^7.6.3:
version "7.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
@@ -8947,13 +8941,6 @@ timed-out@^4.0.0:
resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz"
integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
tiny-async-pool@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz#c013e1b369095e7005db5595f95e646cca6ef8a5"
integrity sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==
dependencies:
semver "^5.5.0"
tinyqueue@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
@@ -9239,10 +9226,10 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
undici-types@~6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
unique-filename@^1.1.0, unique-filename@~1.1.0:
version "1.1.0"