* fix: preserve remote sync references (#1092)
* fix: centralize outbound address validation (#1093)
* fix: preserve architecture in unpacked ASAR path (#1094)
* fix: allow sharing empty folders (#1096)
* fix: preserve WoL broadcast address (#1097)
* fix: deduplicate shared hosts (#1098)
* fix snippet execution result handling (#1099)
* fix SSH login alert delivery (#1100)
* fix outbound DNS lookup callback shape (#1101)
* fix OIDC verification for JWKs without alg (#1102)
* fix file manager navigation after permission errors (#1103)
* fix database persistence during container shutdown (#1104)
* fix: persist host command history setting (#1107)
* fix: recognize Windows terminal Tab events (#1109)
* fix: recognize Windows terminal Tab events
* style: format terminal key event test
* fix: export repository user record (#1111)
* fix: keep localhost database export same-origin (#1112)
* fix: support Tailscale auth in tmux monitor (#1113)
* fix: forward Android hardware keyboard keys (#1114)
* fix: expose jump tunnels to guacd (#1115)
* fix OIDC login with unverifiable ID tokens (#1117)
verifyOIDCToken passed the raw id_token straight to jose's jwtVerify, which
throws JWSInvalid when the token is not a three-segment compact JWS. Authentik
issues an encrypted JWE id_token when the provider has an encryption key set,
so the callback threw and every OIDC login failed with 'Invalid Compact JWS'.
2.5.0 hid this behind a catch-all that decoded the unverified payload; removing
that fallback fixed the trust bug but turned the pre-existing verification
failure into a hard login failure.
Check the segment count before verifying and raise a distinct
OIDCTokenFormatError, which the callback treats as 'no usable claims here' and
falls through to the userinfo endpoint. Signature and claim failures still
reject the login.
FixesTermix-SSH/Support#1016FixesTermix-SSH/Support#1018
* refuse to start with an empty database when data exists elsewhere (#1118)
When the data directory holds no database, startup treats it as a first run and
silently creates an empty one. A deployment that loses DATA_DIR — an .env file
the service no longer loads, a volume that did not mount — lands in exactly that
state, so the user is asked to register an admin account again while the real
database sits untouched one directory over. It is indistinguishable from the
upgrade having deleted everything.
Check the known data locations before creating a new database and refuse to
start when one of them already holds a database, naming both directories.
ALLOW_EMPTY_DATA_DIR=true starts anyway for anyone deliberately starting over.
This matches how a failed decryption already behaves: it throws rather than
falling back to an empty database.
ClosesTermix-SSH/Support#1006
* stop read-only shared hosts from being dragged into folders (#1119)
Shared hosts hide their edit, share and delete actions based on the recipient's
permission level, but the sidebar row stays draggable regardless. Dropping one on
a folder issues a bulk folder update the server rejects, so a recipient without
edit rights gets a failure toast for an action the UI offered them.
Gate draggable on canEditHost, and skip hosts the recipient cannot edit in the
move handler so a mixed selection moves what it can instead of failing whole.
ClosesTermix-SSH/Support#1011
* apply the configured RDP resolution to the session (#1120)
The host editor stores width and height in guacamoleConfig, and the backend
passes them to guacd in the connection token. The renderer then appends its own
width and height query parameters measured from the container, which take
precedence, so a configured resolution never reached the session — only dpi did,
because that was the one display field GuacamoleApp read back.
Pass the configured width and height alongside dpi, and skip the container-driven
sendSize on connect and on resize when a resolution is pinned. rescaleDisplay
still fits the fixed display into the available space.
ClosesTermix-SSH/Support#1039
* honour per-host recording flags and explain a missing recording (#1121)
The session recording section offers a recording path, a filename template and
four content toggles, but the backend overwrote five of the six on every
connection. A host could set none of them and get no indication why.
Location and filename genuinely are not the host's to choose — recordings are
indexed by them for playback and the backend refuses to read outside its
recordings directory — so drop those two inputs rather than keep pretending they
apply. The content flags are a host-level decision, so default them instead of
forcing them.
That still leaves the reported case, where guacd writes the file somewhere the
backend cannot see it. The warning now reports both paths and names the two env
vars that align them, which is otherwise guesswork for a split-container setup.
ClosesTermix-SSH/Support#1041
* route desktop guacd calls to the connected remote server (#1122)
resolveConnectionOrigin() pins RDP/VNC/Telnet to "remote" because the embedded
desktop backend does not bundle guacd, and the Guacamole websocket already
follows that. The status check and both token calls did not: they use the shared
authApi, which in Electron is hard-coded to the embedded backend.
So the desktop app asked the backend without guacd whether guacd was available,
got "disconnected", and refused to connect — while the connected server it would
actually have used reports it as connected and serves the same host fine from the
web client.
Send those three calls through a remote-origin instance in Electron, alongside
the existing file-manager, tunnel and stats ones.
ClosesTermix-SSH/Support#1043
* move the Homebrew cask to where a tap looks for it (#1123)
A tap discovers casks in a top-level Casks/ directory. The cask sat in
packaging/Casks/, so tapping the repository succeeded and every subsequent
brew install --cask termix reported that no cask with that name exists.
Move it and repoint the five workflow references. The release job still rewrites
the version and checksum in place, and the electron job still copies it into the
generated and submission trees.
ClosesTermix-SSH/Support#1044
* stop highlighting inside a split control string (#1124)
A control string (OSC/DCS/APC/PM) carries text that must never be displayed —
an OSC 0 title holds the user, host and path, and PROMPT_COMMAND emits one on
every prompt. Its opener and its terminator routinely land in different
websocket frames, and the continuation frame contains no escape byte at all, so
every guard in the highlighter misses it: TUI_SEQUENCE, CONTROL_STRING_SEQUENCE
and hasIncompleteAnsiSequence all only look at one chunk.
Highlighting that continuation injects an SGR sequence into the middle of the
open string, which aborts it early in xterm.js and prints the remainder as
ordinary text — the stray ~/path glued to the prompt, and the cursor arithmetic
drift behind the duplicate prompts and Ctrl+R corruption.
Track the state across chunks the way alternate-screen mode already is, and skip
any chunk that starts or ends inside a control string. A trailing lone ESC counts
as inside, since its meaning only arrives with the next chunk.
ClosesTermix-SSH/Support#1025
* stop session-log route test importing the real repository layer (#1125)
The test mocks db, logger and AuthManager, but the route module also calls
PermissionManager.getInstance() at import time and pulls in the repository
factory, which loads the drizzle schema and the better-sqlite3 native binding.
Importing that costs seconds when the full suite runs its projects
concurrently, and the test times out at 5s. On its own it passes, so it read as
flaky rather than as a missing mock.
Mock both. None of it is under test here, and the file now imports in
milliseconds regardless of load.
* fail the guacamole-lite patch when an anchor is gone (#1126)
Each patch bails out with a console.log and process.exit(0) when its anchor
string is missing. The write-back happens at the end of the file, so an upstream
release that moves any one anchor drops every patch, exits successfully, and
leaves postinstall reporting nothing wrong. Termix then builds and starts
normally and drops VNC/RDP sessions at runtime — with no signal pointing at the
patch.
Every patch here is required for correctness: protocol negotiation, the guacd
1.6.0 name handshake, dynamic argument answering, UTF-8 tokens, read-only joins.
A missing anchor means the patch no longer applies, so exit non-zero and say
which one and what to do.
Unchanged: a missing guacamole-lite still skips quietly, and an already-patched
tree still exits 0.
* fix: clarify desktop local profile (#1095)
* fix: clarify desktop local profile
* cover the AccordionSection hidden branch
The desktop build hides the Security section because the embedded profile signs
in automatically and has no login password, so the controls there would imply a
protection that does not exist. Nothing asserted that hidden actually keeps the
children out of the DOM rather than merely collapsing them.
Export the component and cover both states, including that an expanded hidden
section still renders nothing.
* fix: show remote sync account identity (#1110)
* fix: show remote sync account identity
* cover getRemoteSyncUserInfo and make its null contract hold
Nothing asserted the renderer-side gate: browser builds must not reach for the
IPC bridge, and a missing bridge, an unconfigured server, an expired JWT or a
failed channel all have to degrade to no identity rather than throw.
Writing that turned up a mismatch — with no preload bridge the optional chain
resolved to undefined while the signature promises null. The only caller uses
??, so nothing is broken today, but the type was not telling the truth.
The main-process half (token expiry, /users/me, the roles fallback) stays
uncovered: remote-sync.cjs requires electron at load, so exercising it means
stubbing safeStorage and the filesystem, which is a bigger change than this PR
warrants.
* improve settings navigation and legal disclosure (#1105)
* fix desktop preference synchronization (#1106)
* fix: use jump host SOCKS proxy settings (#1116)
* ci(deps): bump the github-actions group with 2 updates (#1086)
Bumps the github-actions group with 2 updates: [actions/setup-node](https://github.com/actions/setup-node) and [useblacksmith/setup-docker-builder](https://github.com/useblacksmith/setup-docker-builder).
Updates `actions/setup-node` from 6 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)
Updates `useblacksmith/setup-docker-builder` from 1 to 2
- [Release notes](https://github.com/useblacksmith/setup-docker-builder/releases)
- [Commits](https://github.com/useblacksmith/setup-docker-builder/compare/v1...v2)
---
updated-dependencies:
- dependency-name: actions/setup-node
dependency-version: '7'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: github-actions
- dependency-name: useblacksmith/setup-docker-builder
dependency-version: '2'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: github-actions
...
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 23 updates (#1087)
Bumps the dev-patch-updates group with 23 updates:
| Package | From | To |
| --- | --- | --- |
| [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) | `2.5.4` | `2.5.5` |
| [@radix-ui/react-accordion](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/accordion) | `1.2.17` | `1.2.20` |
| [@radix-ui/react-alert-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/alert-dialog) | `1.1.20` | `1.1.23` |
| [@radix-ui/react-checkbox](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/checkbox) | `1.3.8` | `1.3.11` |
| [@radix-ui/react-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dialog) | `1.1.20` | `1.1.23` |
| [@radix-ui/react-dropdown-menu](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dropdown-menu) | `2.1.21` | `2.1.24` |
| [@radix-ui/react-label](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/label) | `2.1.12` | `2.1.15` |
| [@radix-ui/react-popover](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/popover) | `1.1.20` | `1.1.23` |
| [@radix-ui/react-progress](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/progress) | `1.1.13` | `1.1.16` |
| [@radix-ui/react-scroll-area](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/scroll-area) | `1.2.15` | `1.2.18` |
| [@radix-ui/react-select](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/select) | `2.3.4` | `2.3.7` |
| [@radix-ui/react-separator](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/separator) | `1.1.12` | `1.1.15` |
| [@radix-ui/react-slider](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/slider) | `1.4.4` | `1.4.7` |
| [@radix-ui/react-slot](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/slot) | `1.3.0` | `1.3.3` |
| [@radix-ui/react-switch](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/switch) | `1.3.4` | `1.3.7` |
| [@radix-ui/react-tabs](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tabs) | `1.1.18` | `1.1.21` |
| [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tooltip) | `1.2.13` | `1.2.16` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.0.3` | `6.0.4` |
| [concurrently](https://github.com/open-cli-tools/concurrently) | `10.0.3` | `10.0.4` |
| [radix-ui](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/radix-ui) | `1.6.3` | `1.6.7` |
| [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.2.7` | `19.2.8` |
| [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.2.7` | `19.2.8` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.10` | `17.0.11` |
Updates `@biomejs/biome` from 2.5.4 to 2.5.5
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.5.5/packages/@biomejs/biome)
Updates `@radix-ui/react-accordion` from 1.2.17 to 1.2.20
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/accordion/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/accordion)
Updates `@radix-ui/react-alert-dialog` from 1.1.20 to 1.1.23
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/alert-dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/alert-dialog)
Updates `@radix-ui/react-checkbox` from 1.3.8 to 1.3.11
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/checkbox/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/checkbox)
Updates `@radix-ui/react-dialog` from 1.1.20 to 1.1.23
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dialog)
Updates `@radix-ui/react-dropdown-menu` from 2.1.21 to 2.1.24
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dropdown-menu/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dropdown-menu)
Updates `@radix-ui/react-label` from 2.1.12 to 2.1.15
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/label/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/label)
Updates `@radix-ui/react-popover` from 1.1.20 to 1.1.23
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/popover/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/popover)
Updates `@radix-ui/react-progress` from 1.1.13 to 1.1.16
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/progress/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/progress)
Updates `@radix-ui/react-scroll-area` from 1.2.15 to 1.2.18
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/scroll-area/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/scroll-area)
Updates `@radix-ui/react-select` from 2.3.4 to 2.3.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/select/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/select)
Updates `@radix-ui/react-separator` from 1.1.12 to 1.1.15
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/separator/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/separator)
Updates `@radix-ui/react-slider` from 1.4.4 to 1.4.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/slider/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slider)
Updates `@radix-ui/react-slot` from 1.3.0 to 1.3.3
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/slot/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slot)
Updates `@radix-ui/react-switch` from 1.3.4 to 1.3.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/switch/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/switch)
Updates `@radix-ui/react-tabs` from 1.1.18 to 1.1.21
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tabs/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tabs)
Updates `@radix-ui/react-tooltip` from 1.2.13 to 1.2.16
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tooltip/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tooltip)
Updates `@vitejs/plugin-react` from 6.0.3 to 6.0.4
- [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.0.4/packages/plugin-react)
Updates `concurrently` from 10.0.3 to 10.0.4
- [Release notes](https://github.com/open-cli-tools/concurrently/releases)
- [Commits](https://github.com/open-cli-tools/concurrently/compare/v10.0.3...v10.0.4)
Updates `radix-ui` from 1.6.3 to 1.6.7
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/radix-ui/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/1.6.7/packages/react/radix-ui)
Updates `react` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react)
Updates `react-dom` from 19.2.7 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react-dom)
Updates `react-i18next` from 17.0.10 to 17.0.11
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.10...v17.0.11)
---
updated-dependencies:
- dependency-name: "@biomejs/biome"
dependency-version: 2.5.5
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-accordion"
dependency-version: 1.2.20
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-alert-dialog"
dependency-version: 1.1.23
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-checkbox"
dependency-version: 1.3.11
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dialog"
dependency-version: 1.1.23
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dropdown-menu"
dependency-version: 2.1.24
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-label"
dependency-version: 2.1.15
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-popover"
dependency-version: 1.1.23
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-progress"
dependency-version: 1.1.16
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-scroll-area"
dependency-version: 1.2.18
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-select"
dependency-version: 2.3.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-separator"
dependency-version: 1.1.15
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-slider"
dependency-version: 1.4.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-slot"
dependency-version: 1.3.3
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-switch"
dependency-version: 1.3.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tabs"
dependency-version: 1.1.21
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tooltip"
dependency-version: 1.2.16
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@vitejs/plugin-react"
dependency-version: 6.0.4
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: concurrently
dependency-version: 10.0.4
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: radix-ui
dependency-version: 1.6.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: react
dependency-version: 19.2.8
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: react-dom
dependency-version: 19.2.8
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: react-i18next
dependency-version: 17.0.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 3 updates (#1088)
Bumps the prod-patch-updates group with 3 updates: [@tanstack/react-virtual](https://github.com/TanStack/virtual/tree/HEAD/packages/react-virtual), [jose](https://github.com/panva/jose) and [js-yaml](https://github.com/nodeca/js-yaml).
Updates `@tanstack/react-virtual` from 3.14.6 to 3.14.8
- [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.8/packages/react-virtual)
Updates `jose` from 6.2.3 to 6.2.4
- [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.3...v6.2.4)
Updates `js-yaml` from 5.2.1 to 5.2.2
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/5.2.1...5.2.2)
---
updated-dependencies:
- dependency-name: "@tanstack/react-virtual"
dependency-version: 3.14.8
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: prod-patch-updates
- dependency-name: jose
dependency-version: 6.2.4
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: prod-patch-updates
- dependency-name: js-yaml
dependency-version: 5.2.2
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 undici in the prod-minor-updates group (#1089)
Bumps the prod-minor-updates group with 1 update: [undici](https://github.com/nodejs/undici).
Updates `undici` from 8.7.0 to 8.9.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v8.7.0...v8.9.0)
---
updated-dependencies:
- dependency-name: undici
dependency-version: 8.9.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): bump the major-updates group with 4 updates (#1090)
Bumps the major-updates group with 4 updates: [better-sqlite3](https://github.com/WiseLibs/better-sqlite3), [chalk](https://github.com/chalk/chalk), [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) and [typescript](https://github.com/microsoft/TypeScript).
Updates `better-sqlite3` from 12.11.1 to 13.0.1
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](https://github.com/WiseLibs/better-sqlite3/compare/v12.11.1...v13.0.1)
Updates `chalk` from 5.6.2 to 6.0.0
- [Release notes](https://github.com/chalk/chalk/releases)
- [Commits](https://github.com/chalk/chalk/compare/v5.6.2...v6.0.0)
Updates `@testing-library/jest-dom` from 6.9.1 to 7.0.0
- [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/v6.9.1...v7.0.0)
Updates `typescript` from 6.0.3 to 7.0.2
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)
---
updated-dependencies:
- dependency-name: better-sqlite3
dependency-version: 13.0.1
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: major-updates
- dependency-name: chalk
dependency-version: 6.0.0
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: major-updates
- dependency-name: "@testing-library/jest-dom"
dependency-version: 7.0.0
dependency-type: direct:development
update-type: version-update:semver-major
dependency-group: major-updates
- dependency-name: typescript
dependency-version: 7.0.2
dependency-type: direct:development
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>
* restore lint by pinning typescript below 7 (#1131)
#1090 bumped typescript to 7.0.2. typescript-eslint declares
`typescript: >=4.8.4 <6.1.0`, and TypeScript 7 removed `ts.Extension`, which
@typescript-eslint/typescript-estree dereferences at import time:
node_modules/@typescript-eslint/typescript-estree/dist/create-program/shared.js:59
ts.Extension.Cjs,
TypeError: Cannot read properties of undefined (reading 'Cjs')
ESLint hits that while loading eslint.config.mjs, so `npm run lint` fails before
linting anything. Node reports it as ERR_INTERNAL_ASSERTION, which hides the
cause. Every open PR fails this check, not just new ones.
Even the latest typescript-eslint prerelease still caps at <6.1.0, so there is
nothing to upgrade to yet. Pin back to ~6.0.3 and tell dependabot to hold major
typescript bumps until the ecosystem catches up.
Also fixes biome.json pointing vcs.defaultBranch at dev-2.5.0, a branch that no
longer exists.
* make the repository layer engine-agnostic (#1127)
DatabaseContext handed every repository a raw better-sqlite3 handle alongside
drizzle, and three of them used it for retention queries built on datetime('now',
?) — a SQLite-only function. That handle is the one thing standing between the
repository layer and a second engine.
Drop it. The two time-based prunes compute their cutoff in JS against the
CURRENT_TIMESTAMP text format, which every engine writes the same way and which
compares correctly as a string; the health-history prune becomes a select of the
rows to keep followed by a NOT IN delete. All three turn async, so their two
callers await them.
Name the dialect rather than repeating a string literal, so adding an engine is
one edit instead of a search.
Tests built their schema through context.sqlite?.exec(). Optional chaining meant
removing the field type-checked cleanly and then silently created no tables, so
the fixture now owns exec() and a raw handle for direct assertions — schema setup
belongs to the test harness, not to the interface repositories consume.
No behaviour change, and no Postgres yet: this only removes the coupling that
would have to be undone first.
* keep audit trails and recordings when a user is deleted (#1128)
audit_logs and session_recordings both referenced users with ON DELETE CASCADE,
so removing an account erased everything it had ever done. An audit trail that
disappears with the account it recorded cannot answer the question it exists for,
and a recording is evidence about a host as much as about a person.
Both foreign keys become ON DELETE SET NULL. audit_logs already denormalises
username, so an entry still names who acted once the reference is gone.
session_recordings did not, so the column is added and backfilled first —
otherwise relaxing the constraint would only trade deleted evidence for
anonymous evidence.
SQLite cannot alter a foreign key in place, so existing databases are migrated
by copy-and-swap, guarded by a PRAGMA check that makes it idempotent. Fresh
databases are created in the target shape and skip it. Recordings still cascade
from their host.
* audit the remaining remote access paths (#1129)
Only SSH terminal sessions were audited. Opening a file manager session, an RDP,
VNC or Telnet desktop, a Docker session or an SSH tunnel left no audit entry at
all — which covers most of the ways data leaves a host or a foothold is
established.
Each of those four now writes an entry when the session is established, matching
the existing ssh_connect: who, which host, from what address, and for tunnels
the endpoint and local port being forwarded.
Audit writes are fire-and-forget so they cannot delay or fail the connection,
consistent with logAudit already swallowing its own errors.
getAuditUsername was defined identically in two route files and is needed in
four more, so it moves next to logAudit.
* fix: honor lookupOptions.all in custom DNS lookup hook (#1084)
Node's happy-eyeballs autoSelectFamily calls custom dns lookup functions
with all:true and expects the full address array back. Always replying
with a single (address, family) pair corrupted net's internal state,
surfacing as "Invalid IP address: undefined" instead of a real connect
error, breaking outbound notification delivery (webhook/ntfy).
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
* fix: SSH-login alerts silently dropped (channel load + auth middleware ordering) (#1083)
* fix: load notification channels on mount in AlertsPanel
Channels only loaded when the Channels tab was visited, so opening Edit
Alert Rule before ever switching to that tab showed the channel picker
as empty even when channels existed.
(cherry picked from commit caed913ee91990a853f5a048849c67ed3f7c329e)
* fix: register login-alert route before auth middleware
Global JWT auth middleware ran before this internal
service-to-service route, rejecting it with 401 before
its own IP+token check ever ran — silently dropped every
SSH-login alert. Also surface non-OK responses instead of
swallowing them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* test: add coverage for alert-notification fixes
Channel-load-on-mount, login-alert non-OK handling, and a
source-order guard for the route/auth-middleware regression.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* format AlertsPanel test with prettier
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
* stop deleting audit trails, and say when they are dropped (#1132)
Two ways audit evidence still disappeared silently.
Deleting an account removed its audit entries and session recordings outright.
#1128 relaxed those foreign keys to ON DELETE SET NULL, but deleteUserAndRelatedData
deletes the rows explicitly, so the schema change had no effect on the path that
actually matters. Both repositories gain anonymizeByUserId, which nulls the
reference and leaves the row; username is already denormalised on both tables, so
entries stay attributable to whoever acted.
Separately, the log pruned itself at a hard-coded 10000 rows with no signal.
Entries well inside any retention window were discarded and nothing recorded it.
Retention is now configurable by age via AUDIT_LOG_RETENTION_DAYS, the row cap
via AUDIT_LOG_MAX_ENTRIES, and the two are reported differently: expiring an old
entry is routine and logged at info, while hitting the cap means the ceiling is
too low for how much this install audits and is logged at warn, naming the range
discarded and how to stop it.
* let the audit log leave the box (#1133)
Retention became configurable in #1132, which only helps if entries can be moved
somewhere before they expire. Until now the only way out was two GET endpoints
built for the UI.
Adds GET /audit-logs/export, taking the same filters as the list endpoint and
streaming the whole matching set as CSV or NDJSON in batches, so an export is not
bounded by the 200-row page cap and does not buffer the result set. Reading the
entire trail is itself recorded as export_audit_logs.
CSV fields starting with =, +, - or @ are prefixed with a quote. Audit rows carry
attacker-influenced values like resource names, and spreadsheet software treats
those as formulas on open.
Adds optional live forwarding to a collector via AUDIT_LOG_FORWARD_URL, with an
optional bearer token. Delivery goes through safeOutboundFetch so a misconfigured
URL cannot be turned into an internal network probe, and it is fire-and-forget:
the local write stays the source of truth and a dead SIEM must never delay or
fail the operation being audited. Repeated failures are reported five times and
then suppressed until delivery recovers, so an outage does not bury the logs it
is supposed to appear in.
* encrypt SSO secrets instead of base64-encoding them (#1135)
The OIDC client secret and LDAP bind password were stored behind an encoded:
prefix that is base64, not encryption. Anyone reading the database read the
secrets. A second path wrote the same thing behind an encrypted: prefix, which
was also base64 — and the reader even documented that it could not decrypt it.
These belong to the installation rather than to a user: sso_providers has no
userId, and the values must be readable during login, before anyone has
authenticated, so the per-user DEK used elsewhere does not apply. They are now
sealed with AES-256-GCM under the system encryption key, which already protects
other installation-level material.
Reading handles both legacy prefixes so an existing install is not locked out of
SSO login, and a legacy value is upgraded the next time the provider is saved.
The three scattered encode/decode sites are replaced by one module.
* remove the unwired field encryption boundary (#1136)
FieldEncryptionBoundary declared a full sensitive/plaintext policy for six
tables and was referenced only by its own test. Nothing in production used it.
Its policy is byte-for-byte the same as FieldCrypto.ENCRYPTED_FIELDS, which is
the copy that actually runs, so nothing is lost by deleting it. Keeping a second
list is the real risk: someone adds a field to this one, sees it classified as
sensitive, and ships something that was never encrypted.
The one apparent improvement it had — requiring an explicit recordId instead of
DataCrypto's temp-${Date.now()} fallback — turns out to guard against nothing.
decryptField derives its context from the recordId stored inside the ciphertext,
not from the argument, so a temporary id at encryption time still decrypts.
* load the database file when encryption is off (#1137)
* Groundwork for Postgres and MySQL backends (#1134)
* groundwork for postgres and mysql backends
#1127 made the repository layer dialect-agnostic. This adds the pieces needed
to actually target a second engine, as a foundation only — nothing is wired up
and sqlite remains the sole runtime path.
- DatabaseDialect covers sqlite, postgres and mysql, resolved from
DATABASE_DIALECT and defaulting to sqlite so nothing changes for existing
deployments or the desktop build
- a column kit holding the per-dialect type choices in one file: booleans are
integers on sqlite and native elsewhere, autoincrement differs three ways, and
MySQL cannot index unbounded TEXT so key columns need varchar
- settings and users declared for all three dialects as a proof slice, chosen
because between them they use every construct the real schema does
- pg and mysql2 added as dependencies
The tests build real queries for all three engines without a server, asserting
identifier quoting, placeholder style and boolean storage, so the property the
repositories depend on is verified rather than assumed.
* verify foreign keys and unique constraints port across dialects
The first slice only covered plain columns. The real schema also has 92 foreign
keys (80 cascade, 12 set null) and 14 unique columns, so the approach is only
viable if those survive the port.
Adds audit_logs and ssh_folders to the proof slice: one nullable reference with
ON DELETE SET NULL, one required reference with ON DELETE CASCADE, a unique
column, and an autoincrement surrogate key — which is spelled three different
ways underneath (integer primary key autoincrement, serial, int auto_increment).
All of it holds. Worth noting for whoever picks this up: getTableConfig is
dialect-specific and silently fails on a table from another dialect, so the test
uses each engine's own.
* generate the postgres and mysql schemas instead of hand-writing them
The proof slice showed the constructs port, but left the maintenance question
open. Three hand-written copies of 52 tables is the wrong answer: with foreign
keys the copies cross-reference each other, so a renamed table has to land in
three places consistently or a key silently points at the wrong one.
The mapping is mechanical, so a script does it. schema.ts stays the single
source of truth and schema.pg.ts / schema.mysql.ts are derived, covering all 52
tables — the column kit and the two-table portable slice are gone, since the
generator now holds those decisions.
The transforms are the ones the kit enumerated: integer-backed booleans become
native, autoincrement keys become serial or int auto_increment, real becomes
double precision or double, and any column that is a primary key, is unique, or
sits on either end of a foreign key becomes varchar because MySQL cannot index
unbounded TEXT.
> termix@2.6.0 lint
> node scripts/generate-dialect-schema.cjs --check && eslint .
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/database/routes/homepage-favicon-routes.ts
99:12 warning 'err' is defined but never used unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/database/routes/homepage-ping-routes.ts
123:12 warning 'err' is defined but never used unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/database/routes/homepage-rss-routes.ts
144:12 warning 'err' is defined but never used unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/database/routes/session-log-routes.ts
46:16 warning 'canAccessRecording' is defined but never used. Allowed unused vars must match /^_/u unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/hosts/vault-signer-core.ts
55:12 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
75:13 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/tests/hosts/auth-manager.test.ts
18:73 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/tests/utils/shared-host-secrets-manager.test.ts
7:6 warning 'SecretRow' is defined but never used. Allowed unused vars must match /^_/u unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/utils/auth-manager.ts
510:13 warning 'affectedUsers' is assigned a value but never used. Allowed unused vars must match /^_/u unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/utils/notification-sender.ts
48:12 warning 'firstErr' is defined but never used unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/api/ssh-file-operations-api.ts
35:10 warning 'buildFileManagerUrl' is defined but never used. Allowed unused vars must match /^_/u unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/components/folder-style.tsx
61:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
116:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
121:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
149:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/components/proxmox/ProxmoxDiscoverDialog.tsx
109:19 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
190:19 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/HomepageCanvas.tsx
345:15 warning Empty block statement no-empty
388:15 warning Empty block statement no-empty
415:15 warning Empty block statement no-empty
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/dialogs/SingleHostEditForm.tsx
24:6 warning React Hook useEffect has a missing dependency: 'filter'. Either include it or remove the dependency array. If 'setHosts' needs the current value of 'filter', you can also switch to useReducer instead of useState and read 'filter' in the reducer react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/AlertFeedWidget.tsx
93:6 warning React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/CustomApiWidget.tsx
77:6 warning React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/DockerActivityWidget.tsx
50:6 warning React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/DockerWidget.tsx
16:10 warning Fast refresh only works when a file has exports. Move your component(s) to a separate file react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/FileManagerWidget.tsx
16:10 warning Fast refresh only works when a file has exports. Move your component(s) to a separate file react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/HostGridWidget.tsx
61:6 warning React Hook useCallback has a missing dependency: 'hostIds'. Either include it or remove the dependency array react-hooks/exhaustive-deps
61:7 warning React Hook useCallback has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/MetricsChartWidget.tsx
168:6 warning React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/PingStatusWidget.tsx
79:6 warning React Hook useEffect has a missing dependency: 'fetchAll'. Either include it or remove the dependency array react-hooks/exhaustive-deps
79:7 warning React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/QuickConnectWidget.tsx
64:10 warning Fast refresh only works when a file has exports. Move your component(s) to a separate file react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/RecentActivityWidget.tsx
82:6 warning React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array react-hooks/exhaustive-deps
82:17 warning React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/SshQuickConnectWidget.tsx
67:6 warning React Hook useCallback has a missing dependency: 'hostIds'. Either include it or remove the dependency array react-hooks/exhaustive-deps
67:7 warning React Hook useCallback has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
99:17 warning 'online' is assigned a value but never used. Allowed unused vars must match /^_/u unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/SshTerminalWidget.tsx
17:10 warning Fast refresh only works when a file has exports. Move your component(s) to a separate file react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/SystemOverviewWidget.tsx
72:6 warning React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array react-hooks/exhaustive-deps
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/homepage/widgets/TunnelWidget.tsx
15:10 warning Fast refresh only works when a file has exports. Move your component(s) to a separate file react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/features/host-metrics/cards/CpuCard.tsx
14:10 warning 'computeChartData' is defined but never used. Allowed unused vars must match /^_/u unused-imports/no-unused-vars
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/sidebar/FolderPathPicker.tsx
15:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
22:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
/mnt/c/Users/29037/WebstormProjects/Termix/src/ui/sidebar/HostsPanel.tsx
601:52 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
✖ 44 problems (0 errors, 44 warnings) now fails if the generated files are out of date, so editing the
schema without regenerating cannot reach main.
* select durability behaviour per dialect, and document the backends
The onWrite hook every repository receives exists to serialise the in-memory
SQLite database back to its encrypted file. On a client-server engine a
committed write is already durable and there is nothing to flush, so the factory
now installs no hook at all rather than one that does nothing. Repositories call
it as this.onWrite?.(), so none of the 43 of them change.
Also adds docs/database-backends.md, mostly to be explicit about encryption,
which is the part most likely to be misread. Field-level encryption is identical
on all three engines and covers every credential. Whole-file encryption has no
equivalent on Postgres or MySQL, so host names, snippet contents, audit entries
and backups are only as protected as the storage underneath them — that is the
operator's responsibility and the docs should not imply otherwise.
* generate DDL with drizzle-kit, and give settings a synchronous path
Two of the three remaining blockers.
DDL: db/index.ts hand-writes 67 CREATE TABLE statements and 122 ADD COLUMN
migrations, all in SQLite dialect. Rather than port them, drizzle-kit now
generates migrations from the schema modules — 817 lines for Postgres, 869 for
MySQL, with the type mapping already correct because the schemas it reads are
themselves generated.
> termix@2.6.0 schema:migrations
> drizzle-kit generate --config=drizzle.config.pg.ts && drizzle-kit generate --config=drizzle.config.mysql.ts
Reading config file '/mnt/c/Users/29037/WebstormProjects/Termix/drizzle.config.pg.ts'
52 tables
alert_firings 11 columns 0 indexes 2 fks
alert_rule_channels 3 columns 0 indexes 2 fks
alert_rules 11 columns 0 indexes 2 fks
api_keys 9 columns 0 indexes 1 fks
audit_logs 13 columns 0 indexes 1 fks
c2s_tunnel_presets 8 columns 0 indexes 1 fks
command_history 5 columns 0 indexes 2 fks
dashboard_service_links 8 columns 0 indexes 1 fks
dismissed_alerts 4 columns 0 indexes 1 fks
file_manager_pinned 6 columns 0 indexes 2 fks
file_manager_recent 6 columns 0 indexes 2 fks
file_manager_shortcuts 6 columns 0 indexes 2 fks
homepage_items 9 columns 0 indexes 1 fks
homepage_layouts 4 columns 0 indexes 1 fks
host_access 11 columns 0 indexes 5 fks
host_health_checks 7 columns 0 indexes 2 fks
host_health_history 8 columns 0 indexes 2 fks
host_metrics_history 8 columns 0 indexes 1 fks
host_metrics_preferences 6 columns 0 indexes 2 fks
ssh_data 94 columns 0 indexes 6 fks
network_topology 5 columns 0 indexes 1 fks
notification_channels 7 columns 0 indexes 1 fks
opkssh_tokens 12 columns 0 indexes 2 fks
recent_activity 6 columns 0 indexes 2 fks
roles 8 columns 0 indexes 0 fks
session_recordings 15 columns 0 indexes 3 fks
session_share_participants 6 columns 0 indexes 2 fks
session_shares 15 columns 0 indexes 3 fks
sessions 11 columns 0 indexes 1 fks
settings 2 columns 0 indexes 0 fks
shared_host_secrets 15 columns 0 indexes 3 fks
snippet_access 8 columns 0 indexes 4 fks
snippet_folders 8 columns 0 indexes 1 fks
snippets 11 columns 0 indexes 1 fks
ssh_credential_usage 5 columns 0 indexes 3 fks
ssh_credentials 21 columns 0 indexes 1 fks
ssh_folders 9 columns 0 indexes 2 fks
sso_providers 8 columns 0 indexes 0 fks
sync_tombstones 5 columns 0 indexes 1 fks
termix_identities 6 columns 0 indexes 1 fks
termix_identity_ca 8 columns 0 indexes 2 fks
termix_identity_keys 12 columns 0 indexes 3 fks
tmux_session_tags 6 columns 0 indexes 2 fks
transfer_recent 7 columns 0 indexes 3 fks
trusted_devices 8 columns 0 indexes 1 fks
user_open_tabs 9 columns 0 indexes 2 fks
user_preferences 23 columns 0 indexes 1 fks
user_roles 5 columns 0 indexes 3 fks
users 20 columns 0 indexes 0 fks
vault_profiles 18 columns 0 indexes 1 fks
vault_tokens 8 columns 0 indexes 2 fks
webauthn_credentials 12 columns 0 indexes 1 fks
No schema changes, nothing to migrate 😴
Reading config file '/mnt/c/Users/29037/WebstormProjects/Termix/drizzle.config.mysql.ts'
Reading schema files:
/mnt/c/Users/29037/WebstormProjects/Termix/src/backend/database/db/schema.mysql.ts
52 tables
alert_firings 11 columns 0 indexes 2 fks
alert_rule_channels 3 columns 0 indexes 2 fks
alert_rules 11 columns 0 indexes 2 fks
api_keys 9 columns 0 indexes 1 fks
audit_logs 13 columns 0 indexes 1 fks
c2s_tunnel_presets 8 columns 0 indexes 1 fks
command_history 5 columns 0 indexes 2 fks
dashboard_service_links 8 columns 0 indexes 1 fks
dismissed_alerts 4 columns 0 indexes 1 fks
file_manager_pinned 6 columns 0 indexes 2 fks
file_manager_recent 6 columns 0 indexes 2 fks
file_manager_shortcuts 6 columns 0 indexes 2 fks
homepage_items 9 columns 0 indexes 1 fks
homepage_layouts 4 columns 0 indexes 1 fks
host_access 11 columns 0 indexes 5 fks
host_health_checks 7 columns 0 indexes 2 fks
host_health_history 8 columns 0 indexes 2 fks
host_metrics_history 8 columns 0 indexes 1 fks
host_metrics_preferences 6 columns 0 indexes 2 fks
ssh_data 94 columns 0 indexes 6 fks
network_topology 5 columns 0 indexes 1 fks
notification_channels 7 columns 0 indexes 1 fks
opkssh_tokens 12 columns 0 indexes 2 fks
recent_activity 6 columns 0 indexes 2 fks
roles 8 columns 0 indexes 0 fks
session_recordings 15 columns 0 indexes 3 fks
session_share_participants 6 columns 0 indexes 2 fks
session_shares 15 columns 0 indexes 3 fks
sessions 11 columns 0 indexes 1 fks
settings 2 columns 0 indexes 0 fks
shared_host_secrets 15 columns 0 indexes 3 fks
snippet_access 8 columns 0 indexes 4 fks
snippet_folders 8 columns 0 indexes 1 fks
snippets 11 columns 0 indexes 1 fks
ssh_credential_usage 5 columns 0 indexes 3 fks
ssh_credentials 21 columns 0 indexes 1 fks
ssh_folders 9 columns 0 indexes 2 fks
sso_providers 8 columns 0 indexes 0 fks
sync_tombstones 5 columns 0 indexes 1 fks
termix_identities 6 columns 0 indexes 1 fks
termix_identity_ca 8 columns 0 indexes 2 fks
termix_identity_keys 12 columns 0 indexes 3 fks
tmux_session_tags 6 columns 0 indexes 2 fks
transfer_recent 7 columns 0 indexes 3 fks
trusted_devices 8 columns 0 indexes 1 fks
user_open_tabs 9 columns 0 indexes 2 fks
user_preferences 23 columns 0 indexes 1 fks
user_roles 5 columns 0 indexes 3 fks
users 20 columns 0 indexes 0 fks
vault_profiles 18 columns 0 indexes 1 fks
vault_tokens 8 columns 0 indexes 2 fks
webauthn_credentials 12 columns 0 indexes 1 fks
No schema changes, nothing to migrate 😴 regenerates both.
Settings: 27 call sites read settings synchronously, during startup and inside
request handlers. better-sqlite3 can do that; Postgres and MySQL cannot, and
making all 27 async would push await through code that has no reason to be
asynchronous. Settings are a handful of rarely-changing rows read constantly, so
they are cached in full — primed at startup, kept in step by SettingsRepository
on every set/delete/deleteLike. SQLite keeps reading the database directly and
stays authoritative; only the other engines use the cache.
Opening a connection is still not done. DatabaseContext.drizzle is typed as
BetterSQLite3Database and 43 repositories depend on that inference; the three
drizzle instance types are not interchangeable, so widening it is a design
decision rather than a mechanical change.
* exclude drizzle-kit output from prettier
The generated migrations and snapshots are tool output; their formatting is
drizzle-kit's to decide, and prettier cannot parse the .sql files at all.
* absorb the RETURNING gap so mysql stays reachable
MySQL has no RETURNING clause and drizzle's mysql-core does not expose the
method, while 156 call sites here read the result of a write. That is the real
blocker for MySQL, not the connection layer.
Classifying those call sites showed the split is favourable: 92 of them only
read .length, which every engine reports — as a returned array on sqlite and
postgres, as affectedRows on MySQL. rowsAffected() reads both shapes, so those
sites need no change in query shape. insertedId() does the same for the
autoincrement key, which MySQL reports as insertId.
What is left is the ~34 sites that genuinely consume the returned rows. Those
cannot be emulated without reading first, which needs a transaction to stay
correct under concurrency, so they will be handled individually rather than
behind a helper that quietly adds a round trip. supportsReturning() is the seam
for that.
Identifying the mysql2 result by its own fields rather than by array shape
matters: it hands back [ResultSetHeader, fields], which is an array, so shape
alone cannot tell it apart from a returning() result.
* name the portable database type, and open remote connections
Two pieces of the connection layer.
drizzle's three Database classes share no base class and their signatures are
incompatible, so there is no honest type that covers all three: a union is not
callable and a generic would have to be threaded through 43 repositories and
every method on them. DatabaseContext.drizzle is now PortableDatabase, still
the SQLite type underneath, but named and documented as the deliberate
approximation it is. What makes it safe is that the equivalence is asserted in
multi-dialect.test.ts rather than assumed, and the one place the surfaces truly
differ — RETURNING — is handled explicitly in mutation-result.ts.
connect.ts opens Postgres and MySQL from DATABASE_URL, with the schema module
and driver imported lazily so neither is loaded on a SQLite deployment. The URL
scheme is checked against the configured dialect first: a postgres:// URL with
DATABASE_DIALECT=mysql otherwise surfaces as a driver error deep in a stack
that never mentions the actual misconfiguration.
* open postgres and mysql at startup
* count writes without RETURNING
* read affected rows without RETURNING on mysql
* insert without RETURNING, and split the sync transactions
* stop pretending the generated schemas are used at runtime
* run the dialect checks in CI
* mysql rejects a bare CURRENT_TIMESTAMP default on text
* make the read-back mismatch loud, and stop the next bare returning()
* run the repository tests on the real schema
* skip the byte-level assertions off sqlite
* move generated ids past the seeded ones
* keep the export order the same on every engine
* stop reading better-sqlite3 fields off every write
* read counts as numbers, not whatever the driver returns
* make the fixture usable against a live server
* upsert on the engine that has no ON CONFLICT
* run the repository suite on all three engines in CI
* mysql cannot index a text column without a length
* document how to actually run on postgres or mysql
* keep the sqlite-era migrations off the other engines
* concat strings in a way mysql agrees with
* run every repository test on every engine
* bound how long replicas can disagree about settings
* generate the sqlite migrations alongside the others
* Bump version from 2.6.0 to 2.6.1
* resolve the dialect in the repository factory instead of assuming sqlite (#1143)
createCurrentRepositoryContext() hardcoded `dialect: "sqlite"` while the
runtime already carried all three engines. That field is not decoration:
returning.ts reads it to decide whether it can ask for RETURNING, and
whether an upsert spells itself onConflictDoUpdate or onDuplicateKeyUpdate.
Reporting sqlite while connected to MySQL means the first upsert calls
onConflictDoUpdate on a mysql2 insert builder, which does not have it --
a TypeError, not a rejected query, as the note in returning.ts warned.
So MySQL never worked outside the tests, and Postgres worked only because
it also supports RETURNING and shares the conflict syntax.
Three things were supposed to catch this and none could. The repository
suite builds its own DatabaseContext in test-support.ts, verify-dialects.mjs
builds its own, and the CI matrix runs both against real Postgres and MySQL
containers -- all of them bypassing the one function the application calls.
Green on three engines, broken on two.
Resolve it from the environment, and test the factory itself rather than a
hand-built context: the default, each configured dialect, the write hook it
installs only for sqlite, and that an unsupported value throws rather than
falling back. Reverting the fix fails two of them.
FixesTermix-SSH/Support#282
* fix remote sync stalling after the first pass and never propagating deletions (#1140)
The incremental cursor never matched. updated_at/deleted_at are TEXT columns
written by CURRENT_TIMESTAMP ("2026-07-29 10:11:21"), while the client sends
an ISO 8601 since ("2026-07-29T10:06:55.172Z"). Both comparisons are lexical
and ' ' sorts below 'T', so a newer row lost at position 10 and every
?since= query came back empty. Pass 1 syncs everything (since is null) and
persists a cursor; every pass after it returns nothing with lastError: null
and reports success. Normalize since into the stored shape on the way in,
leaving an already-normalized value alone -- parsing that would treat it as
local time and, west of UTC, push the cursor past unsynced rows.
POST /sync/tombstones was unreachable. It was registered after
POST /:entityType, and "tombstones" is a valid :entityType, so the wildcard
answered it with 400 "Unknown entity type" and the handler never ran. The
pass has no per-entity error handling, so that 400 also discarded the state
of every entity type already synced in the same pass. Move it ahead of the
wildcards.
The tombstone guard consulted the incremental window. A row deleted on one
side and untouched on the other -- the shape every ordinary deletion takes
once the two sides converge -- is not in that window, so the tombstone was
skipped, and skipped again on each later pass as it slid out of its own
window. The guard cannot just be dropped: recording a tombstone for a row
that was already gone hands the sender a fresh one to push back, and the two
trade the same deletion forever. So only a delete that removed something
records a tombstone, which makes the endpoint idempotent and lets the client
push every tombstone unconditionally.
Deletions missed while the cursor was broken stay missed -- their tombstones
predate the persisted cursor. Ordinary edits do come through, since the
row's updatedAt is still newer than it.
FixesTermix-SSH/Support#1050FixesTermix-SSH/Support#1051
* report why every JWKS fetch failed instead of swallowing the reason (#1142)
An OIDC login that cannot reach the provider's keys ends in "Failed to
fetch JWKS from any URL" and nothing else. Getting there discards
everything worth knowing: a non-2xx response hit an empty else branch, a
thrown request hit a bare `continue`, and discovery only logged when it
threw -- a 404 or a document without jwks_uri passed in silence. An
administrator cannot tell an issuer URL typo from a proxy, a private CA,
or an outage at the provider, and neither can anyone reading the report.
Collect each attempt with its reason and put them in the thrown error.
It reaches the log through the existing "OIDC callback failed" handler;
the browser still gets the same generic message it did before.
Unwrapping the cause is the part that matters: undici reports every
transport failure as "fetch failed" and hangs the real reason -- ENOTFOUND,
ECONNREFUSED, a certificate that will not verify -- off error.cause. An
attempt list built from the outer messages would be as useless as the
single line it replaces.
Also require jwks_uri to be a string before using it, so a malformed
discovery document is reported as such rather than as a failed fetch of
"[object Object]".
Refs Termix-SSH/Support#1047
* restore the closing quote on the version string (#1147)
"Bump version from 2.6.0 to 2.6.1" (2a66775) wrote
"version": "2.6.1,
dropping the closing quote, so package.json has not been valid JSON since.
Anything that parses it fails: npm install, npm run build, and every CI run
on this branch -- vitest cannot even load its config, because vite reads
package.json before it gets to the test files.
2.6.1 cannot be built or released until this is fixed, which is why it goes
in on its own rather than riding along with anything else.
* Revert "fix remote sync stalling after the first pass and never propagating deletions (#1140)" (#1146)
This reverts commit ca7abf8426.
Reverted for process, not for content. Both defects were reported by
@kacperpietrzyk in Support#1050 and Support#1051, and he opened #1138 and
#1139 fixing them 4.5 hours before #1140 was filed. Merging #1140 made two
PRs from the person who found and diagnosed the bugs redundant.
#1138 and #1139 stand on their own: the same root-cause analysis, complete
regression tests, and a tombstone guard that only pays for its extra lookup
on a pass that actually carries a deletion. There is no technical reason to
prefer the reverted commit over them.
The sync fixes land through those two PRs instead.
* fix: make sync deletions reach the other side (#1139)
* fix: apply sync tombstones to rows outside the incremental window
Deletions never reached the other side. `syncEntity` decides whether to apply a
tombstone by looking the row up in `localBySyncId` / `remoteBySyncId`, which are
built from `pullSide(..., since)` -- the incremental window. A row deleted on one
side and untouched on the other is by definition absent from that window, which
is the shape every ordinary deletion takes once the two sides have converged, so
the tombstone was silently skipped and never retried.
The guard cannot simply be dropped. `POST /sync/tombstones` records a tombstone
on the receiving side, so an unconditional push would give the other side a fresh
tombstone to push back on the following pass, and the two would trade deletions
forever.
Instead ask the receiving side what it still holds, ignoring the window, and only
when there is a deletion to apply -- so an ordinary pass costs nothing extra, and
a pass carrying a deletion costs one additional list per affected entity type.
Once the row is gone the push stops, so nothing ping-pongs.
Note this only becomes observable together with the cursor fix in
Termix-SSH/Support#1050: while that defect is present the tombstone endpoint
returns nothing at all, so there is no tombstone to apply in the first place.
Refs Termix-SSH/Support#1034
* fix: make the sync tombstone endpoint reachable
`POST /sync/tombstones` was registered after `POST /:entityType`, and Express
matches in registration order, so every deletion push was swallowed by the
wildcard: "tombstones" is a perfectly good value for :entityType, fails
isValidEntityType, and comes back as 400 "Unknown entity type". The handler
below it has never run.
Registering the literal path before the parameterised one restores it. The
regression test reads the router stack rather than the source, so a future
re-order fails the test rather than silently disabling deletions again.
The GET pair is unaffected -- "/:entityType/tombstones" and "/:entityType" have
different segment counts, so they cannot shadow each other.
* feat: add host export dialog with host and field selection (#1108)
* fix: compare sync cursors independently of timestamp layout (#1138)
* fix: compare sync cursors independently of timestamp layout
Incremental sync returned nothing after its first pass. `GET /sync/:entityType`
filters with `gt(table.updatedAt, since)` on a TEXT column, and the tombstone
endpoint does the same through `listSince`, but the two sides of that comparison
are written in different layouts: the columns default to `CURRENT_TIMESTAMP`
("2026-07-29 10:11:21") while the desktop engine sends `new Date().toISOString()`
("2026-07-29T10:06:55.172Z"). Text comparison is decided at position 10, where
' ' (0x20) sorts below 'T' (0x54), so the predicate answers on layout rather than
on time and is false for every CURRENT_TIMESTAMP row however new it is.
The engine only sends a cursor from the second pass onward, so pass 1 synced
everything and passes 2..n pulled zero rows and zero tombstones while reporting
success -- edits and deletions silently stopped propagating in both directions.
This was masked until now: before the reference fix in #1092 the loop threw
before persisting state, so the cursor never advanced past null and every cycle
was a full sync.
Comparing "YYYY-MM-DD HH:MM:SS" on both sides is layout-independent. `replace`
and `substr` are used rather than `datetime()` to keep the expression portable
across engines, since the repository layer is deliberately drizzle-only. The
comparison is `>=` because normalising truncates sub-second precision, and a
strict `>` would permanently skip rows written in the cursor's own second; the
re-sent boundary rows are a no-op, as the engine pushes only when one side is
strictly newer.
`updatedAt` is written in both layouts across the codebase (14 sites use
toISOString, 11 use CURRENT_TIMESTAMP), so the tests cover rows of each kind.
ClosesTermix-SSH/Support#1050
* test: seed the cursor tests against the migrated schema
#1134 moved schema creation into the repository test harness, so the
hand-written CREATE TABLE blocks here collided with tables that already
existed. Seeding into the real tables instead surfaced two constraints the
local definitions had papered over: the harness enables foreign keys and
both `sync_tombstones.user_id` and `ssh_credentials.user_id` reference
`users`, so the owning row has to be seeded first; and `auth_type` is NOT
NULL with no default, unlike the local copy.
`exec` is awaited, since it only returns synchronously on SQLite.
The assertions are unchanged.
* Make Proxmox guest discovery and import reliable over a jump host (#1144)
* fix: repair unterminated version string in package.json
The version field on dev-2.6.1 reads "2.6.1, (no closing quote), which
makes package.json invalid JSON and breaks every npm invocation on the
branch. Close the string so the branch builds.
* fix(proxmox): reliable guest discovery and import over jump hosts
Importing Proxmox guests from a node reachable only through a jump host
(with the guests behind the same jump) failed in a chain of small ways.
- Discovery timed out intermittently: execCommand capped every pvesh call
at 8s, but a single call over a jump measured ~8.3s. Raised to 25s for
core calls and 12s for best-effort agent/interface lookups.
- No IPs were resolved (so nothing imported): resolveIp fanned out 6
concurrent pvesh calls; on a small node they contend (3 concurrent
already exceeded the timeout), so every IP came back empty. Lowered
CONCURRENCY to 2.
- RDP guests aborted the whole sync via NOT NULL on ssh_data.username;
use "" instead of null (matches the normal create path).
- Guests without a resolvable IP (e.g. QEMU with no guest agent) were
skipped entirely; they now import with a 0.0.0.0 placeholder, and
re-sync preserves any manually entered IP (guest.ip || existing.ip).
- Manual import did not inherit the source host's jump chain or
credential (guests ended up unreachable with authType "none"). The
discovery result now carries the source jumpHosts, and
resolveProxmoxImportAuth uses an available credential even under the
default "password" authType (explicit secretless choices still win).
- Long discoveries had no feedback and fought client/proxy timeouts;
added an SSE endpoint GET /proxmox/discover/stream (heartbeat + n/N
progress), keeping POST /discover as a fallback. Also always render the
IP cell in the discovery table so IP-less rows stay aligned.
Adds a unit test for resolveProxmoxImportAuth covering the credential
inheritance behaviour.
* test(proxmox): lock resolveProxmoxImportAuth matrix on both copies; fix agent secretless drift
- extract the backend decision into src/backend/database/routes/proxmox-import-auth.ts
(leaf module mirroring the UI copy) so it is unit-testable without pulling the
whole backend module graph into the test env
- add src/backend/tests/database/routes/proxmox-import-auth.test.ts asserting the
shared matrix (lifted from #1141, thanks @ZacharyZcR)
- consolidate the UI test into src/ui/tests/components/proxmox/proxmox-import-auth.test.ts
and drop the duplicate src/ui/tests/proxmox/ copy
- add 'agent' to the UI SECRETLESS_AUTH_TYPES: the one real auth type where the two
copies still diverged (UI -> credential, backend -> passthrough)
* fix(hosts): parse portKnockSequence JSON in host-resolver (#1149)
host-resolver JSON-parses jumpHosts/tunnelConnections/statsConfig/
terminalConfig/socks5ProxyChain/quickActions but NOT portKnockSequence.
Empty knock is stored as the string "[]" (UI save of empty array); the
terminal code then checks portKnockSequence.length > 0 on the STRING, so
"[]".length === 2 is truthy -> logs 'Loaded 2 port knock(s)' and attempts
a bogus knock. Real knock sequences (JSON string) are likewise never
parsed to the Array<{port,...}> that performPortKnocking expects, so a
genuine knock would never fire. Parse portKnockSequence like the other
JSON columns: '[]' -> [] (length 0, no knock), real seq -> array.
Adds unit tests for both cases.
Co-authored-by: XtraLarge <xtralarge@users.noreply.github.com>
* Feature request map OIDC provider groups to RBAC roles (#1148)
* Bump version from 2.6.0 to 2.6.1 in package-lock.json
* Fix formatting issue in package-lock.json
* Feature request map OIDC provider groups to RBAC roles
Group membership from an OIDC provider currently drives only a single
boolean: OIDC_ADMIN_GROUP toggles isAdmin and switches the user between
the built-in `admin` and `user` roles. There is no way to map a provider
group onto a custom role, so deployments that use host_access grants for
environment-scoped access (e.g. a role that can reach staging hosts and
another that can reach production) have to assign those roles by hand
for every user.
Add OIDC_ROLE_MAP, a comma- or newline-separated list of `group:role`
pairs, reconciled against the user's roles on each OIDC login:
OIDC_ROLE_MAP=devops-interns:devops-intern,devops-seniors:devops-senior
Only roles named in the map are ever added or removed. Roles assigned by
hand, and the admin/user pair maintained by the existing admin-group
sync, are deliberately left untouched so the two mechanisms don't fight
each other. Group names are matched case-insensitively with leading
slashes stripped, so providers that emit full group paths (Keycloak's
"Full group path" option) work without extra configuration.
Reuses the existing extractOidcGroups claim handling, so custom claim
paths via OIDC_GROUP_CLAIM are supported too, and invalidates the
permission cache when roles change so new grants apply to the session
that triggered the sync. Malformed map entries are skipped and a failed
sync is logged but non-fatal — neither can block a valid login.
Adds unit tests for the parser and resolver covering full group paths,
multi-group membership, colons in group names and malformed input.
---------
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
* feat: support for overriding shared host ssh credentials (#1145)
* Bump version from 2.6.0 to 2.6.1 in package-lock.json
* Fix formatting issue in package-lock.json
* feat: support for overriding ssh credentials
---------
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
* ci(deps): bump the github-actions group with 2 updates (#1150)
* Bump version from 2.6.0 to 2.6.1 in package-lock.json
* Fix formatting issue in package-lock.json
* Update README to remove Tailscale and add Ginernet
Removed Tailscale logo and link from the README. Added Ginernet logo and link.
* Update README.md
* ci(deps): bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [actions/setup-node](https://github.com/actions/setup-node) and [useblacksmith/setup-docker-builder](https://github.com/useblacksmith/setup-docker-builder).
Updates `actions/setup-node` from 6 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)
Updates `useblacksmith/setup-docker-builder` from 1 to 2
- [Release notes](https://github.com/useblacksmith/setup-docker-builder/releases)
- [Commits](https://github.com/useblacksmith/setup-docker-builder/compare/v1...v2)
---
updated-dependencies:
- dependency-name: actions/setup-node
dependency-version: '7'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: github-actions
- dependency-name: useblacksmith/setup-docker-builder
dependency-version: '2'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: github-actions
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump the prod-minor-updates group with 3 updates (#1154)
* Bump version from 2.6.0 to 2.6.1 in package-lock.json
* Fix formatting issue in package-lock.json
* Update README to remove Tailscale and add Ginernet
Removed Tailscale logo and link from the README. Added Ginernet logo and link.
* Update README.md
* chore(deps): bump the prod-minor-updates group with 3 updates
Bumps the prod-minor-updates group with 3 updates: [axios](https://github.com/axios/axios), [motion](https://github.com/motiondivision/motion) and [undici](https://github.com/nodejs/undici).
Updates `axios` from 1.18.1 to 1.19.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.18.1...v1.19.0)
Updates `motion` from 12.42.2 to 12.43.0
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.42.2...v12.43.0)
Updates `undici` from 8.7.0 to 8.9.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v8.7.0...v8.9.0)
---
updated-dependencies:
- dependency-name: axios
dependency-version: 1.19.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: prod-minor-updates
- dependency-name: motion
dependency-version: 12.43.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: prod-minor-updates
- dependency-name: undici
dependency-version: 8.9.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: prod-minor-updates
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* fix: data guard test failure
* chore(deps): bump 23 dependencies and fix dialect-unsafe queries
Applies the non-major updates from the open dependabot PRs directly,
since dependabot rebases against main and could not resolve its
lockfiles against this branch. Holds back typescript 7 and jsdom 30;
those majors need their own pass.
Reformats with prettier 3.9.6, which collapses short union types onto
one line. Formatting only: the compiled backend output is byte for byte
identical.
Also fixes two lint errors in the shared host auth override repository,
where onConflictDoUpdate and .returning() are SQLite-only and broke the
Postgres and MySQL builds, and drops unused imports left over from the
shared host auth override merge.
* chore: reversal of legal work
* feat: improve pin side rail button position and added env var for telemetrics
* Add Ctrl+F terminal search (#1156)
* Bump version from 2.6.0 to 2.6.1 in package-lock.json
* Fix formatting issue in package-lock.json
* Update README to remove Tailscale and add Ginernet
Removed Tailscale logo and link from the README. Added Ginernet logo and link.
* Update README.md
* Add Ctrl+F terminal search
---------
Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* fix: host export dialog using incorrect widths
* fix: made logger display expanded errors
* feat: added support for multi disk usage in file manager and host metrics
* chore: harden nginx headers and improve static asset caching
* chore: format
* chore: update release notes
* fix: default font size to md instead of lg
* feat: support Tailscale SSH check mode
* chore: sync Crowdin translations for 2.6.1
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Brennan Neoh <497569+brennanneoh@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: kacperpietrzyk <105545577+kacperpietrzyk@users.noreply.github.com>
Co-authored-by: Max <50905012+maxiwolleb@users.noreply.github.com>
Co-authored-by: XtraLarge <eMail@WilliWerres.de>
Co-authored-by: XtraLarge <xtralarge@users.noreply.github.com>
Co-authored-by: Devin Dissanayaka <dsdissanayaka2002@gmail.com>
Co-authored-by: Peter Cinibulk <petercinibulk@gmail.com>
Co-authored-by: Med Ali Ezzeddine <47082236+xDaly@users.noreply.github.com>
* feat: continued adding features to the release.yml
* feat: added auto youtube submit
* feat: add dry run to release workflow
* feat: improve release workflow mode system with new dropdown and overwrite release mode
* fix: make credentials start collapsed
* fix: make hostname fill entire column and truncate at proper spot in dashboard
* fix: guacamole display using an incorrect height
* feat: add folder management (nested folders, folder icons, folder colors, improved folder selection, etc.)
* feat: move ssh host config outside of top tab bar and into new tab bar visible when on SSH tab
* fix: 2FA failing to disable
* feat: Proxmox guest discovery and import (#881)
* feat(db): add Proxmox host fields and schema migration
Add enableProxmox flag and proxmoxConfig JSON to the hosts table so an
SSH host can be marked as a Proxmox node and carry per-host discovery
settings (default credential, Windows/Docker name patterns, preferred
IP prefixes). Includes addColumnIfNotExists migration entries and the
matching SSHHost / HostData / Host type definitions.
* feat(api): add Proxmox guest discovery endpoint
Add POST /proxmox/discover which connects to a Proxmox node over SSH
using the host's existing stored credentials (no separate API token),
runs pvesh to enumerate cluster guests, and returns VMs and LXC
containers ready to import. Guest IPs are resolved with bounded
concurrency (LXC from net config, QEMU via guest agent) to stay within
the node's SSH MaxSessions; configured preferred prefixes pick the
address when a guest has several. Name patterns flag Windows guests as
RDP and enable Docker. Node names are validated before use in shell
commands and the SSH connection is always closed via try/finally. The
endpoint carries an OpenAPI annotation. Persists the new host fields
across host create/update/select, the normalizers (transformHostResponse)
and the bulk routes, with normalizer test coverage.
* feat(ui): add Proxmox host settings and guest import
Add a Proxmox tab to the host editor (following the Docker tab pattern)
to enable the integration and configure the default credential, name
patterns and preferred IP ranges. Proxmox-enabled hosts show a discover
action in the sidebar that opens an import dialog listing the cluster's
guests with multi-select; the import reuses the host's credential, maps
Windows guests to RDP, and groups imported guests into a folder named
after the Proxmox host. Also exposes the import via the hosts
import/export menu. All user-facing strings are added to the en.json
locale and rendered via i18n. Built with the existing shadcn Select,
dialog and section-card components to match the dark theme.
* feat(ui): add Proxmox to the bulk feature toggle
Proxmox was the only host feature missing from the multi-select
"Features" menu. Enabling it in bulk is special: unlike the other
toggles it needs a credential to be useful, so each host now defaults
its Proxmox credential to the credential already stored on that host
(host.credentialId). Discovery then works right away without picking
one by hand, and per-host settings can still be adjusted afterwards.
- SidebarTree: Enable/Disable Proxmox entries (Boxes icon) in the
bulk Features dropdown
- host-bulk-routes: enabling Proxmox runs per-host so each host keeps
its own default credential; existing proxmoxConfig is preserved;
disabling stays a simple flag flip
- en.json: enableProxmoxFeature / disableProxmoxFeature
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix: reliable OIDC group syncing for admin roles (#882)
- always fetch from the userinfo endpoint to get extra claims (like `groups` from Authelia) instead of skipping it if the id_token was already parsed
- handle cases where the OIDC provider sends groups as a single string, a comma-separated string
- add debug logging
* fix: incorrect guacd screen height
* fix: guacd black screen on connnection
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* feat: initial server stats rewrite (renamed to host metrics)
* feat: continue renaming and improving host metrics features and UI
* fix: clipboard copy fails in Brave/non-HTTPS, dashboard total credentials stuck at 0, host username ignored when credential attached, cloned host can't switch auth method, file-manager context menu off-screen, file delete affecting inactive tabs, silent delete failure on Windows hosts, iPad host tap does nothing, OIDC custom group claim support
* chore: update dependabot for my app and add auto merge/branch update
* chore: update dependabot for my app and add auto merge/branch update
* Feat/docker release tag (#894)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* feat(docker): add version tag to production Docker image tags
---------
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* fix: disable hardware acceleration on Windows to prevent startup crash (#895)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* fix: disable hardware acceleration on Windows to prevent startup crash
---------
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* chore(deps-dev): bump the dev-patch-updates group across 1 directory with 23 updates (#893)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps-dev): bump the dev-patch-updates group across 1 directory with 23 updates
Bumps the dev-patch-updates group with 22 updates in the / directory:
| Package | From | To |
| --- | --- | --- |
| [@codemirror/autocomplete](https://github.com/codemirror/autocomplete) | `6.20.2` | `6.20.3` |
| [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) | `21.0.1` | `21.0.2` |
| [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) | `21.0.1` | `21.0.2` |
| [@radix-ui/react-accordion](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/accordion) | `1.2.12` | `1.2.13` |
| [@radix-ui/react-alert-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/alert-dialog) | `1.1.15` | `1.1.16` |
| [@radix-ui/react-checkbox](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/checkbox) | `1.3.3` | `1.3.4` |
| [@radix-ui/react-dialog](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dialog) | `1.1.15` | `1.1.16` |
| [@radix-ui/react-dropdown-menu](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/dropdown-menu) | `2.1.16` | `2.1.17` |
| [@radix-ui/react-label](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/label) | `2.1.8` | `2.1.9` |
| [@radix-ui/react-popover](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/popover) | `1.1.15` | `1.1.16` |
| [@radix-ui/react-progress](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/progress) | `1.1.8` | `1.1.9` |
| [@radix-ui/react-scroll-area](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/scroll-area) | `1.2.10` | `1.2.11` |
| [@radix-ui/react-separator](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/separator) | `1.1.8` | `1.1.9` |
| [@radix-ui/react-tabs](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tabs) | `1.1.13` | `1.1.14` |
| [@radix-ui/react-tooltip](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/tooltip) | `1.2.8` | `1.2.9` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.9.1` | `25.9.2` |
| [i18next](https://github.com/i18next/i18next) | `26.3.0` | `26.3.1` |
| [lint-staged](https://github.com/lint-staged/lint-staged) | `17.0.5` | `17.0.7` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.6` | `19.2.7` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.15` | `19.2.17` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.6` | `19.2.7` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.14` | `8.0.16` |
Updates `@codemirror/autocomplete` from 6.20.2 to 6.20.3
- [Changelog](https://github.com/codemirror/autocomplete/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/autocomplete/commits)
Updates `@commitlint/cli` from 21.0.1 to 21.0.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.0.2/@commitlint/cli)
Updates `@commitlint/config-conventional` from 21.0.1 to 21.0.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.0.2/@commitlint/config-conventional)
Updates `@radix-ui/react-accordion` from 1.2.12 to 1.2.13
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/accordion/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/accordion)
Updates `@radix-ui/react-alert-dialog` from 1.1.15 to 1.1.16
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/alert-dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/alert-dialog)
Updates `@radix-ui/react-checkbox` from 1.3.3 to 1.3.4
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/checkbox/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/checkbox)
Updates `@radix-ui/react-dialog` from 1.1.15 to 1.1.16
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dialog/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dialog)
Updates `@radix-ui/react-dropdown-menu` from 2.1.16 to 2.1.17
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/dropdown-menu/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/dropdown-menu)
Updates `@radix-ui/react-label` from 2.1.8 to 2.1.9
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/label/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/label)
Updates `@radix-ui/react-popover` from 1.1.15 to 1.1.16
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/popover/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/popover)
Updates `@radix-ui/react-progress` from 1.1.8 to 1.1.9
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/progress/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/progress)
Updates `@radix-ui/react-scroll-area` from 1.2.10 to 1.2.11
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/scroll-area/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/scroll-area)
Updates `@radix-ui/react-separator` from 1.1.8 to 1.1.9
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/separator/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/separator)
Updates `@radix-ui/react-slot` from 1.2.4 to 1.2.5
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/slot/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/slot)
Updates `@radix-ui/react-tabs` from 1.1.13 to 1.1.14
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tabs/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tabs)
Updates `@radix-ui/react-tooltip` from 1.2.8 to 1.2.9
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/tooltip/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/tooltip)
Updates `@types/node` from 25.9.1 to 25.9.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)
Updates `i18next` from 26.3.0 to 26.3.1
- [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.0...v26.3.1)
Updates `lint-staged` from 17.0.5 to 17.0.7
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v17.0.5...v17.0.7)
Updates `react` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react)
Updates `@types/react` from 19.2.15 to 19.2.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)
Updates `react-dom` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom)
Updates `vite` from 8.0.14 to 8.0.16
- [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.0.16/packages/vite)
---
updated-dependencies:
- dependency-name: "@codemirror/autocomplete"
dependency-version: 6.20.3
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@commitlint/cli"
dependency-version: 21.0.2
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@commitlint/config-conventional"
dependency-version: 21.0.2
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-accordion"
dependency-version: 1.2.13
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-alert-dialog"
dependency-version: 1.1.16
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-checkbox"
dependency-version: 1.3.4
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dialog"
dependency-version: 1.1.16
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-dropdown-menu"
dependency-version: 2.1.17
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-label"
dependency-version: 2.1.9
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-popover"
dependency-version: 1.1.16
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-progress"
dependency-version: 1.1.9
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-scroll-area"
dependency-version: 1.2.11
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-separator"
dependency-version: 1.1.9
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-slot"
dependency-version: 1.2.5
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tabs"
dependency-version: 1.1.14
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@radix-ui/react-tooltip"
dependency-version: 1.2.9
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@types/node"
dependency-version: 25.9.2
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: i18next
dependency-version: 26.3.1
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: lint-staged
dependency-version: 17.0.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: react
dependency-version: 19.2.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: "@types/react"
dependency-version: 19.2.17
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: react-dom
dependency-version: 19.2.7
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
- dependency-name: vite
dependency-version: 8.0.16
dependency-type: direct:development
update-type: version-update:semver-patch
dependency-group: dev-patch-updates
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump undici from 7.26.0 to 8.4.0 (#891)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps): bump undici from 7.26.0 to 8.4.0
Bumps [undici](https://github.com/nodejs/undici) from 7.26.0 to 8.4.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.26.0...v8.4.0)
---
updated-dependencies:
- dependency-name: undici
dependency-version: 8.4.0
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump the prod-minor-updates group with 2 updates (#890)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps): bump the prod-minor-updates group with 2 updates
Bumps the prod-minor-updates group with 2 updates: [axios](https://github.com/axios/axios) and [js-yaml](https://github.com/nodeca/js-yaml).
Updates `axios` from 1.16.1 to 1.17.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.16.1...v1.17.0)
Updates `js-yaml` from 4.1.1 to 4.2.0
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/commits)
---
updated-dependencies:
- dependency-name: axios
dependency-version: 1.17.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: prod-minor-updates
- dependency-name: js-yaml
dependency-version: 4.2.0
dependency-type: direct:production
update-type: version-update:semver-minor
dependency-group: prod-minor-updates
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump actions/setup-node from 4 to 6 (#887)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps): bump actions/setup-node from 4 to 6
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)
---
updated-dependencies:
- dependency-name: actions/setup-node
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump actions/checkout from 4 to 6 (#886)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps): bump actions/checkout from 4 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-version: '6'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump actions/upload-artifact from 4 to 7 (#885)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps): bump actions/upload-artifact from 4 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)
---
updated-dependencies:
- dependency-name: actions/upload-artifact
dependency-version: '7'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore(deps): bump actions/download-artifact from 4 to 8 (#884)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* chore(deps): bump actions/download-artifact from 4 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)
---
updated-dependencies:
- dependency-name: actions/download-artifact
dependency-version: '8'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* chore: automate rebasing dependabot
* feat: add admin settings audit log feature
* feat: add customizability of app rail tabs
* fix: host metrics giving sudo password error
* feat: add terminal session logging
* feat: sso system redesign (multiple oidc, ldap support, etc.)
* feat: tailscale auth support
* feat: improve syntax highlighting system
* feat: improve nested folder system/ui
* feat: improve nested folder system/ui
* fix: move tailscale i18n and add scrollbar to ssh host manager customization
* feat: improve syntax highlighting, fix tailscale bugs and host manger UX
* fix: admin page not loading user admin information
* chore: update crowdin workflow
* fix: guacd getting passed incorrect protocol for app view
* fix: add SFTP jump-host fallback from host data (#902)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* fix: add SFTP jump-host fallback from host data
---------
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* feat(tmux-monitor): add per-host tmux session monitor (#896)
* fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)
* Revert "fix(docker): use resolveTermixThemeColors for Docker console terminal background (#883)"
This reverts commit 4d04559ca5.
* feat(tmux-monitor): add per-host tmux session monitor
New isolated feature module following the docker/server-stats pattern:
- Backend Express service on port 30010 (src/backend/ssh/tmux-monitor.ts)
listing tmux sessions/windows/panes, pane capture, cross-session
output search, and per-pane CPU/RAM/GPU metrics over pooled SSH
connections. Read-only; reuses host-resolver, jump-host-chain,
connection pool and RBAC access checks.
- tmux_session_tags table for per-user project tags on sessions.
- Frontend fullscreen app at ?view=tmux-monitor with host selector,
session/window/pane tree, live pane preview (2s polling), search
bar, metrics display, and tag editing.
- nginx location blocks for /tmux_monitor in Docker deployments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): live streaming backend and shell integration
- WebSocket service on port 30011 (tmux-monitor-live.ts) bridging tmux
control mode (-C attach-session) to the browser: subscribe per pane,
decoded %output events streamed as JSON, structure-change and detach
notifications. Pure control-mode parser with 17 unit tests.
- Register tmux_monitor as a singleton shell tab: AppRail entry below
Network Graph, global Command Palette action, and per-host palette
action (gated on enableTerminal) that opens with the host preselected.
- nginx WebSocket location /tmux_monitor/live/ for Docker deployments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): xterm live preview and UX polish
- Pane preview is now a read-only xterm.js terminal with ANSI colors
(capture-pane -e via new ansi=1 param) fed by the live WebSocket;
status chip shows live/connecting/polling and the original 2s REST
polling remains as automatic fallback.
- useTmuxLive hook: survives React StrictMode remounts (unmounted flag
reset on mount), force-closes sockets stuck in CONNECTING after 8s so
retry/fallback always engages, uses import.meta.env.DEV for dev
detection.
- UX: skeleton loading, error state with retry, actionable empty states,
persisted host/expanded-session selection, "/" and Escape shortcuts,
search match highlighting, fresh relative timestamps.
Verified end-to-end in Chrome against a local backend: live chip goes
green and pane output streams in real time over the control-mode bridge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(tmux-monitor): replace control-mode bridge with native PTY attach
The pane preview now embeds the real Terminal component and attaches to
the selected session through the existing terminal WebSocket (new
tmuxAttachSession handshake field in ssh/terminal.ts), making the
preview fully interactive — typing, mouse scrolling and tmux copy-mode
behave exactly like a normal terminal tab. Pane clicks within a session
use the new /focus endpoint (select-window/select-pane) instead of
remounting the terminal.
This removes the entire custom live-streaming stack: the control-mode
WebSocket service on port 30011 (tmux-monitor-live.ts), the control
sequence parser and its tests, the useTmuxLive hook, the nginx
/tmux_monitor/live/ location blocks, and the now-unused live/polling
status chip locale keys.
Verified end-to-end against a dockerized SSH host (Alpine + tmux 3.6):
session tree, interactive preview with ANSI colors, cross-session
search with jump-to-pane, per-pane CPU/RAM metrics, session tags, and
attach-in-new-tab.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): use printable field separator in tmux format strings
The unit separator control character (\x1f) used to delimit fields in
tmux -F output gets sanitized to "_" by tmux itself — tmux replaces
control characters (and, under non-UTF-8 locales, any multibyte
character) in expanded format output. On such hosts every list-sessions
line came back as a single unsplittable field, so the monitor showed
session names like "build_1781066459_1781066459_0" and windows/panes
failed to parse entirely.
Switch SEP to the printable ASCII token "<<TMX>>", which survives every
tmux version and locale. Reproduced and verified against tmux 3.6 on
Alpine (C locale) in a docker container.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): create sessions and split panes from the monitor
- POST /tmux_monitor/:hostId/sessions creates a detached session
(tmux new-session -d), starting the tmux server if needed. Session
names are validated against a conservative charset on both ends
(tmux forbids ":" and "."), and a duplicate name returns 409 with
tmux's own message surfaced in the toast.
- POST /tmux_monitor/:hostId/split splits the window containing a pane
(tmux split-window -h/-v), with the new pane starting in the source
pane's working directory via -c '#{pane_current_path}'.
- UI: a "+" button next to the host selector opens a name popover
(Enter or Create); the pane preview header gains split-right and
split-down buttons. Splits appear instantly in the attached preview
terminal and a silent overview reload updates the tree; new sessions
are auto-expanded.
Command syntax verified against tmux 3.6 in a dockerized SSH host.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): VSCode tmux-manager style tree with window actions
Restyle the session tree after the VSCode tmux manager view:
- Header toolbar: new-session (+) popover and refresh moved next to the
panel title; the host selector row is back to a plain full-width
select.
- Session rows gain hover actions — attach (play) and new window (+) —
revealed with the opacity pattern used by docker's ContainerCard so
they stay keyboard-focusable, with aria-labels on all icon buttons.
- Window rows are collapsible (chevron, "index: name" with a window
icon); panes show "index: command" plus the pane's working directory
in muted text with a full-path tooltip.
- New POST /tmux_monitor/:hostId/windows route runs tmux new-window
against an exact-match ("=name") shell-escaped target; rejects names
containing ":"/"."/newline and returns 404 for missing sessions.
- Pane preview header groups the split buttons apart from close with a
separator.
Reviewed by SA/BA/UX subagent panel; keyboard accessibility and
aria-label findings applied.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): rename/kill sessions, collapse-all, no-flash refresh
- Session rows gain a "…" menu with Rename (dialog, validated name) and
Kill (destructive confirmation). Rename migrates saved tags to the
new name and re-attaches an open preview; kill closes the preview and
drops the session's tags. Both routes use exact-match ("=name")
shell-escaped targets and map tmux's "can't find session" /
"duplicate session" errors to 404/409.
- Header gains a VSCode-style collapse-all / expand-all toggle for the
session tree.
- Refresh UX: manual refresh no longer blanks the tree into skeletons —
the skeleton is reserved for a host's first load; refresh keeps the
tree, spins the icon (header and toolbar) and reports failures with a
toast instead of silently keeping stale data.
tmux command syntax verified against tmux 3.6 in the docker test host.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): single-row sessions, overlay hover actions, tag dialog
UI cleanup after desktop testing showed the tree looked cluttered:
- Sessions are now a single row. The permanently visible tags row (a
mostly empty line with a lone tag icon under every session) is gone:
tags render as inline badges after the name (max 2, then "+n" with a
full-list tooltip) and editing moved to the "…" menu, which opens a
dialog like rename.
- Session metrics merged into the right-hand meta label
("just now · 0% · 7 MB"). Hover actions (attach, new window, …) are
stacked over that label in a grid cell with an opacity cross-fade, so
the row never shifts and the buttons remain keyboard-focusable
(focus-within reveals them).
- Dropdown items no longer wrap: short labels (Rename / Edit tags /
Kill), whitespace-nowrap, min-w-36, align="end".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): kill pane; fix session actions in the desktop app
- Kill pane: hover ✕ on pane rows and a trash button in the preview
header, both behind a confirmation dialog (kill-pane terminates the
pane's process; the last pane closes its window). New
POST /tmux_monitor/:hostId/kill-pane route with pane-id validation.
- Fix attach (▷) doing nothing in the Electron build: window.open of
internal file:// URLs is denied by the window-open handler, so on
desktop the button now attaches inline — expands the session and
selects its active pane in the embedded terminal. Browsers keep the
open-in-new-tab behavior.
- Enlarge the hover-action hit areas (-m-1 p-1) so clicks land on the
buttons instead of toggling the session row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): session hover actions were unclickable
The meta label (time · cpu · mem) fades to opacity-0 on hover, which
turns it into a stacking context painted above its plain-flow sibling —
the invisible label sat on top of the attach/new-window/menu buttons
and swallowed their clicks, so clicking them toggled the session row
instead. Give the actions overlay z-10 and make the label
pointer-events-none.
Reproduced and verified in Chrome with elementFromPoint before/after;
create → rename → kill all work end-to-end through the UI now.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): resizable session tree panel
The tree panel was fixed at w-72; long session names and pane paths had
no room. Its right edge is now a drag handle (200–520px, same pattern
and styling as the AppShell host sidebar), double-click resets to the
default width, and the width persists in localStorage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): split buttons on pane rows
Pane rows' hover actions gain split-right and split-down next to the
kill button, so a pane can be split straight from the tree. splitPane
now takes the target pane id instead of implicitly using the selected
pane; the preview header passes its own pane through.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): repair garbled preview after layout changes
External split / kill-pane / new-window actions can leave the attached
preview client with stale borders (the redraw races the xterm size).
Two-part fix:
- After any layout-changing action the monitor nudges the embedded
terminal (fit + notifyResize + refresh) — the PTY resize forces tmux
to fully redraw the client.
- The preview header gains a re-attach button that remounts the
terminal with a fresh PTY as a one-click rescue when the view is
garbled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): kill window, compact mode, session status tooltip
- Kill window: hover ✕ on window rows behind a confirmation dialog
(kills every pane; the last window ends the session). New
POST /tmux_monitor/:hostId/kill-window route with exact-match target
and 404 mapping.
- Narrow tree panel (<280px) hides the inline "time · cpu · mem" label,
which used to crush long session names into "bui…".
- Hovering a session row now shows a status board tooltip (attached
state, activity, window/pane counts, CPU/RAM/GPU, tags) — the numbers
stay reachable in compact mode and richer in normal mode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): keep preview attached after killing the viewed pane
Killing the selected pane (or its window) dumped the user back to the
"select a pane" empty state even though the session was still alive and
the attached terminal had already focused a sibling pane. After the
kill the monitor now refetches the overview and selects the session's
new active pane, so the preview stays on the same attach connection
(same session key → no remount); the empty state only appears when the
whole session died with the pane.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): require execute permission, audit destructive actions, persist tag mutations
- Mutating endpoints (kill/kill-window/kill-pane/rename/split/focus,
create session/window) now require "execute" host access like docker;
read-only shared hosts could previously kill sessions and spawn shells
- Log kill/rename actions to the audit log (same pattern as host.ts)
- Trigger a DB save after tag updates in rename/kill handlers; the dirty
flag was never set, so a crash could lose or resurrect tags
- Add host_id -> ssh_data FK with ON DELETE CASCADE to tmux_session_tags
(drizzle schema + SQL migration), with a rebuild migration for
pre-release tables created without the FK
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): stop polling and key handling while the tab is hidden, guard stale host responses
- Pass isVisible into TmuxMonitor (like DockerManager/HostMetricsTab);
the global "/"+Escape keydown listener and both SSH polling loops now
pause while the tab is mounted but hidden
- Split the overview polling interval out of the host-change effect so
resuming a tab does not reset state or flash the skeleton
- Ignore overview responses for a host the user has switched away from;
a slow response could overwrite the selected host's tree
- Format SearchResults/SessionTree/TmuxMonitorApp/SidebarTree with
prettier (pr-check was failing on these)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): show an empty state when no SSH hosts exist
With zero hosts the host dropdown opened an empty popover and the
preview area showed the unrelated "select a pane" hint. Disable the
select (its placeholder now says no hosts are available) and show a
central no-hosts message with a pointer to the Host Manager.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): refresh the host list when hosts change elsewhere
The list was fetched once on mount, but the tab stays mounted forever,
so adding the first host in Host Manager left the monitor stuck on
"no hosts" until the tab was closed and reopened. Listen to the
app-wide termix:hosts-changed event (same as AppShell/HostManager),
keep the current selection when still valid, auto-select the first
host when one appears, and clear the session tree when the selected
host is deleted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): keep pane/window actions reachable on a narrow tree
Pane rows kept the split/kill buttons and the "index: command" label at
fixed width, so dragging the panel toward the 200px minimum pushed the
buttons past the right edge; Radix ScrollArea's display:table viewport
wrapper made it worse by stretching every row to the widest pane path,
clipping the window kill button too.
Stack the cpu label and the hover actions in one grid cell (the same
overlay pattern as the session rows), let the command and path labels
truncate, and force the viewport wrapper back to display:block.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): reskin the session status tooltip as a popover card
The base TooltipContent is the inverted one-line chip (bg-foreground,
sharp corners, arrow), so the multi-row session board inherited a light
surface that washed out its muted-foreground labels and clashed with
every other floating card in the app. Restyle this one instance with the
popover surface tokens and hide the chip arrow (important is needed
because Radix sets display on the arrow svg inline).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): disable new-session and search when tmux is missing
On a host without tmux the + button still opened the create popover
(submitting just surfaced the backend TMUX_NOT_INSTALLED toast) and
search silently returned "0 matches". Gate both on overview.available
like the neighboring refresh/expand buttons; the search input carries
the unavailable message as its tooltip.
Verified against a real no-tmux host (alpine+sshd container): both
controls disable on it and stay enabled on a host with tmux.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): restyle floating surfaces to match the square UI
Review feedback on #896: the host selector, the new-session popover,
the session status tooltip and the three kill confirmations rendered
with the stock rounded shadcn look while the rest of the app moved to
square corners, ring borders and blurred dialog overlays. Convert the
kill confirmations from AlertDialog to the already-restyled Dialog and
override the remaining surfaces with rounded-none + ring-border.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* style(host-editor): format the tailscale device options with project prettier
The block arrived unformatted in the dev-2.4.0 merge; committing the
reformat separately keeps the tmux-monitor commits free of unrelated
churn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(tmux-monitor): per-host opt-in flag, disabled by default
Review feedback on #896: the tmux actions appeared on every SSH host's
sidebar entry even though most users do not use tmux. Add an
enable_tmux_monitor column (default off) mirroring the enableDocker
plumbing, expose it as an "Enable Tmux Monitor" toggle in the host
editor's Terminal tab, and gate every per-host tmux surface on it:
the sidebar hover action and copy-URL menu item, the command palette
entry, the monitor's host selector, and the tmux-monitor API itself
(refusing like docker.ts does when the feature is off).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): drop the redundant navbar rail entry
The monitor is per-host opt-in, so the global rail item opened a
host-less view. Hosts with enableTmuxMonitor still expose it via the
host action in the sidebar tree and the command palette.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(tmux-monitor): fill the status popover card width
TooltipContent is an inline-flex container, so the inner block sized
to its natural content width and left a dead gutter on the right of
the w-56 card. Stretch it with w-full so the values align to the edge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: remove unused dropdown, seperate 3 line menu, and fix a few small UI bugs
---------
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix: add i18n for tmux
* feat: continue improving terminal highlighint with more options and more consistency
* feat: add per host configuration of history tracking with overarching admin toggle
* feat: add storage preference to user profile settings (local or DB)
* chore: update release notes
* fix: return user password reset code to logs
* fix: missing tailscale errors and i18n
* fix: sso/browser preference fixes
* fix: remove SSL_ENABLED references
* feat: add filter/sort to credentials list and fixed some JSDoc comments
* chore: update release notes
* chore: update readmes
* chore: update readmes and add docs links
* feat: continue improving SSO system
* fix: host metrics bugs
* fix: session logging api endpoint fail
* chore: make electron.yml auto deliver to macos app store
* chore: fix linting issues
* chore: fix linting issues
* chore: lint, format, and bump version to 2.4.0
* chore: crowdin using incorrect api key name
* chore: sync Crowdin translations for 2.4.0
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: XtraLarge <eMail@WilliWerres.de>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: verybadsoldier <364469+verybadsoldier@users.noreply.github.com>
Co-authored-by: i/o agent <273482092+claw-io@users.noreply.github.com>
Co-authored-by: Félix MARQUET <72651575+BreizhHardware@users.noreply.github.com>
Co-authored-by: Rabindra Kumar Meher <rabindrameher116@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jose Tenggren <kf16el42@students.muetkhp.edu.pk>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Kang <78076796+khengyun@users.noreply.github.com>
* Add documentation in Chinese language (#160)
* Update file naming and structure for mobile support
* Add conditional desktop/mobile rendering
* Mobile terminal
* Fix overwritten i18n (#161)
* Add comprehensive Chinese internationalization support
- Implemented i18n framework with react-i18next for multi-language support
- Added Chinese (zh) and English (en) translation files with comprehensive coverage
- Localized Admin interface, authentication flows, and error messages
- Translated FileManager operations and UI elements
- Updated HomepageAuth component with localized authentication messages
- Localized LeftSidebar navigation and host management
- Added language switcher component (shown after login only)
- Configured default language as English with Chinese as secondary option
- Localized TOTPSetup two-factor authentication interface
- Updated Docker build to include translation files
- Achieved 95%+ UI localization coverage across core components
Co-Authored-By: Claude <noreply@anthropic.com>
* Extend Chinese localization coverage to Host Manager components
- Added comprehensive translations for HostManagerHostViewer component
- Localized all host management UI text including import/export features
- Translated error messages and confirmation dialogs for host operations
- Added translations for HostManagerHostEditor validation messages
- Localized connection details, organization settings, and form labels
- Fixed syntax error in FileManagerOperations component
- Achieved near-complete localization of SSH host management interface
- Updated placeholders and tooltips for better user guidance
Co-Authored-By: Claude <noreply@anthropic.com>
* Complete comprehensive Chinese localization for Termix
- Added full localization support for Tunnel components (connected/disconnected states, retry messages)
- Localized all tunnel status messages and connection errors
- Added translations for port forwarding UI elements
- Verified Server, TopNavbar, and Tab components already have complete i18n support
- Achieved 99%+ localization coverage across entire application
- All core UI components now fully support Chinese and English languages
This completes the comprehensive internationalization effort for the Termix SSH management platform.
Co-Authored-By: Claude <noreply@anthropic.com>
* Localize additional Host Manager components and authentication settings
- Added translations for all authentication options (Password, Key, SSH Private Key)
- Localized form labels in HostManagerHostEditor (Pin Connection, Enable Terminal/Tunnel/FileManager)
- Translated Upload/Update Key button states
- Localized Host Viewer and Add/Edit Host tab labels
- Added Chinese translations for all host management settings
- Fixed duplicate translation keys in JSON files
Co-Authored-By: Claude <noreply@anthropic.com>
* Extend localization coverage to UI components and common strings
- Added comprehensive common translations (online/offline, success/error, etc.)
- Localized status indicator component with all status states
- Updated FileManagerLeftSidebar toast messages for rename/delete operations
- Added translations for UI elements (close, toggle sidebar, etc.)
- Expanded placeholder translations for form inputs
- Added Chinese translations for all new common strings
- Improved consistency across component status messages
Co-Authored-By: Claude <noreply@anthropic.com>
* Complete Chinese localization for remaining UI components
- Add comprehensive Chinese translations for Host Manager component
- Translate all form labels, buttons, and descriptions
- Add translations for SSH configuration warnings and instructions
- Localize tunnel connection settings and port forwarding options
- Localize SSH Tools panel
- Translate key recording functionality
- Add translations for settings and configuration options
- Translate homepage welcome messages and navigation elements
- Add Chinese translations for login success messages
- Localize "Updates & Releases" section title
- Translate sidebar "Host Manager" button
- Fix translation key display issues
- Remove duplicate translation keys in both language files
- Ensure all components properly reference translation keys
- Fix hosts.tunnelConnections key mapping
This completes the full Chinese localization of the Termix application,
achieving near 100% UI translation coverage while maintaining English
as the default language.
* Complete final Chinese localization for Host Manager tunnel configuration
- Add Chinese translations for authentication UI elements
- Translate "Authentication", "Password", and "Key" tab labels
- Localize SSH private key and key password fields
- Add translations for key type selector
- Localize tunnel connection configuration descriptions
- Translate retry attempts and retry interval descriptions
- Add dynamic tunnel forwarding description with port parameters
- Localize endpoint SSH configuration labels
- Fix missing translation keys
- Add "upload" translation for file upload button
- Ensure all FormLabel and FormDescription elements use translation keys
This completes the comprehensive Chinese localization of the entire
Termix application, achieving 100% UI translation coverage.
* Fix PR feedback: Improve Profile section translations and UX
- Fixed password reset translations in Profile section
- Moved language selector from TopNavbar to Profile page
- Added profile.selectPreferredLanguage translation key
- Improved user experience for language preferences
* Apply critical OIDC and notification system fixes while preserving i18n
- Merge OIDC authentication fixes from 3877e90:
* Enhanced JWKS discovery mechanism with multiple backup URLs
* Better support for non-standard OIDC providers (Authentik, etc.)
* Improved error handling for "Failed to get user information"
- Migrate to unified Sonner toast notification system:
* Replace custom success/error state management
* Remove redundant alert state variables
* Consistent user feedback across all components
- Improve code quality and function naming conventions
- PRESERVE all existing i18n functionality and Chinese translations
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix OIDC errors for "Failed to get user information"
* Fix OIDC errors for "Failed to get user information"
* Fix spelling error
* Migrate everything to alert system, update user.ts for OIDC updates.
* Fix OIDC errors for "Failed to get user information"
* Fix OIDC errors for "Failed to get user information"
* Fix spelling error
* Migrate everything to alert system, update user.ts for OIDC updates.
* Update env
* Fix users.ts and schema for override
* Convert web app to Electron desktop application
- Add Electron main process with developer tools support
- Create preload script for secure context bridge
- Configure electron-builder for packaging
- Update Vite config for Electron compatibility (base: './')
- Add environment variable support for API host configuration
- Fix i18n to use relative paths for Electron file protocol
- Restore multi-port backend architecture (8081-8085)
- Add enhanced backend startup script with port checking
- Update package.json with Electron dependencies and build scripts
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Complete Electron desktop application implementation
- Add backend auto-start functionality in main process
- Fix authentication token storage for Electron environment
- Implement localStorage-based token management in Electron
- Add proper Electron environment detection via preload script
- Fix WebSocket connections for terminal functionality
- Resolve font file loading issues in packaged application
- Update API endpoints to work with backend auto-start
- Streamline build scripts with unified electron:package command
- Fix better-sqlite3 native module compatibility issues
- Ensure all services start automatically in production mode
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove releases folder from git and force Desktop UI.
* Improve mobile support with half-baked custom keyboard
* Fix API routing
* Upgrade mobile keyboard with more keys.
* Add cross-platform support and clean up obsolete files
- Add electron-packager scripts for Windows, macOS, and Linux
- Include universal architecture support for macOS
- Add electron:package:all for building all platforms
- Remove obsolete start-backend.sh script (replaced by Electron auto-start)
- Improve ignore patterns to exclude repo-images folder
- Add platform-specific icon configurations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix build system by removing electron-builder dependency
- Remove electron-builder and @electron/rebuild packages to resolve build errors
- Clean up package.json scripts that depend on electron-builder
- Fix merge conflict markers in AdminSettings.tsx and PasswordReset.tsx
- All build commands now work correctly:
- npm run build (frontend + backend)
- npm run build:frontend
- npm run build:backend
- npm run electron:package (using electron-packager)
The build system is now stable and functional without signing requirements.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* Mobile UI improvement
* Electron dev (#185)
* Add comprehensive Chinese internationalization support
- Implemented i18n framework with react-i18next for multi-language support
- Added Chinese (zh) and English (en) translation files with comprehensive coverage
- Localized Admin interface, authentication flows, and error messages
- Translated FileManager operations and UI elements
- Updated HomepageAuth component with localized authentication messages
- Localized LeftSidebar navigation and host management
- Added language switcher component (shown after login only)
- Configured default language as English with Chinese as secondary option
- Localized TOTPSetup two-factor authentication interface
- Updated Docker build to include translation files
- Achieved 95%+ UI localization coverage across core components
Co-Authored-By: Claude <noreply@anthropic.com>
* Extend Chinese localization coverage to Host Manager components
- Added comprehensive translations for HostManagerHostViewer component
- Localized all host management UI text including import/export features
- Translated error messages and confirmation dialogs for host operations
- Added translations for HostManagerHostEditor validation messages
- Localized connection details, organization settings, and form labels
- Fixed syntax error in FileManagerOperations component
- Achieved near-complete localization of SSH host management interface
- Updated placeholders and tooltips for better user guidance
Co-Authored-By: Claude <noreply@anthropic.com>
* Complete comprehensive Chinese localization for Termix
- Added full localization support for Tunnel components (connected/disconnected states, retry messages)
- Localized all tunnel status messages and connection errors
- Added translations for port forwarding UI elements
- Verified Server, TopNavbar, and Tab components already have complete i18n support
- Achieved 99%+ localization coverage across entire application
- All core UI components now fully support Chinese and English languages
This completes the comprehensive internationalization effort for the Termix SSH management platform.
Co-Authored-By: Claude <noreply@anthropic.com>
* Localize additional Host Manager components and authentication settings
- Added translations for all authentication options (Password, Key, SSH Private Key)
- Localized form labels in HostManagerHostEditor (Pin Connection, Enable Terminal/Tunnel/FileManager)
- Translated Upload/Update Key button states
- Localized Host Viewer and Add/Edit Host tab labels
- Added Chinese translations for all host management settings
- Fixed duplicate translation keys in JSON files
Co-Authored-By: Claude <noreply@anthropic.com>
* Extend localization coverage to UI components and common strings
- Added comprehensive common translations (online/offline, success/error, etc.)
- Localized status indicator component with all status states
- Updated FileManagerLeftSidebar toast messages for rename/delete operations
- Added translations for UI elements (close, toggle sidebar, etc.)
- Expanded placeholder translations for form inputs
- Added Chinese translations for all new common strings
- Improved consistency across component status messages
Co-Authored-By: Claude <noreply@anthropic.com>
* Complete Chinese localization for remaining UI components
- Add comprehensive Chinese translations for Host Manager component
- Translate all form labels, buttons, and descriptions
- Add translations for SSH configuration warnings and instructions
- Localize tunnel connection settings and port forwarding options
- Localize SSH Tools panel
- Translate key recording functionality
- Add translations for settings and configuration options
- Translate homepage welcome messages and navigation elements
- Add Chinese translations for login success messages
- Localize "Updates & Releases" section title
- Translate sidebar "Host Manager" button
- Fix translation key display issues
- Remove duplicate translation keys in both language files
- Ensure all components properly reference translation keys
- Fix hosts.tunnelConnections key mapping
This completes the full Chinese localization of the Termix application,
achieving near 100% UI translation coverage while maintaining English
as the default language.
* Complete final Chinese localization for Host Manager tunnel configuration
- Add Chinese translations for authentication UI elements
- Translate "Authentication", "Password", and "Key" tab labels
- Localize SSH private key and key password fields
- Add translations for key type selector
- Localize tunnel connection configuration descriptions
- Translate retry attempts and retry interval descriptions
- Add dynamic tunnel forwarding description with port parameters
- Localize endpoint SSH configuration labels
- Fix missing translation keys
- Add "upload" translation for file upload button
- Ensure all FormLabel and FormDescription elements use translation keys
This completes the comprehensive Chinese localization of the entire
Termix application, achieving 100% UI translation coverage.
* Fix PR feedback: Improve Profile section translations and UX
- Fixed password reset translations in Profile section
- Moved language selector from TopNavbar to Profile page
- Added profile.selectPreferredLanguage translation key
- Improved user experience for language preferences
* Apply critical OIDC and notification system fixes while preserving i18n
- Merge OIDC authentication fixes from 3877e90:
* Enhanced JWKS discovery mechanism with multiple backup URLs
* Better support for non-standard OIDC providers (Authentik, etc.)
* Improved error handling for "Failed to get user information"
- Migrate to unified Sonner toast notification system:
* Replace custom success/error state management
* Remove redundant alert state variables
* Consistent user feedback across all components
- Improve code quality and function naming conventions
- PRESERVE all existing i18n functionality and Chinese translations
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix OIDC errors for "Failed to get user information"
* Fix OIDC errors for "Failed to get user information"
* Fix spelling error
* Migrate everything to alert system, update user.ts for OIDC updates.
* Fix OIDC errors for "Failed to get user information"
* Fix OIDC errors for "Failed to get user information"
* Fix spelling error
* Migrate everything to alert system, update user.ts for OIDC updates.
* Update env
* Fix users.ts and schema for override
* Convert web app to Electron desktop application
- Add Electron main process with developer tools support
- Create preload script for secure context bridge
- Configure electron-builder for packaging
- Update Vite config for Electron compatibility (base: './')
- Add environment variable support for API host configuration
- Fix i18n to use relative paths for Electron file protocol
- Restore multi-port backend architecture (8081-8085)
- Add enhanced backend startup script with port checking
- Update package.json with Electron dependencies and build scripts
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Complete Electron desktop application implementation
- Add backend auto-start functionality in main process
- Fix authentication token storage for Electron environment
- Implement localStorage-based token management in Electron
- Add proper Electron environment detection via preload script
- Fix WebSocket connections for terminal functionality
- Resolve font file loading issues in packaged application
- Update API endpoints to work with backend auto-start
- Streamline build scripts with unified electron:package command
- Fix better-sqlite3 native module compatibility issues
- Ensure all services start automatically in production mode
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Remove releases folder from git and force Desktop UI.
* Improve mobile support with half-baked custom keyboard
* Fix API routing
* Upgrade mobile keyboard with more keys.
* Add cross-platform support and clean up obsolete files
- Add electron-packager scripts for Windows, macOS, and Linux
- Include universal architecture support for macOS
- Add electron:package:all for building all platforms
- Remove obsolete start-backend.sh script (replaced by Electron auto-start)
- Improve ignore patterns to exclude repo-images folder
- Add platform-specific icon configurations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix build system by removing electron-builder dependency
- Remove electron-builder and @electron/rebuild packages to resolve build errors
- Clean up package.json scripts that depend on electron-builder
- Fix merge conflict markers in AdminSettings.tsx and PasswordReset.tsx
- All build commands now work correctly:
- npm run build (frontend + backend)
- npm run build:frontend
- npm run build:backend
- npm run electron:package (using electron-packager)
The build system is now stable and functional without signing requirements.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
Co-authored-by: Karmaa <88517757+LukeGus@users.noreply.github.com>
* Add navigation and hardcoded hosts
* Update mobile sidebar to use API, add auth and tab system to mobile.
* Update sidebar state
* Mobile support (#190)
* Add vibration to keyboard
* Fix keyboard keys
* Fix keyboard keys
* Fix keyboard keys
* Rename files, improve keyboard usability
* Improve keyboard view and fix various issues with it
* Add mobile chinese translation
* Disable OS keyboard from appearing
* Fix fit addon not resizing with "more" on keyboard
* Disable OS keyboard on terminal load
* Merge Luke and Zac
* feat: add export option for ssh hosts (#173) (#187)
* Update issue templates
* feat: add export JSON option for SSH hosts (#173)
---------
Co-authored-by: Karmaa <88517757+LukeGus@users.noreply.github.com>
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* feat(profile): display version number from .env in profile menu (#182)
* feat(profile): display version number from .env in profile menu
* Update version checking process
---------
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* Add pretier
* feat(auth): Add password visibility toggle to auth forms (#166)
* added hide and unhide password button
* Undo admin settings changes
---------
Co-authored-by: LukeGus <bugattiguy527@gmail.com>
* Re-added password input
* Remove encrpytion, improve logging and merge interfaces.
* Improve logging (backend and frontend) and added dedicde OIDC clear
* feat: Added option to paste private key (#203)
* Improve logging frontend/backend, fix host form being reversed.
* Improve logging more, fix credentials sync issues, migrate more to be toasts
* Improve logging more, fix credentials sync issues, migrate more to be toasts
* More error to toast migration
* Remove more inline styles and run npm updates
* Update homepage appearing over everything and terminal incorrect bg
* Improved server stat generation and UI by caching and supporting more platforms
* Update mobile app with the same stat changes and remove rate limiting
* Put user profle in its own tab, add code rabbit support
* Improve code rabbit yaml
* Update chinese translation and fix z indexs causing delay to hide
* Bump vite from 7.1.3 to 7.1.5 (#204)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.3 to 7.1.5.
- [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/v7.1.5/packages/vite)
---
updated-dependencies:
- dependency-name: vite
dependency-version: 7.1.5
dependency-type: direct:development
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Update read me
* Update electron builder and fix mobile terminal background
* Update logo, move translations, update electron building.
* Remove backend from electon, switching to server manager
* Add electron server configurator
* Fix backend builder on Dockerfile
* Fix langauge file for Dockerfile
* Fix architecture issues in Dockerfile
* Fix architecture issues in Dockerfile
* Fix architecture issues in Dockerfile
* Fix backend building for docker image
* Add electron builder
* Fix node starting in entrypoint and remove release from electron build
* Remove double packaing in electron build
* Fix folder nesting for electron gbuilder
* Fix native module docker build (better-sql and bcrypt)
* Fix api routes and missing translations and improve reconnection for terminals
* Update read me for new installation method
* Update CONTRIBUTING.md with color scheme
* Fix terrminal not closing afer 3 tries
* Fix electronm api routing, fikx ssh not connecting, and OIDC redirect errors
* Fix more electron API issues (ssh/oidc), make server manager force API check, and login saving.
* Add electron API routes
* Fix more electron APi routes and issues
* Hide admin settings on electron and fix server manager URl verification
* Hide admin settings on electron and fix server manager URl verification
* Fix admin setting visiblity on electron
* Add links to docs in respective places
* Migrate all getCookies to use main-axios.
* Migrate all isElectron to use main-axios.
* Clean up backend files
* Clean up frontend files and read me translations
* Run prettier
* Fix terminal in web, and update translations and prep for release.
* Update API to work on devs and remove random letter
* Run prettier
* Update read me for release
* Update read me for release
* Fixed delete issue (ready for release)
* Ensure retention days for artifact upload are set
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: starry <115192496+sky22333@users.noreply.github.com>
Co-authored-by: ZacharyZcR <PayasoNorahC@protonmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
Co-authored-by: Shivam Kumar <155747305+maishivamhoo123@users.noreply.github.com>
Co-authored-by: Abhilash Gandhamalla <150357125+AbhilashG12@users.noreply.github.com>
Co-authored-by: jedi04 <78037206+jedi04@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>