tabby-control-tmux 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/index.js +1 -0
- package/package.json +30 -0
- package/typings/index.d.ts +2 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nir Israel Hen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# ControlTmux for Tabby
|
|
2
|
+
|
|
3
|
+
Control tmux on remote hosts from a right-click menu in Tabby SSH tabs.
|
|
4
|
+
|
|
5
|
+
Right-click an SSH tab (title or terminal body) to get a **ControlTmux** section:
|
|
6
|
+
|
|
7
|
+
- **New session** – default name, or *Named…* (types `tmux new-session -s ` for you to complete)
|
|
8
|
+
- **Attach to…** – pick from the sessions running on the host
|
|
9
|
+
- **Kill session** – pick a session to kill
|
|
10
|
+
- **Detach** – detach the current client
|
|
11
|
+
- **Close session** – kill the session you are in
|
|
12
|
+
|
|
13
|
+
Each item has a single-key shortcut shown on the right of the menu.
|
|
14
|
+
|
|
15
|
+
If tmux isn't installed on the host, the menu offers **Install tmux…**, which detects the package
|
|
16
|
+
manager (apt, dnf, yum, apk, pacman, zypper, brew) and runs the install in the tab, using `sudo`
|
|
17
|
+
when you aren't root (you type the password in the terminal).
|
|
18
|
+
|
|
19
|
+
Sessions are listed over a separate exec channel on the same SSH connection, so your terminal is never disturbed.
|
|
20
|
+
It works alongside [tabby-tmux](https://github.com/ruanimal/tabby-tmux) (control mode); the two serve different purposes.
|
|
21
|
+
|
|
22
|
+
## Preview
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
ControlTmux
|
|
26
|
+
├─ New session N ▸ Default name D
|
|
27
|
+
│ Named… N
|
|
28
|
+
├─ Attach to… A ▸ 1 main (attached)
|
|
29
|
+
│ 2 work
|
|
30
|
+
├─ Kill session K ▸ 1 main …
|
|
31
|
+
├─ ───────────
|
|
32
|
+
├─ Detach D
|
|
33
|
+
└─ Close session C
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
Settings → Plugins → search for `tabby-control-tmux`, then restart Tabby.
|
|
39
|
+
|
|
40
|
+
## Build from source
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install --legacy-peer-deps
|
|
44
|
+
npm run build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Copy `package.json` and `dist/` into `<Tabby config dir>/plugins/node_modules/tabby-control-tmux/`
|
|
48
|
+
(macOS: `~/Library/Application Support/tabby/plugins/node_modules/`) and restart Tabby.
|
|
49
|
+
|
|
50
|
+
## Notes
|
|
51
|
+
|
|
52
|
+
- Actions type commands into the active tab, so use them at a shell prompt.
|
|
53
|
+
- Requires `tmux` on the remote host (or use the install item).
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("@angular/core"),require("tabby-core"));else if("function"==typeof define&&define.amd)define(["@angular/core","tabby-core"],t);else{var n="object"==typeof exports?t(require("@angular/core"),require("tabby-core")):t(e["@angular/core"],e["tabby-core"]);for(var s in n)("object"==typeof exports?exports:e)[s]=n[s]}}(global,(e,t)=>(()=>{"use strict";var n={860(t){t.exports=e},650(e){e.exports=t}};const s={};function o(e){const t=s[e];if(void 0!==t)return t.exports;const r=s[e]={exports:{}};return n[e](r,r.exports,o),r.exports}o.d=(e,t)=>{for(var n in t)o.o(t,n)&&!o.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};let r={};o.r(r),o.d(r,{default:()=>f});var a=o(860),l=o(650);const i=[["apt-get","apt-get update && apt-get install -y tmux"],["dnf","dnf install -y tmux"],["yum","yum install -y tmux"],["apk","apk add tmux"],["pacman","pacman -Sy --noconfirm tmux"],["zypper","zypper --non-interactive install tmux"],["brew","brew install tmux"]];let c=class{async exec(e,t){const n=e.sshSession?.ssh;if(!n)return{out:"",ok:!1};const s=await n.activateChannel(await n.openSessionChannel()),o=[],r=new Promise(e=>{s.closed$.subscribe({complete:e,next:e}),s.eof$.subscribe({complete:e,next:e}),setTimeout(e,8e3)});return s.data$.subscribe(e=>o.push(e)),await s.requestExec(t),await r,{out:Buffer.concat(o).toString(),ok:!0}}async isInstalled(e){return"yes"===(await this.exec(e,"command -v tmux >/dev/null 2>&1 && echo yes || echo no")).out.trim()}async listSessions(e){return(await this.exec(e,"tmux ls -F '#{session_name}\t#{session_windows}\t#{session_attached}' 2>/dev/null")).out.split("\n").filter(e=>e.trim()).map(e=>{const[t,n,s]=e.split("\t");return{name:t,windows:+n,attached:+s>0}})}async buildInstallCommand(e){const t=i.map(([e])=>`command -v ${e} >/dev/null 2>&1 && echo ${e}`).join("; "),n=await this.exec(e,t),s=n.out.split("\n")[0]?.trim(),o=i.find(([e])=>e===s);if(!o)return null;const r=o[1];return"brew"===o[0]?r:`if [ "$(id -u)" -eq 0 ]; then ${r}; else sudo sh -c '${r}'; fi`}q(e){return`'${e.replace(/'/g,"'\\''")}'`}newSession(e,t){e.sendInput(`tmux new-session${t?" -s "+this.q(t):""}\r`)}attach(e,t){e.sendInput(`tmux attach-session -t ${this.q(t)}\r`)}newNamedSession(e){e.sendInput("tmux new-session -s ")}closeCurrent(e){e.sendInput("tmux kill-session\r")}detach(e){e.sendInput("tmux detach-client 2>/dev/null\r")}async kill(e,t){await this.exec(e,`tmux kill-session -t ${this.q(t)}`)}install(e,t){e.sendInput(t+"\r")}};c=function(e,t,n,s){var o,r=arguments.length,a=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,s);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(a=(r<3?o(a):r>3?o(t,n,a):o(t,n))||a);return r>3&&a&&Object.defineProperty(t,n,a),a}([(0,a.Injectable)({providedIn:"root"})],c);var u;let d=class extends l.TabContextMenuItemProvider{constructor(e){super(),this.tmux=e,this.weight=-.5}getItems(e){return async function(e,t){const n=t;if(!n.sshSession)return[];try{if(!await e.isInstalled(n)){const t=await e.buildInstallCommand(n);return[{label:"ControlTmux",submenu:[t?{label:"tmux is not installed — Install tmux…",click:()=>e.install(n,t)}:{label:"tmux is not installed (no supported package manager found)",enabled:!1}]}]}const t=await e.listSessions(n),s=e=>t.map((t,n)=>({label:t.name+(t.attached?" (attached)":""),accelerator:n<9?String(n+1):void 0,click:()=>e(t.name)})),o=(e,t,n)=>({label:e,accelerator:t,...n});return[{label:"ControlTmux",submenu:[o("New session","N",{submenu:[o("Default name","D",{click:()=>e.newSession(n)}),o("Named…","N",{click:()=>e.newNamedSession(n)})]}),o("Attach to…","A",{enabled:t.length>0,submenu:s(t=>e.attach(n,t))}),o("Kill session","K",{enabled:t.length>0,submenu:s(t=>e.kill(n,t))}),{type:"separator"},o("Detach","D",{click:()=>e.detach(n)}),o("Close session","C",{click:()=>e.closeCurrent(n)})]}]}catch{return[]}}(this.tmux,e)}};d=function(e,t,n,s){var o,r=arguments.length,a=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,s);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(a=(r<3?o(a):r>3?o(t,n,a):o(t,n))||a);return r>3&&a&&Object.defineProperty(t,n,a),a}([(0,a.Injectable)(),function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}("design:paramtypes",["function"==typeof(u=void 0!==c&&c)?u:Object])],d);let p=class{};p=function(e,t,n,s){var o,r=arguments.length,a=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,s);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(a=(r<3?o(a):r>3?o(t,n,a):o(t,n))||a);return r>3&&a&&Object.defineProperty(t,n,a),a}([(0,a.NgModule)({providers:[{provide:l.TabContextMenuItemProvider,useClass:d,multi:!0}]})],p);const f=p;return r})());
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tabby-control-tmux",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ControlTmux: right-click tmux controls for SSH tabs: new, attach, detach, close, and one-click tmux install",
|
|
5
|
+
"keywords": ["tabby-plugin"],
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"typings": "typings/index.d.ts",
|
|
8
|
+
"files": ["dist", "typings"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "webpack --mode production",
|
|
11
|
+
"watch": "webpack --mode development --watch"
|
|
12
|
+
},
|
|
13
|
+
"author": "Nir Israel Hen",
|
|
14
|
+
"repository": { "type": "git", "url": "git+https://github.com/controlfix87/tabby-control-tmux.git" },
|
|
15
|
+
"homepage": "https://github.com/controlfix87/tabby-control-tmux#readme",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"tabby-core": "*",
|
|
19
|
+
"tabby-ssh": "*",
|
|
20
|
+
"tabby-terminal": "*"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@angular/core": "^15",
|
|
24
|
+
"rxjs": "^7",
|
|
25
|
+
"ts-loader": "^9",
|
|
26
|
+
"typescript": "~4.9",
|
|
27
|
+
"webpack": "^5",
|
|
28
|
+
"webpack-cli": "^5"
|
|
29
|
+
}
|
|
30
|
+
}
|