Skip to content

release-2.8.0 - #1456

Merged
LukeGus merged 185 commits into
mainfrom
dev-2.8.0
Sep 20, 2026
Merged

LukeGus merged 185 commits into
mainfrom
dev-2.8.0

Conversation

@LukeGus

@LukeGus LukeGus commented Sep 20, 2026

Copy link
Copy Markdown
Member

Tip

Termix is free and always will be. If it's useful to you, consider donating to support development.

A side-by-side local and remote file manager for desktop, a new tab for transferring files straight between two servers, collaboration rooms, Step CA and 1Password credential support, per-host Web Endpoints, credential sharing with users and roles, and a large batch of connection, sync, and remote desktop fixes.

YouTube
Architecture Windows Linux Mac Android iOS
x86-64 (64-bit) EXE · MSI · Portable AppImage · DEB · Portable DMG — —
AArch64 (ARM64) — AppImage · DEB · Portable DMG APK (1.5.0) IPA (1.5.0)
ARMv7 (32-bit) — AppImage · DEB · Portable — — —
x86-32 (32-bit) EXE · MSI · Portable — — — —
Universal Chocolatey Flatpak DMG · App Store · Homebrew — —

Update Log:

  • Added a side-by-side local and remote view to the desktop file manager
  • Added a dedicated tab for transferring files directly between two servers
  • Added a dedicated Port Forwarding tab to the desktop app sidebar
  • Added inline autosuggestions in the terminal using command history
  • Added collaboration rooms for sharing a terminal or remote desktop session with a group
  • Added Step CA as an SSH authentication type
  • Added 1Password Connect as a credential source for SSH
  • Added the ability to share credentials with specific users and roles
  • Added automatic sharing for hosts added to an already-shared folder
  • Added per-host Web Endpoints
  • Added quick connect for RDP and VNC
  • Added a button to pin the sidebar rail open instead of it auto-collapsing
  • Added a compact snippet list option
  • Added copy/paste support to the local terminal
  • Added a terminal copy-on-select option
  • Added tab switching and command palette actions to custom keybindings
  • Added selectable host temperature sensors
  • Added accessible interface font choices
  • Added VNC display zoom controls
  • Added more actions to the host right-click context menu
  • Added white label branding for admins
  • Added support for additional TOTP authenticator apps
  • Added the ability to open RDP, VNC, and Telnet sessions directly from the desktop app
  • Improved file manager navigation
  • Improved motion and transition animations throughout the app
  • Improved macOS packaging and terminal keyboard shortcuts
  • Improved the terminal AI assistant with a toggle for terminal context
  • Began plugin backend work (cut cross feature imports, added plugin DB tables, made the rail/tab system use registries, and updated nginx and manifests for plugins)

Bug Fixes:

  • Private AI custom endpoints failing to connect
  • Proxmox credential guest imports not working correctly
  • Fleet command results layout being broken
  • Synced client tunnel endpoints not matching the source host
  • Proxmox jump host settings not persisting after a sync
  • Command palette keyboard navigation not working correctly
  • Split layout selection not being restored
  • macOS VNC connections failing to establish
  • Rapid VNC scroll wheel input queuing up and making the remote desktop keep scrolling after you stop
  • Remote desktop connections timing out unexpectedly
  • RDP clipboard paste not working across some browsers
  • Process inspector command column showing truncated commands
  • RDP drive redirection uploads failing on the default deployment
  • A terminal session that expired silently reconnected without explaining Auto-Tmux as an option
  • Host status wrongly showing as offline when nothing was actively watching it
  • Shared RDP users not being prompted for credentials when required
  • Protected file reads failing without a sudo retry
  • Host status polling unnecessarily authenticating over SSH
  • Some host protocol settings being dropped when left unset
  • Remote sync reauthentication failures not being surfaced to the user
  • Dashboard metrics sessions not recovering after expiring
  • RDP file uploads to redirected drives failing
  • Connection toolbar visibility being inconsistent
  • Host list scroll position resetting incorrectly after editing a host
  • Live SSH sessions not being reflected in host status
  • Vault authentication not working in the file manager
  • Running snippets and commands on shared hosts being blocked
  • Chunked file uploads failing due to a contract mismatch
  • Bulk uploads failing partway through
  • Local echo not being disabled on the terminal alternate screen
  • Invalid timezones in the clock widget crashing the homepage
  • Connection origin setting not being preserved when editing a host
  • Local login notifications not appearing after a remote sync
  • Passkey login not working in the desktop app
  • Proxmox guest discovery commands failing without elevated permissions
  • File transfer completion toasts staying on screen permanently
  • SSH key type not being clearable once set
  • Local echo appearing during password prompts inside other programs
  • The desktop app hanging on a loading screen with no message when the embedded backend's port was in use
  • Backend ports silently failing to bind, leaving a feature dead with no error in the logs
  • Imported host settings and jump host references being lost or broken after import
  • SSH agent forwarding breaking after certain unsupported extensions
  • Sidebar host tree continuing to render while hidden, wasting resources
  • macOS Alt+digit tab shortcuts producing characters instead of switching tabs
  • macOS Option key producing Meta/escape sequences instead of special characters by default
  • Dashboard not opening the correct remote desktop protocol
  • Version checks overwriting the local version number on failure
  • SFTP directory creation relying on shell access
  • GPU acceleration opt-out setting being ignored on desktop
  • Remote-only hosts leaking into local tab persistence on desktop
  • Host metrics not being collected correctly on macOS and Windows hosts
  • CORS rejecting requests by default when no allowed origins were configured
  • Streamed SFTP uploads not completing correctly
  • The SSH connection pool not enforcing its connection limits, letting stale connections pile up
  • Local connections to shared hosts being blocked
  • Client-to-server tunnels using the wrong bind or target address in some setups
  • SSH host key changes not being surfaced as a warning
  • Nested subhost parent references breaking after a remote sync
  • Termix ID certificates missing principals needed for some servers to accept them
  • TOTP being skipped without a fully verified WebAuthn check
  • SSH connections not verifying the resolved server's host identity
  • The OPKSSH binary not having its integrity verified before use
  • Several transitive dependency security advisories
  • Various HTTP and application trust boundary hardening (CSP, Docker, config defaults)

ZacharyZcR and others added 30 commits August 23, 2026 22:38
Co-authored-by: Angad Singh <angad@singhangad.in>
…1321)

Bumps the docker-major-updates group in /docker with 1 update: node.


Updates `node` from 24-slim to 26-slim

---
updated-dependencies:
- dependency-name: node
  dependency-version: 26-slim
  dependency-type: direct:production
  dependency-group: docker-major-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

