tabby-ssh-config-groups
v1.0.1
Published
Auto-groups SSH hosts imported from ~/.ssh/config by regex rules.
Readme
tabby-ssh-config-groups
A Tabby plugin that automatically groups SSH hosts
imported from ~/.ssh/config by regex rules, so a frequently-regenerated config
(e.g. produced by an AWS inventory script) always shows up organized in Tabby's
profile list — no manual re-grouping needed.
Example: any host whose alias matches prod-cass (e.g. prod-cass23) is placed into
a group named PROD-CASS instead of Tabby's default flat "Imported from .ssh/config" group.
How it works
Tabby already parses ~/.ssh/config itself (via its built-in OpenSSHImporter,
including Include directives and cache invalidation on file changes) and exposes
every host as a builtin SSH profile. This plugin doesn't re-parse the file or add a
second importer (which would duplicate every host) — instead, at startup it wraps the
existing importer's getProfiles() and rewrites each profile's group field according
to your rules, read fresh from config on every call. Tabby's profile-group tree already
creates a group per distinct group string on builtin profiles, so this is all that's
needed.
Rules are evaluated in order; the first matching rule wins. A rule matches if its
regex tests true against the host's ~/.ssh/config alias (and, optionally, its resolved
HostName/IP). Hosts matching no rule keep Tabby's default group, or a configurable
fallback group.
Only profiles actually imported from ~/.ssh/config are regrouped. Tabby also ships a
separate StaticFileImporter (for a manually-curated ssh-profiles.yaml) registered
under the same importer mechanism — this plugin leaves those profiles' groups untouched.
It also patches two more Tabby core services so your groups consistently sort before Tabby's other builtin profiles (shells, serial ports, unmanaged imports) instead of after them — see "Where grouped hosts show up" below for why both patches are needed.
Where grouped hosts show up
Your regex groups appear in:
- Settings → Profiles & connections
- The New Tab profile dropdown
- The quick Ctrl+Shift+E profile selector
By default, Tabby sorts builtin profiles (shells, serial ports, and ~/.ssh/config
imports alike) alphabetically by group name, and an empty group name (e.g. the "OS
default" shell, which has none) always sorts first — so without this plugin's help, any
regex-grouped host sorts after the ungrouped shell/serial entries everywhere. Two
separate Tabby behaviors need patching to fix this, since they use unrelated ordering
logic:
ProfilesService.getProfiles()is patched to move profiles in one of your configured groups (rule groups, orfallbackGroup) ahead of the rest of the builtin bucket. This is what Settings → Profiles & connections and the New Tab dropdown build their order from.SelectorService.show()is patched to bump the sort weight of options in one of your groups. The Ctrl+Shift+E quick selector ignores the order of the profile list entirely and always re-sorts its own way (by weight, then group name, then profile name), so thegetProfiles()fix alone has no effect there.
Configuration
Edit via Settings → SSH Config Groups in Tabby, or directly in config.yaml:
sshConfigGroup:
enabled: true
matchHostname: false # also test rules against the resolved HostName/IP
fallbackGroup: null # null keeps Tabby's original group for unmatched hosts
rules:
- group: PROD-CASS
match: prod-cass
flags: i
- group: ZABBIX
match: zabbix
flags: iInvalid regexes are skipped safely rather than breaking profile loading.
Install
Development (loads the plugin without installing it permanently — quit Tabby first if it's already running):
git clone <this repo>
cd tabby-ssh-config-groups
npm install --legacy-peer-deps
npm run build
# macOS, if `tabby` isn't on PATH:
TABBY_PLUGINS=$(pwd) /Applications/Tabby.app/Contents/MacOS/Tabby
# if `tabby` is on PATH (Linux/Windows, or a CLI install):
TABBY_PLUGINS=$(pwd) tabby --debugPlugins load once at startup, so after editing/rebuilding you need to quit and relaunch Tabby the same way to pick up changes.
Permanent install: build (npm run build), then copy the whole plugin folder
(including node_modules and dist) into Tabby's plugins directory (Settings →
Plugins → Open Plugins Directory), and restart Tabby normally.
Why there's no tabby-ssh devDependency
Tabby only redirects require() calls for a fixed whitelist of module names (tabby-core,
tabby-settings, tabby-terminal, tabby-local, @angular/*, rxjs, etc.) to its own
already-running singletons — tabby-ssh is not on that list. If a plugin has its own
node_modules/tabby-ssh installed, plain Node module resolution finds that copy before
ever falling back to Tabby's real, already-bootstrapped tabby-ssh, loading a second,
independent instance of the whole module — including its own private bundle of
NgxFilesizeModule (used by the SFTP panel) — which collides with the app's own instance
and throws Error: NgxFilesizeModule does not have a module def (ɵmod property) at startup.
The published tabby-ssh package ships no typings anyway (see src/tabby-ssh.d.ts), so
this plugin never installs it — npm install alone is safe to smoke-test against a real
Tabby.app. Don't add tabby-ssh back to package.json, and if you ever copy node_modules
wholesale for a permanent install, exclude any tabby-ssh directory that might land in
it (the build already inlines every other runtime dependency, e.g. pug-runtime, directly
into dist/index.js).
After either method, check Settings → Profiles & connections or the New Tab dropdown for the regrouped hosts, and Settings → SSH Config Groups for the rule editor. It flags rules with an invalid regex inline, and includes a live test box (with an optional HostName field, shown once "Also match HostName" is on) to check what group a given alias/hostname resolves to.
Development
npm run build # one-off webpack build -> dist/index.js
npm run watch # rebuild on change (still needs a Tabby restart, see above)
npm test # jest unit tests for the grouping logic (src/grouping.spec.ts)The regex-matching core (src/grouping.ts) has no Angular/Tabby runtime dependency and
is covered by table-driven unit tests independent of a running Tabby instance.
Publishing
Tabby's Settings → Plugins → Available tab has no submission/approval process — it
just live-queries the npm registry's search API for packages named tabby-* with the
tabby-plugin keyword (see tabby-plugin-manager's PluginManagerService.listAvailable).
So "publishing to the plugin page" means publishing to npm; nothing else to configure.
This repo already satisfies what that search needs:
- package name starts with
tabby-(tabby-ssh-config-groups) "keywords": ["tabby-plugin"]inpackage.jsonprepublishOnlyrebuildsdist/automatically before every publish
To publish:
npm login # one-time, needs your own npm account
npm publish # rebuilds dist/, then uploads to the npm registryThen in Tabby: Settings → Plugins → Available, search "ssh-config-groups" (Tabby
strips the tabby- prefix when displaying the name), click Get, and restart Tabby.
It usually takes a few minutes (occasionally up to ~30) for npm's search index to pick up
a new package or version after publishing.
This repo being a private GitHub repo doesn't stop npm publish from working — npm
doesn't check git hosting at all, it just uploads the built tarball. But publishing an
unscoped package like this makes it and its contents public on npm regardless of GitHub
visibility (and it must be public for Tabby's marketplace search to find it at all).
package.json's files field is deliberately scoped to dist/**/*.js and
dist/**/*.d.ts only — it excludes dist/index.js.map, which would otherwise embed the
full original TypeScript source (via sourcesContent) in every published version. Run
npm pack --dry-run before publishing to double-check exactly what would ship.
Bumping a release: update version in package.json, then npm publish again — Tabby's
Installed tab shows an "Upgrade" button once npm has indexed the new version.
References
- Tabby — the terminal this plugin extends
- Tabby plugin/theme development guide (HACKING.md)
- Tabby documentation
