sshcp 0.2.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/README.md ADDED
@@ -0,0 +1,306 @@
1
+ # sshcp
2
+
3
+ Easy SSH file copy CLI tool with persistent server selection, bookmarks, rsync sync, and 2-way watch mode.
4
+
5
+ No more typing long `scp user@host:/path/to/file` commands. Just select your server once and copy files with ease.
6
+
7
+ ## Features
8
+
9
+ - **Interactive server selection** - Arrow-key navigation from `~/.ssh/config`
10
+ - **Persistent server selection** - No need to re-select every time
11
+ - **Bookmarks** - Save frequently used remote paths
12
+ - **Rsync sync** - Efficient incremental directory syncing
13
+ - **Watch mode** - 2-way sync with conflict resolution
14
+ - **Beautiful terminal UI** - Rich formatting and progress display
15
+
16
+ ## Installation
17
+
18
+ ### Using npx (easiest)
19
+
20
+ ```bash
21
+ npx sshcp --help
22
+ npx sshcp set
23
+ ```
24
+
25
+ > Requires Python and [uv](https://docs.astral.sh/uv/) or pipx installed.
26
+
27
+ ### Using uv (recommended for Python users)
28
+
29
+ ```bash
30
+ # Run without installing
31
+ uvx sshcp --help
32
+
33
+ # Or install globally
34
+ uv tool install sshcp
35
+ ```
36
+
37
+ ### Using pip
38
+
39
+ ```bash
40
+ pip install sshcp
41
+ ```
42
+
43
+ ### From source
44
+
45
+ ```bash
46
+ git clone https://github.com/shubham8550/sshcp.git
47
+ cd sshcp
48
+ uv sync
49
+ uv run sshcp --help
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ ```bash
55
+ # 1. Select your server (arrow keys to navigate)
56
+ sshcp set
57
+
58
+ # 2. Copy files
59
+ sshcp push ./local_file.txt /remote/path/
60
+ sshcp pull /remote/file.txt ./local/
61
+
62
+ # 3. Use bookmarks for frequent paths
63
+ sshcp bookmark add logs /var/log/myapp
64
+ sshcp pull @logs/error.log ./
65
+
66
+ # 4. Sync directories efficiently
67
+ sshcp sync ./src /var/www/app
68
+
69
+ # 5. Watch and auto-sync changes
70
+ sshcp watch ./project /deploy/app
71
+ ```
72
+
73
+ ## Commands
74
+
75
+ ### Server Selection
76
+
77
+ #### `sshcp set`
78
+
79
+ Interactive server selector with arrow-key navigation:
80
+
81
+ ```
82
+ ╭─ Select SSH Server ─────────────────────────────────╮
83
+ │ Name Host User Port │
84
+ │ prod 192.168.1.100 deploy 22 │
85
+ │ ▸ staging staging.example admin 22 │
86
+ │ dev 10.0.0.50 dev 2222 │
87
+ ╰─────────────────────────────────────────────────────╯
88
+ ↑/↓ navigate • Enter select • q quit
89
+ ```
90
+
91
+ #### `sshcp status`
92
+
93
+ Show currently selected server with details.
94
+
95
+ ---
96
+
97
+ ### File Transfer
98
+
99
+ #### `sshcp push <local> <remote>`
100
+
101
+ Upload a file or directory to the selected server.
102
+
103
+ ```bash
104
+ sshcp push ./myfile.txt /home/user/myfile.txt
105
+ sshcp push ./folder /remote/destination/
106
+ ```
107
+
108
+ #### `sshcp pull <remote> <local>`
109
+
110
+ Download a file or directory from the selected server.
111
+
112
+ ```bash
113
+ sshcp pull /var/log/app.log ./app.log
114
+ sshcp pull /etc/nginx ./nginx_config/
115
+ ```
116
+
117
+ ---
118
+
119
+ ### Bookmarks
120
+
121
+ Save frequently used remote paths for quick access.
122
+
123
+ #### `sshcp bookmark add <name> <path>`
124
+
125
+ Create a new bookmark:
126
+
127
+ ```bash
128
+ sshcp bookmark add logs /var/log/myapp
129
+ sshcp bookmark add config /etc/nginx
130
+ sshcp bookmark add deploy /var/www/production
131
+ ```
132
+
133
+ #### `sshcp bookmark list`
134
+
135
+ Show all saved bookmarks:
136
+
137
+ ```
138
+ ╭─────────────── Saved Bookmarks ───────────────╮
139
+ │ Name Path Usage │
140
+ │ @logs /var/log/myapp @logs/... │
141
+ │ @config /etc/nginx @config/... │
142
+ │ @deploy /var/www/production @deploy/... │
143
+ ╰───────────────────────────────────────────────╯
144
+ ```
145
+
146
+ #### `sshcp bookmark rm <name>`
147
+
148
+ Remove a bookmark.
149
+
150
+ #### Using Bookmarks
151
+
152
+ Use `@bookmark` syntax in any path:
153
+
154
+ ```bash
155
+ sshcp pull @logs/error.log ./ # → /var/log/myapp/error.log
156
+ sshcp push nginx.conf @config/ # → /etc/nginx/
157
+ sshcp sync ./src @deploy # → /var/www/production
158
+ ```
159
+
160
+ ---
161
+
162
+ ### Sync (Rsync)
163
+
164
+ Efficient incremental directory syncing using rsync.
165
+
166
+ #### `sshcp sync <local> <remote> [options]`
167
+
168
+ ```bash
169
+ # Push local to remote (default)
170
+ sshcp sync ./local_folder /remote/folder
171
+
172
+ # Pull remote to local
173
+ sshcp sync ./local_folder /remote/folder --pull
174
+
175
+ # Delete files not in source
176
+ sshcp sync ./src @deploy --delete
177
+
178
+ # Preview changes without executing
179
+ sshcp sync ./src /remote --dry-run
180
+
181
+ # Exclude patterns
182
+ sshcp sync ./project /deploy --exclude "*.log" --exclude "node_modules"
183
+ ```
184
+
185
+ **Options:**
186
+
187
+ | Option | Short | Description |
188
+ |--------|-------|-------------|
189
+ | `--pull` | `-p` | Pull from remote to local (default is push) |
190
+ | `--delete` | `-d` | Delete files not present in source |
191
+ | `--dry-run` | `-n` | Preview changes without executing |
192
+ | `--exclude` | `-e` | Exclude patterns (can be used multiple times) |
193
+
194
+ ---
195
+
196
+ ### Watch Mode (2-Way Sync)
197
+
198
+ Monitor directories and sync changes bidirectionally in real-time.
199
+
200
+ #### `sshcp watch <local> <remote> [options]`
201
+
202
+ ```bash
203
+ # Start watching (prompts on conflict - default)
204
+ sshcp watch ./src /var/www/app
205
+
206
+ # With bookmark
207
+ sshcp watch ./project @deploy
208
+
209
+ # Custom poll interval
210
+ sshcp watch ./src /app --interval 10
211
+
212
+ # Auto-resolve conflicts
213
+ sshcp watch ./src /app --on-conflict local # Always use local
214
+ sshcp watch ./src /app --on-conflict remote # Always use remote
215
+ sshcp watch ./src /app --on-conflict newer # Keep newer version
216
+ sshcp watch ./src /app -c skip # Skip conflicts
217
+ ```
218
+
219
+ **Output:**
220
+
221
+ ```
222
+ ╭─────────── Watch Mode Active ───────────────────────╮
223
+ │ Local: /Users/me/project/src │
224
+ │ Remote: myserver:/var/www/app │
225
+ │ Mode: 2-way sync │
226
+ ╰─────────────────────────────────────────────────────╯
227
+
228
+ Press Ctrl+C to stop
229
+
230
+ [12:34:56] → Updated: src/app.py
231
+ [12:35:10] ← Downloaded: config/settings.json
232
+ [12:35:20] ⚠ CONFLICT: data/cache.db
233
+ ```
234
+
235
+ **Conflict Resolution:**
236
+
237
+ When both local and remote versions of a file change, you'll see:
238
+
239
+ ```
240
+ ╭─────────────── ⚠ Conflict Detected ─────────────────╮
241
+ │ File: data/cache.db │
242
+ │ │
243
+ │ Local Remote │
244
+ │ Modified 2024-01-13 12:35 2024-01-13 12:34 │
245
+ │ Size 1.2 KB 1.3 KB │
246
+ │ │
247
+ │ Local is newer │
248
+ │ │
249
+ │ [L] Keep local [R] Keep remote [S] Skip [Q] Quit │
250
+ ╰─────────────────────────────────────────────────────╯
251
+ ```
252
+
253
+ **Options:**
254
+
255
+ | Option | Short | Description |
256
+ |--------|-------|-------------|
257
+ | `--interval` | `-i` | Seconds between remote polling (default: 5) |
258
+ | `--on-conflict` | `-c` | Conflict resolution mode (default: ask) |
259
+
260
+ **Conflict Resolution Modes:**
261
+
262
+ | Mode | Description |
263
+ |------|-------------|
264
+ | `ask` | Prompt user for each conflict (default) |
265
+ | `local` | Always keep local version |
266
+ | `remote` | Always keep remote version |
267
+ | `newer` | Keep the newer version by timestamp |
268
+ | `skip` | Skip conflicting files |
269
+
270
+ ---
271
+
272
+ ## Configuration
273
+
274
+ ### SSH Config
275
+
276
+ sshcp reads hosts from `~/.ssh/config`:
277
+
278
+ ```
279
+ Host prod
280
+ HostName 192.168.1.100
281
+ User deploy
282
+ IdentityFile ~/.ssh/id_rsa
283
+
284
+ Host staging
285
+ HostName staging.example.com
286
+ User admin
287
+ Port 22
288
+ ```
289
+
290
+ ### sshcp Config
291
+
292
+ Configuration is stored in `~/.config/sshcp/`:
293
+
294
+ - `config.json` - Selected server
295
+ - `bookmarks.json` - Saved bookmarks
296
+
297
+ ## Requirements
298
+
299
+ - Python 3.10+
300
+ - OpenSSH (for `scp` and `ssh` commands)
301
+ - rsync (for sync command)
302
+ - SSH config file with configured hosts
303
+
304
+ ## License
305
+
306
+ MIT
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require('child_process');
4
+
5
+ /**
6
+ * Check if a command exists
7
+ */
8
+ function commandExists(cmd) {
9
+ try {
10
+ const result = spawnSync(process.platform === 'win32' ? 'where' : 'which', [cmd], {
11
+ stdio: 'pipe',
12
+ });
13
+ return result.status === 0;
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ // Check for available Python runners
20
+ const hasUvx = commandExists('uvx');
21
+ const hasPipx = commandExists('pipx');
22
+ const hasSshcp = commandExists('sshcp');
23
+
24
+ if (hasUvx || hasPipx || hasSshcp) {
25
+ // At least one method available
26
+ if (hasUvx) {
27
+ console.log('✓ sshcp will use uvx (fastest)');
28
+ } else if (hasPipx) {
29
+ console.log('✓ sshcp will use pipx');
30
+ } else {
31
+ console.log('✓ sshcp found in PATH');
32
+ }
33
+ } else {
34
+ console.warn(`
35
+ ⚠ sshcp requires Python and a package runner
36
+
37
+ For best experience, install uv:
38
+ curl -LsSf https://astral.sh/uv/install.sh | sh
39
+
40
+ Or install pipx:
41
+ pip install pipx
42
+
43
+ Then run: npx sshcp --help
44
+ `);
45
+ }
46
+
package/bin/sshcp.js ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn, spawnSync } = require('child_process');
4
+ const path = require('path');
5
+
6
+ const PACKAGE_NAME = 'sshcp';
7
+
8
+ /**
9
+ * Check if a command exists
10
+ */
11
+ function commandExists(cmd) {
12
+ try {
13
+ const result = spawnSync(process.platform === 'win32' ? 'where' : 'which', [cmd], {
14
+ stdio: 'pipe',
15
+ });
16
+ return result.status === 0;
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Run sshcp using the best available method
24
+ */
25
+ function runSshcp(args) {
26
+ // Try uvx first (fastest, from uv package manager)
27
+ if (commandExists('uvx')) {
28
+ const proc = spawn('uvx', [PACKAGE_NAME, ...args], {
29
+ stdio: 'inherit',
30
+ });
31
+ proc.on('close', (code) => process.exit(code || 0));
32
+ return;
33
+ }
34
+
35
+ // Try pipx (common Python tool runner)
36
+ if (commandExists('pipx')) {
37
+ const proc = spawn('pipx', ['run', PACKAGE_NAME, ...args], {
38
+ stdio: 'inherit',
39
+ });
40
+ proc.on('close', (code) => process.exit(code || 0));
41
+ return;
42
+ }
43
+
44
+ // Try direct sshcp command (if installed via pip)
45
+ if (commandExists('sshcp')) {
46
+ const proc = spawn('sshcp', args, {
47
+ stdio: 'inherit',
48
+ });
49
+ proc.on('close', (code) => process.exit(code || 0));
50
+ return;
51
+ }
52
+
53
+ // No method available - show installation instructions
54
+ console.error(`
55
+ ╭─────────────────────────────────────────────────────────────────╮
56
+ │ sshcp requires Python and one of: uv, pipx, or pip │
57
+ ╰─────────────────────────────────────────────────────────────────╯
58
+
59
+ Install using one of these methods:
60
+
61
+ 1. Using uv (recommended - fastest):
62
+ curl -LsSf https://astral.sh/uv/install.sh | sh
63
+ uvx sshcp --help
64
+
65
+ 2. Using pipx:
66
+ pip install pipx
67
+ pipx run sshcp --help
68
+
69
+ 3. Using pip:
70
+ pip install sshcp
71
+ sshcp --help
72
+
73
+ Learn more: https://github.com/shubham8550/sshcp
74
+ `);
75
+ process.exit(1);
76
+ }
77
+
78
+ // Get command line arguments (skip node and script path)
79
+ const args = process.argv.slice(2);
80
+
81
+ // Run sshcp with arguments
82
+ runSshcp(args);
83
+
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "sshcp",
3
+ "version": "0.2.0",
4
+ "description": "Easy SSH file copy CLI tool with persistent server selection, bookmarks, rsync sync, and 2-way watch mode",
5
+ "bin": {
6
+ "sshcp": "./bin/sshcp.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node ./bin/check-deps.js"
10
+ },
11
+ "keywords": [
12
+ "ssh",
13
+ "scp",
14
+ "file-transfer",
15
+ "sync",
16
+ "rsync",
17
+ "watch",
18
+ "cli"
19
+ ],
20
+ "author": "shubham8550",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/shubham8550/sshcp.git"
25
+ },
26
+ "homepage": "https://github.com/shubham8550/sshcp#readme",
27
+ "bugs": {
28
+ "url": "https://github.com/shubham8550/sshcp/issues"
29
+ },
30
+ "engines": {
31
+ "node": ">=14"
32
+ },
33
+ "files": [
34
+ "bin/"
35
+ ]
36
+ }
37
+