Bumps the dev-patch-updates group with 15 updates:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/view](https://github.com/codemirror/view) | `6.43.7` | `6.43.9` |
| [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) | `21.2.1` | `21.2.2` |
| [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) | `21.2.0` | `21.2.2` |
| [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) | `7.0.0` | `7.0.1` |
| [@testing-library/user-event](https://github.com/testing-library/user-event) | `14.6.1` | `14.6.5` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.10` | `4.1.11` |
| [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `4.1.10` | `4.1.11` |
| [concurrently](https://github.com/open-cli-tools/concurrently) | `10.0.4` | `10.0.5` |
| [cytoscape](https://github.com/cytoscape/cytoscape.js) | `3.34.0` | `3.34.1` |
| [eslint](https://github.com/eslint/eslint) | `10.8.0` | `10.8.1` |
| [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) | `0.5.3` | `0.5.4` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.11` | `17.0.12` |
| [sonner](https://github.com/emilkowalski/sonner) | `2.0.7` | `2.0.8` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.2.0` | `8.2.2` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.10` | `4.1.11` |


Updates `@codemirror/view` from 6.43.7 to 6.43.9
- [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/view/commits)

Updates `@commitlint/cli` from 21.2.1 to 21.2.2
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/cli/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v21.2.2/@commitlint/cli)

Updates `@commitlint/config-conventional` from 21.2.0 to 21.2.2
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v21.2.2/@commitlint/config-conventional)

Updates `@testing-library/jest-dom` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](testing-library/jest-dom@v7.0.0...v7.0.1)

Updates `@testing-library/user-event` from 14.6.1 to 14.6.5
- [Release notes](https://github.com/testing-library/user-event/releases)
- [Changelog](https://github.com/testing-library/user-event/blob/main/CHANGELOG.md)
- [Commits](testing-library/user-event@v14.6.1...v14.6.5)

Updates `@vitest/coverage-v8` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/coverage-v8)

Updates `@vitest/ui` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/ui)

Updates `concurrently` from 10.0.4 to 10.0.5
- [Release notes](https://github.com/open-cli-tools/concurrently/releases)
- [Commits](open-cli-tools/concurrently@v10.0.4...v10.0.5)

Updates `cytoscape` from 3.34.0 to 3.34.1
- [Release notes](https://github.com/cytoscape/cytoscape.js/releases)
- [Commits](cytoscape/cytoscape.js@v3.34.0...v3.34.1)

Updates `eslint` from 10.8.0 to 10.8.1
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](eslint/eslint@v10.8.0...v10.8.1)

Updates `eslint-plugin-react-refresh` from 0.5.3 to 0.5.4
- [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases)
- [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md)
- [Commits](ArnaudBarre/eslint-plugin-react-refresh@v0.5.3...v0.5.4)

Updates `react-i18next` from 17.0.11 to 17.0.12
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](i18next/react-i18next@v17.0.11...v17.0.12)

Updates `sonner` from 2.0.7 to 2.0.8
- [Release notes](https://github.com/emilkowalski/sonner/releases)
- [Commits](emilkowalski/sonner@v2.0.7...v2.0.8)

Updates `vite` from 8.2.0 to 8.2.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.2.2/packages/vite)

Updates `vitest` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/vitest)

---
updated-dependencies:
- dependency-name: "@codemirror/view"
  dependency-version: 6.43.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@commitlint/cli"
  dependency-version: 21.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@commitlint/config-conventional"
  dependency-version: 21.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@testing-library/jest-dom"
  dependency-version: 7.0.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@testing-library/user-event"
  dependency-version: 14.6.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/ui"
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: concurrently
  dependency-version: 10.0.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: cytoscape
  dependency-version: 3.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: eslint
  dependency-version: 10.8.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: eslint-plugin-react-refresh
  dependency-version: 0.5.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: react-i18next
  dependency-version: 17.0.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: sonner
  dependency-version: 2.0.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: vite
  dependency-version: 8.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: vitest
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the prod-patch-updates group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@tanstack/react-virtual](https://github.com/TanStack/virtual/tree/HEAD/packages/react-virtual) | `3.14.9` | `3.14.10` |
| [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) | `13.0.2` | `13.0.3` |
| [jose](https://github.com/panva/jose) | `6.2.8` | `6.2.9` |
| [mysql2](https://github.com/sidorares/node-mysql2) | `3.23.2` | `3.23.4` |
| [ws](https://github.com/websockets/ws) | `8.21.1` | `8.21.3` |


Updates `@tanstack/react-virtual` from 3.14.9 to 3.14.10
- [Release notes](https://github.com/TanStack/virtual/releases)
- [Changelog](https://github.com/TanStack/virtual/blob/main/packages/react-virtual/CHANGELOG.md)
- [Commits](https://github.com/TanStack/virtual/commits/@tanstack/react-virtual@3.14.10/packages/react-virtual)

Updates `better-sqlite3` from 13.0.2 to 13.0.3
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](WiseLibs/better-sqlite3@v13.0.2...v13.0.3)

Updates `jose` from 6.2.8 to 6.2.9
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](panva/jose@v6.2.8...v6.2.9)

Updates `mysql2` from 3.23.2 to 3.23.4
- [Release notes](https://github.com/sidorares/node-mysql2/releases)
- [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md)
- [Commits](sidorares/node-mysql2@v3.23.2...v3.23.4)

Updates `ws` from 8.21.1 to 8.21.3
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](websockets/ws@8.21.1...8.21.3)

---
updated-dependencies:
- dependency-name: "@tanstack/react-virtual"
  dependency-version: 3.14.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: better-sqlite3
  dependency-version: 13.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: jose
  dependency-version: 6.2.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: mysql2
  dependency-version: 3.23.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: ws
  dependency-version: 8.21.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the major-updates group with 1 update: [motion](https://github.com/motiondivision/motion).


Updates `motion` from 12.43.0 to 13.1.1
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](motiondivision/motion@v12.43.0...v13.1.1)

---
updated-dependencies:
- dependency-name: motion
  dependency-version: 13.1.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat: add semantic motion system

* feat: animate session workspace transitions

* feat: refine motion accessibility and transfer feedback
* feat: enforce RBAC and harden collaboration features

- Mount requirePermission on hosts/snippets/credentials/automations/AI routes
- Seed and backfill system role permissions on every dialect at startup
- Support personal credential overrides for RDP/VNC/Telnet shared hosts
- Broadcast participant presence in shared terminal sessions
- Make audit log forwarding configurable from the admin panel
- Add role members endpoint and snippet folder sharing

* fix: enforce RBAC across split routes
* feat: add collaboration rooms with switchable presenter

Rooms are a group of members watching one stage - the live SSH/RDP/VNC
session the current presenter shares. Any member can take over the
stage; the host can invite, force-stop and end the meeting. Stages
reuse session_shares (new room share type), so gating, recording,
expiry and the global sharing toggle all apply unchanged.

* feat: add stage control handoff to collaboration rooms

The presenter or host can grant any member write access to the live
stage and take it back; members can raise a hand to ask. SSH flips the
participant's permission on the live gate; RDP/VNC re-mint the viewer's
join token. Control clears on every stage switch.

* feat: guest links, role invites and invite awareness for collab rooms

- Anonymous guest link per room (host toggles/rotates), followed by
  polling the public resolve endpoint; SSH guests join over the terminal
  WS with roomGuestToken, guac guests get read-only join tokens
- Invite by role (expands to current members, snapshot semantics)
- Toast when a room you were invited to appears
- Stale stages are cleared lazily when the presenter is gone
- Telnet presenting, expired-tab fallback, documented single-instance
  and guac-kick limits
- Tests for the collab routes, room hub, share access and control flip

* fix: keep remote desktop collaboration read-only
LukeGus and others added 27 commits September 18, 2026 09:25
Used by docker, file-manager, and terminal alike, so it belongs
at the hosts root instead of under terminal/.
metrics subscribed to terminal's private online/offline pub-sub
module. Moved to hosts core so both sides depend on a shared
module instead of metrics reaching into terminal. Marked the
subscribe call with PLUGIN-EVENT for the future event bus.
notifyAutomationInternalEvent was in hosts/metrics/automation-bridge.ts
but is used by tunnel, host routes, user routes, and automations
engine itself, not just metrics. Moved it to hosts/automation-events.ts
so those callers depend on a shared module instead of metrics
internals. Left the metrics-specific notifiers in place.
Adds plugins, plugin_permission_grants, plugin_registries, and
plugin_install_counts tables plus their repositories. No routes or UI yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds register/unregister for plugin permission groups so the RBAC
catalog and validation can grow beyond the static list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat(host-metrics): add NVIDIA GPU metrics card

Collect per-GPU utilization, VRAM, temperature, power, fan speed and
the processes using each GPU over SSH with nvidia-smi. The collector
exits immediately when nvidia-smi is missing, so hosts without a GPU
pay almost nothing per poll.

The GPU card is opt-in: it is available from the Add card tray but is
not part of new-host defaults or any UI preset. It shows live
sparklines for utilization and VRAM per GPU.

Adaptive polling now also watches GPU readings and the GPU process
count, so it no longer backs off on hosts where only the GPU is busy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2ctuPwiesLzhF6XQiozm8

* fix(host-metrics): draw sparklines from the first metrics sample

The first sample fetched when the tab connects was shown but never
added to the sparkline history, so every sparkline (CPU, memory, disk,
GPU) stayed empty until the second poll, a full metrics interval later
(about 35 s with the default 30 s interval). Record the first sample
like every later one, so the lines appear as soon as the tab loads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2ctuPwiesLzhF6XQiozm8

* Fix logical condition for memory percentage calculation

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Temporary diagnostic to find which phase drops @img/sharp-darwin-x64
from the packaged app. Revert once root cause is found.
electron-builder uses mergeASARs: false, so universal builds ship
app-x64.asar.unpacked and app-arm64.asar.unpacked side by side instead
of a single app.asar.unpacked. The verify script only checked the
single-asar path, so it always failed on universal/mas artifacts even
when packaging was correct.
The test built fake apps using the single app.asar.unpacked layout,
which doesn't match how universal builds are actually packaged now
(app-x64.asar.unpacked / app-arm64.asar.unpacked side by side).
Tab DOM visibility now syncs before paint instead of after, and
switching tabs no longer tears down live metrics connections.
Terminal tabs no longer flash when switching, the enter animation no
longer nudges layout size, and a stray transform on resting tabs no
longer causes the border between tabs to vanish at some zoom levels.
@LukeGus
LukeGus merged commit fef8a5f into main Sep 20, 2026
1 check passed
@github-actions
github-actions Bot deleted the dev-2.8.0 branch September 20, 2026 20:49
CopilotSiS added a commit to ShipitSmarter/Termix that referenced this pull request Sep 24, 2026
* chore: sync Crowdin translations

* release-2.8.0 (#1456)

* Fix private AI custom endpoints (#1299)

* Fix Proxmox credential guest imports (#1300)

* Fix Fleet command results layout (#1301)

* Fix synced client tunnel endpoints (#1302)

* Fix Proxmox sync jump host persistence (#1303)

* Fix command palette keyboard navigation (#1304)

* Add accessible interface font choices (#1306)

* Add selectable host temperature sensors (#1307)

* Improve file manager navigation and compact layout (#1308)

* Add configurable global hotkeys (#1305)

* fix: restore split layout selection (#1310)

* fix: support macOS VNC connections (#1311)

* fix: use matching Undici fetch for private AI providers (#1309)

Co-authored-by: Angad Singh <angad@singhangad.in>

* feat: support additional TOTP authenticators (#1312)

* feat: add VNC display zoom controls (#1314)

* feat: add host context menu actions (#1315)

* fix: force classic auth for macOS VNC (#1313)

* fix: harden HTTP trust boundaries (#1316)

* fix: harden application trust boundaries (#1317)

* fix: verify OPKSSH binary integrity (#1318)

* Fix remote desktop connection timeout (#1319)

* chore(deps): bump node in /docker in the docker-major-updates group (#1321)

Bumps the docker-major-updates group in /docker with 1 update: node.


Updates `node` from 24-slim to 26-slim

---
updated-dependencies:
- dependency-name: node
  dependency-version: 26-slim
  dependency-type: direct:production
  dependency-group: docker-major-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump the dev-patch-updates group with 15 updates (#1322)

Bumps the dev-patch-updates group with 15 updates:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/view](https://github.com/codemirror/view) | `6.43.7` | `6.43.9` |
| [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) | `21.2.1` | `21.2.2` |
| [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) | `21.2.0` | `21.2.2` |
| [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) | `7.0.0` | `7.0.1` |
| [@testing-library/user-event](https://github.com/testing-library/user-event) | `14.6.1` | `14.6.5` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.10` | `4.1.11` |
| [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `4.1.10` | `4.1.11` |
| [concurrently](https://github.com/open-cli-tools/concurrently) | `10.0.4` | `10.0.5` |
| [cytoscape](https://github.com/cytoscape/cytoscape.js) | `3.34.0` | `3.34.1` |
| [eslint](https://github.com/eslint/eslint) | `10.8.0` | `10.8.1` |
| [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) | `0.5.3` | `0.5.4` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.11` | `17.0.12` |
| [sonner](https://github.com/emilkowalski/sonner) | `2.0.7` | `2.0.8` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.2.0` | `8.2.2` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.10` | `4.1.11` |


Updates `@codemirror/view` from 6.43.7 to 6.43.9
- [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/view/commits)

Updates `@commitlint/cli` from 21.2.1 to 21.2.2
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/cli/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v21.2.2/@commitlint/cli)

Updates `@commitlint/config-conventional` from 21.2.0 to 21.2.2
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v21.2.2/@commitlint/config-conventional)

Updates `@testing-library/jest-dom` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v7.0.0...v7.0.1)

Updates `@testing-library/user-event` from 14.6.1 to 14.6.5
- [Release notes](https://github.com/testing-library/user-event/releases)
- [Changelog](https://github.com/testing-library/user-event/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/user-event/compare/v14.6.1...v14.6.5)

Updates `@vitest/coverage-v8` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/coverage-v8)

Updates `@vitest/ui` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/ui)

Updates `concurrently` from 10.0.4 to 10.0.5
- [Release notes](https://github.com/open-cli-tools/concurrently/releases)
- [Commits](https://github.com/open-cli-tools/concurrently/compare/v10.0.4...v10.0.5)

Updates `cytoscape` from 3.34.0 to 3.34.1
- [Release notes](https://github.com/cytoscape/cytoscape.js/releases)
- [Commits](https://github.com/cytoscape/cytoscape.js/compare/v3.34.0...v3.34.1)

Updates `eslint` from 10.8.0 to 10.8.1
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.8.0...v10.8.1)

Updates `eslint-plugin-react-refresh` from 0.5.3 to 0.5.4
- [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases)
- [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/compare/v0.5.3...v0.5.4)

Updates `react-i18next` from 17.0.11 to 17.0.12
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.11...v17.0.12)

Updates `sonner` from 2.0.7 to 2.0.8
- [Release notes](https://github.com/emilkowalski/sonner/releases)
- [Commits](https://github.com/emilkowalski/sonner/compare/v2.0.7...v2.0.8)

Updates `vite` from 8.2.0 to 8.2.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.2.2/packages/vite)

Updates `vitest` from 4.1.10 to 4.1.11
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.11/packages/vitest)

---
updated-dependencies:
- dependency-name: "@codemirror/view"
  dependency-version: 6.43.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@commitlint/cli"
  dependency-version: 21.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@commitlint/config-conventional"
  dependency-version: 21.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@testing-library/jest-dom"
  dependency-version: 7.0.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@testing-library/user-event"
  dependency-version: 14.6.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: "@vitest/ui"
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: concurrently
  dependency-version: 10.0.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: cytoscape
  dependency-version: 3.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: eslint
  dependency-version: 10.8.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: eslint-plugin-react-refresh
  dependency-version: 0.5.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: react-i18next
  dependency-version: 17.0.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: sonner
  dependency-version: 2.0.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: vite
  dependency-version: 8.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
- dependency-name: vitest
  dependency-version: 4.1.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump the prod-patch-updates group with 5 updates (#1324)

Bumps the prod-patch-updates group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@tanstack/react-virtual](https://github.com/TanStack/virtual/tree/HEAD/packages/react-virtual) | `3.14.9` | `3.14.10` |
| [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) | `13.0.2` | `13.0.3` |
| [jose](https://github.com/panva/jose) | `6.2.8` | `6.2.9` |
| [mysql2](https://github.com/sidorares/node-mysql2) | `3.23.2` | `3.23.4` |
| [ws](https://github.com/websockets/ws) | `8.21.1` | `8.21.3` |


Updates `@tanstack/react-virtual` from 3.14.9 to 3.14.10
- [Release notes](https://github.com/TanStack/virtual/releases)
- [Changelog](https://github.com/TanStack/virtual/blob/main/packages/react-virtual/CHANGELOG.md)
- [Commits](https://github.com/TanStack/virtual/commits/@tanstack/react-virtual@3.14.10/packages/react-virtual)

Updates `better-sqlite3` from 13.0.2 to 13.0.3
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](https://github.com/WiseLibs/better-sqlite3/compare/v13.0.2...v13.0.3)

Updates `jose` from 6.2.8 to 6.2.9
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v6.2.8...v6.2.9)

Updates `mysql2` from 3.23.2 to 3.23.4
- [Release notes](https://github.com/sidorares/node-mysql2/releases)
- [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md)
- [Commits](https://github.com/sidorares/node-mysql2/compare/v3.23.2...v3.23.4)

Updates `ws` from 8.21.1 to 8.21.3
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.21.1...8.21.3)

---
updated-dependencies:
- dependency-name: "@tanstack/react-virtual"
  dependency-version: 3.14.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: better-sqlite3
  dependency-version: 13.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: jose
  dependency-version: 6.2.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: mysql2
  dependency-version: 3.23.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
- dependency-name: ws
  dependency-version: 8.21.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: prod-patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump motion in the major-updates group (#1326)

Bumps the major-updates group with 1 update: [motion](https://github.com/motiondivision/motion).


Updates `motion` from 12.43.0 to 13.1.1
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.43.0...v13.1.1)

---
updated-dependencies:
- dependency-name: motion
  dependency-version: 13.1.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: major-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat: add semantic motion system (#1320)

* feat: add semantic motion system

* feat: animate session workspace transitions

* feat: refine motion accessibility and transfer feedback

* feat: enforce RBAC and harden collaboration features (#1327)

* feat: enforce RBAC and harden collaboration features

- Mount requirePermission on hosts/snippets/credentials/automations/AI routes
- Seed and backfill system role permissions on every dialect at startup
- Support personal credential overrides for RDP/VNC/Telnet shared hosts
- Broadcast participant presence in shared terminal sessions
- Make audit log forwarding configurable from the admin panel
- Add role members endpoint and snippet folder sharing

* fix: enforce RBAC across split routes

* fix: reject malformed Guacamole tokens safely (#1329)

* fix: allow approved private notification hosts (#1330)

* feat: collaboration rooms with switchable presenter (#1328)

* feat: add collaboration rooms with switchable presenter

Rooms are a group of members watching one stage - the live SSH/RDP/VNC
session the current presenter shares. Any member can take over the
stage; the host can invite, force-stop and end the meeting. Stages
reuse session_shares (new room share type), so gating, recording,
expiry and the global sharing toggle all apply unchanged.

* feat: add stage control handoff to collaboration rooms

The presenter or host can grant any member write access to the live
stage and take it back; members can raise a hand to ask. SSH flips the
participant's permission on the live gate; RDP/VNC re-mint the viewer's
join token. Control clears on every stage switch.

* feat: guest links, role invites and invite awareness for collab rooms

- Anonymous guest link per room (host toggles/rotates), followed by
  polling the public resolve endpoint; SSH guests join over the terminal
  WS with roomGuestToken, guac guests get read-only join tokens
- Invite by role (expands to current members, snapshot semantics)
- Toast when a room you were invited to appears
- Stale stages are cleared lazily when the presenter is gone
- Telnet presenting, expired-tab fallback, documented single-instance
  and guac-kick limits
- Tests for the collab routes, room hub, share access and control flip

* fix: keep remote desktop collaboration read-only

* fix: restore RDP clipboard paste across browsers (#1331)

* fix: show the full command line in the process inspector (#1334)

The CMD column rendered ps's comm field, which the kernel caps at 15
characters, so anything longer looked truncated no matter how wide the
column was. The full args were already collected; show them.

* fix: harden collaboration room access (#1332)

* fix: harden collaboration room access

* fix: confirm guest link lifecycle changes

* fix: make RDP drive redirection writable on the stock deployment (#1333)

* fix: make RDP drive redirection writable on the stock deployment

The default drive-path was /drive on the guacd side, which the official
guacd image cannot create as its non-root user, so every upload was
refused with guacd's raw "FAIL (CANNOT OPEN)" ack. Default to
GUACD_DRIVE_PATH (set to the shared termix-data volume in compose) with
one folder per user, and explain guacd's refusal in the file browser.

* style: format RDP drive settings

* feat: quick connect for RDP and VNC (#1335)

The Quick Connect panel gets a protocol switch. RDP/VNC quick hosts are
built like SSH ones (never saved) and opened as regular remote desktop
tabs; GuacamoleApp mints their token from the typed fields through the
existing /guacamole/token endpoint instead of a host-row lookup.

* fix: authenticate unwatched hosts during the status probe (#1337)

With metrics enabled, the status probe left SSH authentication to the
metrics poll - which only runs while someone is viewing the host. An
unwatched host therefore never left "reachable", while a host with
metrics disabled (whose probe always authenticates) showed online. The
probe now authenticates whenever no metrics poll will.

* feat: compact snippet list option (#1339)

A "Show Commands" toggle in the snippets settings menu hides the command
text under each snippet name, for people who dock the panel on the
narrow right rail and only need the names. Local preference, on by
default.

* fix: guide users to Auto-Tmux when a persisted session expires (#1336)

* fix: guide users to Auto-Tmux when a persisted session expires

A timed-out terminal session silently reconnected to a fresh shell, so
people running long jobs lost them with no explanation and never learned
about Auto-Tmux. Explain the expiry with a one-click Enable Auto-Tmux
action, let admins default it for new hosts and tune the persistence
timeout from the UI, and move the setting up with copy that says what it
does. The global default stays off.

* style: format terminal expiry notice

* feat: improve collaboration rooms (#1338)

* feat: Step CA SSH certificates as a host authentication type (#1340)

* feat: Step CA SSH certificates as a host authentication type

Issue short-lived SSH user certificates from a smallstep CA through its
OIDC provisioner, over the CA's HTTP API rather than the step binary.
Everything after issuance reuses the OPKSSH plumbing: the same encrypted
per-user/host token store, WebSocket dialog and ssh2 certificate
injection, with the connect paths branching on a shared
usesIssuedCertificate() predicate. Instance-wide CA settings live in the
admin panel, with a private-host allowlist for the SSRF guard.

* fix: harden Step CA callback flow

* style: format Step CA changes

* feat: 1Password Connect secret sources for SSH credentials (#1341)

* feat: 1Password Connect secret sources for SSH credentials

Hosts and credentials can hold op://vault/item/field references instead
of secrets; they are resolved at connect time from the user's secret
source (1Password Connect) at the single point where every subsystem
receives plaintext credentials, so terminal, SFTP, Docker, metrics and
tunnels all work without per-subsystem changes. Sources are per user,
optionally shared, with the access token encrypted under the owner's
data key; resolved values are cached briefly in memory.

* style: format secret source changes

* feat: share credentials with users and roles, inherit data on account deletion (#1342)

* feat: share credentials with users and roles, inherit data on account deletion

Credentials can be shared at "use" or "manage" level. Recipients get
a copy re-encrypted under their own data key (shared_credential_secrets),
kept in step with the owner's row through the same lifecycle hooks as
shared host secrets. One gate, findUsableCredential(), replaces the
private-namespace lookups so a shared credential works wherever a
private one does. Deleting a user now hands their hosts and credentials
to a successor (the deleting admin by default) instead of revoking
everything they shared.

* fix: harden credential ownership transfer

* feat: folder shares apply to hosts added later (#1343)

* feat: folder shares apply to hosts added later

Sharing a folder only fanned grants out to the hosts in it at the time.
The share is now also kept as a standing rule on the folder, and a host
created in or moved into it (or a subfolder) inherits the same access
and secret snapshots. Rules follow folder renames and can be stopped
from the share dialog.

* fix: stabilize folder access migrations

* fix: package sharp for both macOS architectures (#1344)

* fix: prompt shared RDP users for credentials (#1345)

* feat: add terminal copy-on-select option (#1346)

* fix: retry protected file reads with sudo (#1349)

* fix: stop SSH-authenticating hosts during routine status polling (#1347)

* fix: preserve omitted host protocol settings (#1350)

* fix: surface remote sync reauthentication failures (#1351)

* fix: harden file reads and timer cleanup (#1352)

* fix: harden file reads and timer cleanup

* fix: preserve literal file path escapes

* fix: enforce SSH pool connection limits (#1353)

* fix: enforce SSH pool connection limits

* fix: discard stale pooled connections

* fix: harden connection, payload, and persisted state handling (#1354)

* fix: clean up Cloudflare tunnel timeouts

* fix: couple tunnel socket lifecycle

* fix: validate Docker console messages

* fix: bound homepage proxy responses

* fix: bound reconnect and response failures

* fix: harden persisted and socket state

* fix: support local connections to shared hosts

* fix: recover expired dashboard metrics sessions (#1355)

* fix: upload files to redirected RDP drives (#1356)

* fix: unify connection toolbar visibility (#1357)

* fix: reset host virtualizer after editing (#1358)

* test: update Guacamole toolbar display mock (#1360)

* fix: reflect live SSH sessions in host status (#1359)

* fix: support Vault auth in file manager (#1361)

* fix: allow exec on shared hosts (#1362)

* fix(file-manager): align chunked upload contract (#1371)

* fix(file-manager): make bulk uploads resilient (#1373)

* fix(terminal): disable local echo on alternate screen (#1372)

* fix(homepage): validate clock widget timezones (#1374)

An invalid timezone in a clock widget's config reached toLocaleTimeString
unchecked, throwing RangeError during render and taking the homepage canvas
down with it. The edit dialog accepted any string, so "America/New York" - a
space where IANA wants an underscore - was easy to save, and the homepage
stayed broken on every later load because the value is reloaded from the
database.

The edit dialog now flags an unusable zone the way FolderMetadataDialog flags
a duplicate folder name: inline message, aria-invalid, and a disabled Save.
Whitespace is normalized to underscores on save, so the space spelling is
stored as America/New_York rather than rejected. ClockWidget falls back to
local time for any config already holding an invalid zone.

Related to Termix-SSH/Support#1238

* fix(hosts): preserve connection origin in editor (#1376)

* fix(remote-sync): expose local login notification (#1375)

* fix(auth): allow passkeys in desktop login (#1378)

* fix(proxmox): elevate guest discovery commands (#1379)

* Fix permanent file-transfer completion toasts (#1383)

* fix(file-manager): expire completed progress toasts

* test(file-manager): use valid transfer status

* fix(hosts): allow clearing SSH key type (#1384)

* fix(terminal): suppress local echo for contextual password prompts (#1387)

* fix(desktop): surface a failed embedded backend start (#1382)

* fix(desktop): surface a failed embedded backend start

When the embedded backend's HTTP port was already taken, the desktop app
sat on the "Loading..." spinner forever with nothing in the UI to say
why. The backend logged the conflict and exited 1, and startBackendServer
resolved false, but that verdict never reached the renderer: the
get-embedded-server-status channel was not exposed in preload and nothing
called it.

The renderer, by design, treats every connection failure as "the embedded
backend is still booting" and retries indefinitely -- in main.tsx's
verifying phase, in Auth's desktop auto-session, and in
FullScreenAppWrapper. That holds while the backend is merely slow to boot,
but not once the process has exited, and nothing distinguished the two.

Classify why the child died from its exit code and a bounded tail of its
stderr, report it through get-embedded-server-status, and have each retry
loop keep waiting only while no failure is reported. A port conflict names
the port, since that is what the user has to act on -- most often a Termix
container on the same ports, or a backend orphaned by a hard-kill that
reapOrphanedBackendProcess could not claim.

A deliberate shutdown is not reported as a crash, and a backend that is
only slow to start still gets retried as before.

Fixes Termix-SSH/Support#1254

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(desktop): treat every unrequested backend exit as a failure

The classifier exempted a clean exit and SIGTERM/SIGINT, calling those a
deliberate shutdown. It has no evidence for that: its only caller already
sits behind backendStopRequested, so it is reached only for exits
stopBackendServer() did not ask for. A backend that exited 0 on its own,
or was terminated by the OS or an external signal, therefore reported no
failure at all -- leaving all three renderer loops waiting forever for a
process that is gone, which is the exact hang this change set exists to
remove.

Every exit reaching the classifier is now a failure, port-in-use when
stderr carries EADDRINUSE and crashed otherwise, with backendStopRequested
left as the sole deliberate-shutdown guard. That makes the exit code and
signal irrelevant to the verdict, so the classifier now takes only the
stderr tail rather than carrying two parameters it no longer reads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* Add white label branding settings (#1386)

* feat(admin): add white label branding settings

Admins can configure a custom app name, logo and tagline from the
Admin Settings panel. The values apply to the login screen and the
browser tab title/favicon at runtime.

* fix(admin): restore default icons on logo reset, validate upload MIME type

Resetting the logo now restores the bundled favicon/apple-touch-icon
instead of leaving the previous custom one until a reload. The admin
upload also validates file.type up front instead of only failing
later on save.

* fix(admin): restore default favicons and reject invalid logo types

Capture bundled icon hrefs before the first custom logo is applied so a
reset does not leave the previous upload in the tab, and reject
non-image uploads before they are read into branding state.

* test(admin): cover branding routes and logo validation

Add backend tests for the public GET, admin-only PATCH, unknown-field
rejection, and parseBrandingLogoDataUrl so invalid images cannot land
in settings without a failing test.

* fix(backend): report port conflicts on the service ports (#1388)

Express's app.listen(port, host, callback) registers that callback as the
server's error handler as well as its listening handler:

    if (typeof args[args.length - 1] === 'function') {
      var done = args[args.length - 1] = once(args[args.length - 1])
      server.once('error', done)
    }

so a bind failure invoked the service's "started" callback with an
EADDRINUSE error as its only argument and emitted nothing. None of the
services read that argument, which made a failed bind indistinguishable
from a successful one: the service logged that it had started, ran its
initialisation, and served nothing. With one of 30003-30012 occupied the
backend still reported backend_init_complete, the app loaded, and the
affected feature was dead for the session with no error anywhere in the
logs -- searching the backend log, the Electron main log and stdout for
EADDRINUSE returned nothing, as did uncaughtException and
unhandledRejection probes.

This is also why only the main port behaved sensibly: database.ts does
not use app.listen(), it builds the server and attaches a real error
handler, so 30001 was the one port whose conflict was ever detected.

listenOnServicePort() builds the server so that listening and error stay
separate, and treats a conflict the way database.ts already does -- name
the port, then exit -- rather than running on with one feature missing.
Exiting also hands the desktop app the classified failure it already
surfaces, so the user is told which port to free. Services that must own
their server, such as the tunnel service with its WebSocket upgrade
handler, get the same handler via attachServicePortConflictHandler().

Note that adding .on("error") to the services would not have worked:
express consumes the event through once('error', done) before any later
handler runs. The callback has to stop being passed to listen() at all.

Fixes Termix-SSH/Support#1260

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* feat(desktop): allow RDP/VNC/Telnet to originate from this device (#1389)

The desktop pinned rdp/vnc/telnet to the remote server, so a host the
user's own machine could reach but the Termix server could not was
impossible to open: the app answered "Remote server required" even when
no remote server was wanted. The embedded backend already runs the
Guacamole websocket server and guacd's address is already configurable
globally and per host, so what was missing was the choice.

resolveConnectionOrigin now honours an explicit per-host origin for
these protocols. Left on Default they still resolve to remote: they need
a guacd, which the desktop does not ship, so originating locally only
works once the user has pointed Termix at one of their own. Keeping that
opt-in means an upgrade never moves a working connection onto a guacd
that is not there. Serial and non-Electron behaviour are unchanged.

Three call paths had the same assumption baked in and would have quietly
ignored the setting:

- The Guacamole call sites resolved the origin without passing the
  host's own override, so it could never take effect.
- guacamole-api sent every token, connect-host and status call to the
  remote server whenever running under Electron, and remapped the host
  id onto the remote server's id -- which would address the wrong row,
  or fail outright with no server configured.
- GuacamoleDisplay minted its token before resolving the origin, so the
  token could come from a different backend than the socket dialled.

The origin is a required parameter on those API functions rather than a
defaulted one. A default silently sent a missed call site to the remote
server: the guacd status check in fetchToken was one, and it failed with
a bare "Network Error" on a desktop with no server configured. Making it
required means the compiler names every caller instead. That also
covers CollabRoomTab, which now resolves from the host it already holds,
so a locally-originated host stays local when presented into a room.

Finally, the Connection Origin control was gated on SSH alone, so a host
enabling only these protocols could never reach the setting. That gate
is now a named predicate covering every protocol the control applies to.

Verified end to end on Linux against a local guacd: with a host set to
"This device", guacd accepted the connection and reached the target,
which answered for itself. With guacd stopped, the guacd status check
that has run before every connection since v2.3.0 -- now asking the
backend the session will actually use -- reports it clearly before a
socket is opened.

Refs Termix-SSH/Support#1240

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* feat(local-terminal): add copy/paste support (#1391)

* feat(local-terminal): add copy/paste support

Local terminal had no clipboard wiring, so selected text couldn't be
copied. Extracted the SSH terminal's copy/paste shortcut and
right-click handling into a shared terminal-clipboard module and wired
it into both terminals, removing duplicated logic in the process.

* fix(local-terminal): stop language changes from restarting the shell session

The session effect that starts the local PTY depended on `t`, whose
identity changes on every language switch (react-i18next). That tore
down the running shell and spawned a new one just from changing the UI
language. Read translations through a ref instead so localization
stays decoupled from the PTY lifecycle.

Also adds regression coverage for the extracted terminal-clipboard.ts
helpers: copy with/without selection, explicit vs native paste,
right-click preference, and Ctrl+right-click passthrough.

* fix(file-manager): keep name column visible on narrow viewports in list view (#1402)

Rebased onto dev-2.8.0 (the density refactor kept the same 3
list-view grid patterns). Use minmax(140px, 1fr) for the name track
so it cannot collapse to 0px on narrow viewports; the table scrolls
horizontally instead of hiding names and icons.

Co-authored-by: inontz <inontz@users.noreply.github.com>

* feat(desktop): local filesystem and transfer bridge for the file manager (#1392)

* feat(desktop): local filesystem and transfer bridge for the file manager

Adds the Electron main-process side of the upcoming Local | Remote dual-pane
file manager, with no UI yet:

- electron/local-files.cjs: IPC handlers to browse the local disk (home,
  list, mkdir, createFile, rename, trash, ensureDir, walk, reveal, open) and
  to stream files between the local disk and the file-manager backend
  (uploadLocalFile / downloadToLocal with progress events and cancellation).
  Streams go through Electron's `net` so the session cookie / remembered JWT
  is attached the same way as the renderer's own requests.
- electron/preload.js: exposes them as `window.electronAPI.localFs` and
  `window.electronAPI.localTransfer`; the existing `invoke` allowlist is
  untouched.
- src/types/electron.d.ts: typings for the new surface.
- electron/main.cjs: registers the handlers.

Follow-up PRs add the renderer side (local pane, drag-and-drop transfers,
context menu).

* fix(desktop): harden the local transfer bridge (origin allowlist, collision policy)

Addresses the review on the transfer boundary:

- The renderer no longer supplies a URL or headers. It sends
  `{ origin: "local" | "remote", route, deviceId }` and the main process
  resolves the target itself: fixed route allowlist (`uploadFileStream`,
  `downloadFileStream`), local = the embedded backend base, remote = the
  remote-sync config's URL (http/https only) with the stored JWT. Anything
  else is rejected before a request is made. `deviceId` is validated.
- Downloads never rename or replace silently. The destination is checked
  first and `EEXIST` is returned unless the caller passes `overwrite: true`.
  Each transfer writes to its own `<dest>.<transferId>.termix-part` opened
  with `wx`, and publishes with `fs.link` / `COPYFILE_EXCL` (rename only when
  overwriting), so concurrent transfers to the same path cannot share or
  clobber a partial (`EBUSY` for the second). Partials are removed on
  failure or cancel.
- New `local-fs:exists` handler so the renderer can ask before starting.
- `createLocalFileHandlers` / `createTargetResolver` take their
  dependencies (net, shell, remote-sync getters) as parameters so the
  boundary is unit-testable without Electron.
- src/backend/tests/electron/local-files.test.ts: target resolution and
  off-origin refusal, EEXIST / EBUSY / overwrite paths, unique partials and
  cleanup, upload multipart integrity (parsed with Busboy).

* fix(desktop): Windows-safe replace for overwrite downloads

`publishDownload()` used `rename(partial, dest)` for the explicit overwrite
path. POSIX replaces the destination, but on Windows rename() onto an
existing name commonly fails (EEXIST / EPERM, always while the file is
open), so "Replace" did not actually work there.

The overwrite path no longer renames onto an occupied name:

1. the current file is moved aside to a transfer-unique sibling
   (`<dest>.<transferId>.termix-replaced`) - renaming to a fresh name is
   safe on every platform;
2. the partial is published exclusively under the now-free name (the same
   `link` / `COPYFILE_EXCL` primitive the non-overwrite path uses);
3. the aside copy is deleted (retried once; if another process still holds
   it open on Windows it is left in place and logged rather than failing
   the transfer).

Failure handling preserves the original: if step 1 fails (file in use)
nothing has changed and the caller gets `EBUSY`; if step 2 fails the aside
copy is moved back under its name and the error propagates. Replacing a
folder with a file is refused with `EISDIR`; a destination that vanished
mid-transfer falls back to the exclusive publish.

The publish primitives take their filesystem operations as an injectable
`publishFs` (default: real fs), and the tests drive them with a
Windows-like fs whose rename() refuses to overwrite - so the strategy is
verified without relying on POSIX rename-over-existing semantics:
successful swap with no rename ever targeting an occupied name, original
restored byte-for-byte when publishing fails, EBUSY with nothing touched
when the file cannot be moved aside, EISDIR for folders, vanished
destination, and the end-to-end overwrite through the download handler.

---------

Co-authored-by: Max <maxim@cogitate.ai>

* chore: update package lock

* feat(file-manager): Termius-style Local | Remote dual pane with drag-and-drop transfers (desktop)

Renderer side of the dual-pane file manager, built on the local filesystem
bridge added in the previous PR. Desktop app only; the web build is
unchanged (the toggle is hidden when `window.electronAPI.localFs` is absent).

- New Local pane (LocalFilePane) next to the remote grid, toggled from the
  toolbar (Laptop icon); path, visibility and width are remembered in
  localStorage (`termix:file-manager:local-pane:*`). Grid and list views,
  hidden files toggle, breadcrumb navigation, New Folder.
- Drag files/folders from the Local pane onto the remote grid to upload,
  and from the remote grid onto the Local pane to download. Both directions
  stream through the main process (`useLocalTransfers`) with a single
  progress toast per batch (speed, ETA, cancel). Finder drops onto the
  remote grid keep working as before.
- Collision policy for downloads: destinations are checked first; if any
  exist the user is asked Replace / Skip for the batch. Skip, dismiss and
  timeout all mean skip - nothing is ever replaced without an explicit
  click, and the main process enforces the same rule (`EEXIST` unless
  `overwrite` is set).
- Drag MIME contract: `application/x-termix-local-files` for local drags,
  `application/x-termix-remote-files` marker on the remote grid's internal
  drags, so each pane can tell the two apart from Finder drops.
- Transfer targets are described as `{ origin, route, deviceId }`
  (`getSessionOrigin` in main-axios) - the renderer never hands the main
  process a URL.
- i18n: new `fileManager.local*` keys in en.json only (other locales via
  Crowdin).
- Tests: LocalFilePane rendering/navigation, local-transfer-utils
  (relative-path planning, size formatting).
- Modified column uses the same `Mon DD HH:MM` / `Mon DD  YYYY` (ls -l style)
  format as the remote grid, so both panes read alike.

* docs: point security note to the docs root (old /security page is gone) (#1400)

* chore: sync Crowdin translations

* chore(deps): bump the prod-minor-updates group across 1 directory with 3 updates (#1325)

Bumps the prod-minor-updates group with 3 updates in the / directory: [@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript), [js-yaml](https://github.com/nodeca/js-yaml) and [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg).


Updates `@anthropic-ai/sdk` from 0.116.0 to 0.120.0
- [Release notes](https://github.com/anthropics/anthropic-sdk-typescript/releases)
- [Changelog](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.116.0...sdk-v0.120.0)

Updates `js-yaml` from 5.2.3 to 5.3.0
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/5.2.3...5.3.0)

Updates `pg` from 8.22.0 to 8.23.0
- [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md)
- [Commits](https://github.com/brianc/node-postgres/commits/pg@8.23.0/packages/pg)

---
updated-dependencies:
- dependency-name: "@anthropic-ai/sdk"
  dependency-version: 0.120.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
- dependency-name: js-yaml
  dependency-version: 5.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
- dependency-name: pg
  dependency-version: 8.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump the dev-minor-updates group across 1 directory with 10 updates (#1323)

Bumps the dev-minor-updates group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/commands](https://github.com/codemirror/commands) | `6.10.4` | `6.11.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.1.2` | `26.2.0` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.0.5` | `6.1.0` |
| [electron](https://github.com/electron/electron) | `43.2.0` | `43.4.1` |
| [globals](https://github.com/sindresorhus/globals) | `17.9.0` | `17.11.0` |
| [i18next](https://github.com/i18next/i18next) | `26.3.6` | `26.4.0` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.28.0` | `1.33.0` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.84.0` | `7.85.0` |
| [react-pdf](https://github.com/wojtekmaj/react-pdf/tree/HEAD/packages/react-pdf) | `10.4.1` | `10.5.0` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.66.0` | `8.67.0` |



Updates `@codemirror/commands` from 6.10.4 to 6.11.0
- [Changelog](https://github.com/codemirror/commands/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/commands/commits)

Updates `@types/node` from 26.1.2 to 26.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitejs/plugin-react` from 6.0.5 to 6.1.0
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.0/packages/plugin-react)

Updates `electron` from 43.2.0 to 43.4.1
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v43.2.0...v43.4.1)

Updates `globals` from 17.9.0 to 17.11.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.9.0...v17.11.0)

Updates `i18next` from 26.3.6 to 26.4.0
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.3.6...v26.4.0)

Updates `lucide-react` from 1.28.0 to 1.33.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.33.0/packages/lucide-react)

Updates `react-hook-form` from 7.84.0 to 7.85.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.84.0...v7.85.0)

Updates `react-pdf` from 10.4.1 to 10.5.0
- [Release notes](https://github.com/wojtekmaj/react-pdf/releases)
- [Commits](https://github.com/wojtekmaj/react-pdf/commits/v10.5.0/packages/react-pdf)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@codemirror/commands"
  dependency-version: 6.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@types/node"
  dependency-version: 26.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: electron
  dependency-version: 43.4.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: globals
  dependency-version: 17.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: i18next
  dependency-version: 26.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: lucide-react
  dependency-version: 1.33.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: react-hook-form
  dependency-version: 7.85.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: react-pdf
  dependency-version: 10.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore: sync Crowdin translations

* Update redirect-issues workflow configuration

Updated the workflow to change the runner and modify the issue response message.

* chore: sync Crowdin translations

* Add Hetzner logo and referral link to README

Added Hetzner logo with a referral link to README.

* Fix Hetzner logo URL in README.md

* docs: point security note to the feature security page

The old /security page is gone and the docs root redirects to /install/,
which loses the encryption context the sentence promises. Point the
per-user secret and database encryption note at the canonical
docs.termix.site/features/authentication/security/ page instead.
Applied across all README locales.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: ssmurfgg04-gif <232103099+ssmurfgg04-gif@users.noreply.github.com>
Co-authored-by: ZacharyZcR <payasonorahc@protonmail.com>

* fix: use i18n for host status tooltip labels (#1403)

* chore: sync Crowdin translations

* chore(deps): bump the prod-minor-updates group across 1 directory with 3 updates (#1325)

Bumps the prod-minor-updates group with 3 updates in the / directory: [@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript), [js-yaml](https://github.com/nodeca/js-yaml) and [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg).


Updates `@anthropic-ai/sdk` from 0.116.0 to 0.120.0
- [Release notes](https://github.com/anthropics/anthropic-sdk-typescript/releases)
- [Changelog](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.116.0...sdk-v0.120.0)

Updates `js-yaml` from 5.2.3 to 5.3.0
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/5.2.3...5.3.0)

Updates `pg` from 8.22.0 to 8.23.0
- [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md)
- [Commits](https://github.com/brianc/node-postgres/commits/pg@8.23.0/packages/pg)

---
updated-dependencies:
- dependency-name: "@anthropic-ai/sdk"
  dependency-version: 0.120.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
- dependency-name: js-yaml
  dependency-version: 5.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
- dependency-name: pg
  dependency-version: 8.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump the dev-minor-updates group across 1 directory with 10 updates (#1323)

Bumps the dev-minor-updates group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/commands](https://github.com/codemirror/commands) | `6.10.4` | `6.11.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.1.2` | `26.2.0` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.0.5` | `6.1.0` |
| [electron](https://github.com/electron/electron) | `43.2.0` | `43.4.1` |
| [globals](https://github.com/sindresorhus/globals) | `17.9.0` | `17.11.0` |
| [i18next](https://github.com/i18next/i18next) | `26.3.6` | `26.4.0` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.28.0` | `1.33.0` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.84.0` | `7.85.0` |
| [react-pdf](https://github.com/wojtekmaj/react-pdf/tree/HEAD/packages/react-pdf) | `10.4.1` | `10.5.0` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.66.0` | `8.67.0` |



Updates `@codemirror/commands` from 6.10.4 to 6.11.0
- [Changelog](https://github.com/codemirror/commands/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/commands/commits)

Updates `@types/node` from 26.1.2 to 26.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitejs/plugin-react` from 6.0.5 to 6.1.0
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.0/packages/plugin-react)

Updates `electron` from 43.2.0 to 43.4.1
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v43.2.0...v43.4.1)

Updates `globals` from 17.9.0 to 17.11.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.9.0...v17.11.0)

Updates `i18next` from 26.3.6 to 26.4.0
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.3.6...v26.4.0)

Updates `lucide-react` from 1.28.0 to 1.33.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.33.0/packages/lucide-react)

Updates `react-hook-form` from 7.84.0 to 7.85.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.84.0...v7.85.0)

Updates `react-pdf` from 10.4.1 to 10.5.0
- [Release notes](https://github.com/wojtekmaj/react-pdf/releases)
- [Commits](https://github.com/wojtekmaj/react-pdf/commits/v10.5.0/packages/react-pdf)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@codemirror/commands"
  dependency-version: 6.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@types/node"
  dependency-version: 26.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: electron
  dependency-version: 43.4.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: globals
  dependency-version: 17.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: i18next
  dependency-version: 26.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: lucide-react
  dependency-version: 1.33.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: react-hook-form
  dependency-version: 7.85.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: react-pdf
  dependency-version: 10.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore: sync Crowdin translations

* Update redirect-issues workflow configuration

Updated the workflow to change the runner and modify the issue response message.

* chore: sync Crowdin translations

* fix: use i18n for host status tooltip labels (#1265)

* fix: add missing hosts.status.* locale keys (fixes #1265)

* fix: add hosts.status.* translation keys for i18n tooltip

The buildStatusTooltip function calls t("hosts.status.available"), t("hosts.status.reachable"), t("hosts.status.offline"), and t("hosts.status.monitoringDisabled"), but the locale file only had "status": "Status" as a flat string.

Replaced with a status object containing all four keys plus a "label" key preserving the original "Status" string.

* fix: restore final newline in en.json

Requested by ZacharyZcR in review feedback.

* test: assert translated labels in buildStatusTooltip

Per review feedback from ZacharyZcR: add focused tests that exercise
buildStatusTooltip with a translator and assert the rendered labels
rather than key paths. Covers all three status values, monitoring
disabled, protocol list, and the no-key-path regression guard.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: ZacharyZcR <payasonorahc@protonmail.com>

* fix(workspaces): fall back when randomUUID is unavailable (#1397)

* fix(terminal): preserve macOS Alt digit characters (#1398)

* fix(ssh): verify resolved server host identity (#1419)

* fix: add principals to Termix ID certificates (#1421)

* chore: sync Crowdin translations

* chore(deps): bump the prod-minor-updates group across 1 directory with 3 updates (#1325)

Bumps the prod-minor-updates group with 3 updates in the / directory: [@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript), [js-yaml](https://github.com/nodeca/js-yaml) and [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg).


Updates `@anthropic-ai/sdk` from 0.116.0 to 0.120.0
- [Release notes](https://github.com/anthropics/anthropic-sdk-typescript/releases)
- [Changelog](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md)
- [Commits](https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.116.0...sdk-v0.120.0)

Updates `js-yaml` from 5.2.3 to 5.3.0
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/5.2.3...5.3.0)

Updates `pg` from 8.22.0 to 8.23.0
- [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md)
- [Commits](https://github.com/brianc/node-postgres/commits/pg@8.23.0/packages/pg)

---
updated-dependencies:
- dependency-name: "@anthropic-ai/sdk"
  dependency-version: 0.120.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
- dependency-name: js-yaml
  dependency-version: 5.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
- dependency-name: pg
  dependency-version: 8.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: prod-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump the dev-minor-updates group across 1 directory with 10 updates (#1323)

Bumps the dev-minor-updates group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@codemirror/commands](https://github.com/codemirror/commands) | `6.10.4` | `6.11.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.1.2` | `26.2.0` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.0.5` | `6.1.0` |
| [electron](https://github.com/electron/electron) | `43.2.0` | `43.4.1` |
| [globals](https://github.com/sindresorhus/globals) | `17.9.0` | `17.11.0` |
| [i18next](https://github.com/i18next/i18next) | `26.3.6` | `26.4.0` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.28.0` | `1.33.0` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.84.0` | `7.85.0` |
| [react-pdf](https://github.com/wojtekmaj/react-pdf/tree/HEAD/packages/react-pdf) | `10.4.1` | `10.5.0` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.66.0` | `8.67.0` |



Updates `@codemirror/commands` from 6.10.4 to 6.11.0
- [Changelog](https://github.com/codemirror/commands/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/commands/commits)

Updates `@types/node` from 26.1.2 to 26.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitejs/plugin-react` from 6.0.5 to 6.1.0
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.1.0/packages/plugin-react)

Updates `electron` from 43.2.0 to 43.4.1
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v43.2.0...v43.4.1)

Updates `globals` from 17.9.0 to 17.11.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v17.9.0...v17.11.0)

Updates `i18next` from 26.3.6 to 26.4.0
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.3.6...v26.4.0)

Updates `lucide-react` from 1.28.0 to 1.33.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.33.0/packages/lucide-react)

Updates `react-hook-form` from 7.84.0 to 7.85.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.84.0...v7.85.0)

Updates `react-pdf` from 10.4.1 to 10.5.0
- [Release notes](https://github.com/wojtekmaj/react-pdf/releases)
- [Commits](https://github.com/wojtekmaj/react-pdf/commits/v10.5.0/packages/react-pdf)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@codemirror/commands"
  dependency-version: 6.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@types/node"
  dependency-version: 26.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: electron
  dependency-version: 43.4.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: globals
  dependency-version: 17.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: i18next
  dependency-version: 26.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: lucide-react
  dependency-version: 1.33.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: react-hook-form
  dependency-version: 7.85.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: react-pdf
  dependency-version: 10.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: dev-minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore: sync Crowdin translations

* Update redirect-issues workflow configuration

Updated the workflow to …
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.