ssh-agent-workspace 1.0.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 +319 -0
- package/dist/__tests__/SSHManager.test.d.ts +2 -0
- package/dist/__tests__/SSHManager.test.d.ts.map +1 -0
- package/dist/__tests__/SSHManager.test.js +134 -0
- package/dist/__tests__/SSHManager.test.js.map +1 -0
- package/dist/__tests__/SessionManager.test.d.ts +2 -0
- package/dist/__tests__/SessionManager.test.d.ts.map +1 -0
- package/dist/__tests__/SessionManager.test.js +141 -0
- package/dist/__tests__/SessionManager.test.js.map +1 -0
- package/dist/__tests__/StorageManager.test.d.ts +2 -0
- package/dist/__tests__/StorageManager.test.d.ts.map +1 -0
- package/dist/__tests__/StorageManager.test.js +171 -0
- package/dist/__tests__/StorageManager.test.js.map +1 -0
- package/dist/__tests__/ansi.test.d.ts +2 -0
- package/dist/__tests__/ansi.test.d.ts.map +1 -0
- package/dist/__tests__/ansi.test.js +41 -0
- package/dist/__tests__/ansi.test.js.map +1 -0
- package/dist/__tests__/security.test.d.ts +2 -0
- package/dist/__tests__/security.test.d.ts.map +1 -0
- package/dist/__tests__/security.test.js +87 -0
- package/dist/__tests__/security.test.js.map +1 -0
- package/dist/__tests__/validation.test.d.ts +2 -0
- package/dist/__tests__/validation.test.d.ts.map +1 -0
- package/dist/__tests__/validation.test.js +23 -0
- package/dist/__tests__/validation.test.js.map +1 -0
- package/dist/core/HostSecurityManager.d.ts +25 -0
- package/dist/core/HostSecurityManager.d.ts.map +1 -0
- package/dist/core/HostSecurityManager.js +76 -0
- package/dist/core/HostSecurityManager.js.map +1 -0
- package/dist/core/SSHManager.d.ts +48 -0
- package/dist/core/SSHManager.d.ts.map +1 -0
- package/dist/core/SSHManager.js +288 -0
- package/dist/core/SSHManager.js.map +1 -0
- package/dist/core/SessionManager.d.ts +15 -0
- package/dist/core/SessionManager.d.ts.map +1 -0
- package/dist/core/SessionManager.js +96 -0
- package/dist/core/SessionManager.js.map +1 -0
- package/dist/core/StorageManager.d.ts +27 -0
- package/dist/core/StorageManager.d.ts.map +1 -0
- package/dist/core/StorageManager.js +87 -0
- package/dist/core/StorageManager.js.map +1 -0
- package/dist/core/TmuxManager.d.ts +21 -0
- package/dist/core/TmuxManager.d.ts.map +1 -0
- package/dist/core/TmuxManager.js +110 -0
- package/dist/core/TmuxManager.js.map +1 -0
- package/dist/core/ToolConfigManager.d.ts +15 -0
- package/dist/core/ToolConfigManager.d.ts.map +1 -0
- package/dist/core/ToolConfigManager.js +57 -0
- package/dist/core/ToolConfigManager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +169 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +44 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +152 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/backup.d.ts +74 -0
- package/dist/tools/backup.d.ts.map +1 -0
- package/dist/tools/backup.js +152 -0
- package/dist/tools/backup.js.map +1 -0
- package/dist/tools/connect.d.ts +46 -0
- package/dist/tools/connect.d.ts.map +1 -0
- package/dist/tools/connect.js +235 -0
- package/dist/tools/connect.js.map +1 -0
- package/dist/tools/connection_status.d.ts +39 -0
- package/dist/tools/connection_status.d.ts.map +1 -0
- package/dist/tools/connection_status.js +67 -0
- package/dist/tools/connection_status.js.map +1 -0
- package/dist/tools/db_query.d.ts +103 -0
- package/dist/tools/db_query.d.ts.map +1 -0
- package/dist/tools/db_query.js +194 -0
- package/dist/tools/db_query.js.map +1 -0
- package/dist/tools/deploy.d.ts +127 -0
- package/dist/tools/deploy.d.ts.map +1 -0
- package/dist/tools/deploy.js +201 -0
- package/dist/tools/deploy.js.map +1 -0
- package/dist/tools/disconnect.d.ts +46 -0
- package/dist/tools/disconnect.d.ts.map +1 -0
- package/dist/tools/disconnect.js +77 -0
- package/dist/tools/disconnect.js.map +1 -0
- package/dist/tools/exec.d.ts +69 -0
- package/dist/tools/exec.d.ts.map +1 -0
- package/dist/tools/exec.js +188 -0
- package/dist/tools/exec.js.map +1 -0
- package/dist/tools/group_exec.d.ts +80 -0
- package/dist/tools/group_exec.d.ts.map +1 -0
- package/dist/tools/group_exec.js +150 -0
- package/dist/tools/group_exec.js.map +1 -0
- package/dist/tools/health_check.d.ts +38 -0
- package/dist/tools/health_check.d.ts.map +1 -0
- package/dist/tools/health_check.js +161 -0
- package/dist/tools/health_check.js.map +1 -0
- package/dist/tools/host_security.d.ts +52 -0
- package/dist/tools/host_security.d.ts.map +1 -0
- package/dist/tools/host_security.js +127 -0
- package/dist/tools/host_security.js.map +1 -0
- package/dist/tools/index.d.ts +24 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +24 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/interrupt.d.ts +47 -0
- package/dist/tools/interrupt.d.ts.map +1 -0
- package/dist/tools/interrupt.js +77 -0
- package/dist/tools/interrupt.js.map +1 -0
- package/dist/tools/list_hosts.d.ts +15 -0
- package/dist/tools/list_hosts.d.ts.map +1 -0
- package/dist/tools/list_hosts.js +18 -0
- package/dist/tools/list_hosts.js.map +1 -0
- package/dist/tools/list_sessions.d.ts +16 -0
- package/dist/tools/list_sessions.d.ts.map +1 -0
- package/dist/tools/list_sessions.js +20 -0
- package/dist/tools/list_sessions.js.map +1 -0
- package/dist/tools/read_output.d.ts +46 -0
- package/dist/tools/read_output.d.ts.map +1 -0
- package/dist/tools/read_output.js +73 -0
- package/dist/tools/read_output.js.map +1 -0
- package/dist/tools/reconnect_to_tmux.d.ts +53 -0
- package/dist/tools/reconnect_to_tmux.d.ts.map +1 -0
- package/dist/tools/reconnect_to_tmux.js +199 -0
- package/dist/tools/reconnect_to_tmux.js.map +1 -0
- package/dist/tools/send_input.d.ts +45 -0
- package/dist/tools/send_input.d.ts.map +1 -0
- package/dist/tools/send_input.js +83 -0
- package/dist/tools/send_input.js.map +1 -0
- package/dist/tools/sftp_download.d.ts +52 -0
- package/dist/tools/sftp_download.d.ts.map +1 -0
- package/dist/tools/sftp_download.js +90 -0
- package/dist/tools/sftp_download.js.map +1 -0
- package/dist/tools/sftp_list.d.ts +46 -0
- package/dist/tools/sftp_list.d.ts.map +1 -0
- package/dist/tools/sftp_list.js +93 -0
- package/dist/tools/sftp_list.js.map +1 -0
- package/dist/tools/sftp_upload.d.ts +52 -0
- package/dist/tools/sftp_upload.d.ts.map +1 -0
- package/dist/tools/sftp_upload.js +98 -0
- package/dist/tools/sftp_upload.js.map +1 -0
- package/dist/tools/ssh_tunnel.d.ts +116 -0
- package/dist/tools/ssh_tunnel.d.ts.map +1 -0
- package/dist/tools/ssh_tunnel.js +282 -0
- package/dist/tools/ssh_tunnel.js.map +1 -0
- package/dist/tools/sync.d.ts +71 -0
- package/dist/tools/sync.d.ts.map +1 -0
- package/dist/tools/sync.js +310 -0
- package/dist/tools/sync.js.map +1 -0
- package/dist/tools/tail_log.d.ts +61 -0
- package/dist/tools/tail_log.d.ts.map +1 -0
- package/dist/tools/tail_log.js +111 -0
- package/dist/tools/tail_log.js.map +1 -0
- package/dist/tools/tools_config.d.ts +34 -0
- package/dist/tools/tools_config.d.ts.map +1 -0
- package/dist/tools/tools_config.js +98 -0
- package/dist/tools/tools_config.js.map +1 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ansi.d.ts +2 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +7 -0
- package/dist/utils/ansi.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +8 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/security.d.ts +7 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +58 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/ssh.d.ts +4 -0
- package/dist/utils/ssh.d.ts.map +1 -0
- package/dist/utils/ssh.js +29 -0
- package/dist/utils/ssh.js.map +1 -0
- package/dist/utils/sshConfig.d.ts +4 -0
- package/dist/utils/sshConfig.d.ts.map +1 -0
- package/dist/utils/sshConfig.js +85 -0
- package/dist/utils/sshConfig.js.map +1 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +12 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs/SECURITY.md +213 -0
- package/docs/TOOLS.md +425 -0
- package/keygen.bat +325 -0
- package/package.json +48 -0
- package/test_check.bat +9 -0
- package/test_delayed.bat +12 -0
- package/vitest.config.ts +14 -0
package/keygen.bat
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableDelayedExpansion
|
|
3
|
+
title SSH MCP Setup
|
|
4
|
+
color 07
|
|
5
|
+
cls
|
|
6
|
+
|
|
7
|
+
:: ================================================
|
|
8
|
+
:: SSH MCP Setup (Windows)
|
|
9
|
+
:: Generates an ed25519 key and adds an SSH alias
|
|
10
|
+
:: ================================================
|
|
11
|
+
|
|
12
|
+
:: ------------------------------------------------
|
|
13
|
+
:: [0/4] Locate ssh-keygen
|
|
14
|
+
:: ------------------------------------------------
|
|
15
|
+
set "SSHKEYGEN="
|
|
16
|
+
|
|
17
|
+
for %%I in (ssh-keygen.exe) do (
|
|
18
|
+
if not "%%~$PATH:I"=="" set "SSHKEYGEN=%%~$PATH:I"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if not defined SSHKEYGEN (
|
|
22
|
+
if exist "%SystemRoot%\System32\OpenSSH\ssh-keygen.exe" (
|
|
23
|
+
set "SSHKEYGEN=%SystemRoot%\System32\OpenSSH\ssh-keygen.exe"
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if not defined SSHKEYGEN (
|
|
28
|
+
echo.
|
|
29
|
+
echo [X] ssh-keygen not found.
|
|
30
|
+
echo.
|
|
31
|
+
echo Please install one of:
|
|
32
|
+
echo - OpenSSH Client ^(Windows Settings ^> Optional Features^)
|
|
33
|
+
echo - Git for Windows ^(https://git-scm.com^)
|
|
34
|
+
echo.
|
|
35
|
+
pause
|
|
36
|
+
exit /b 1
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
echo [OK] ssh-keygen: !SSHKEYGEN!
|
|
40
|
+
echo.
|
|
41
|
+
|
|
42
|
+
:: ------------------------------------------------
|
|
43
|
+
:: Paths
|
|
44
|
+
:: ------------------------------------------------
|
|
45
|
+
set "SSHDIR=%USERPROFILE%\.ssh"
|
|
46
|
+
set "PRIVKEY=%SSHDIR%\id_ed25519"
|
|
47
|
+
set "PUBKEY=%SSHDIR%\id_ed25519.pub"
|
|
48
|
+
set "CONFIG=%SSHDIR%\config"
|
|
49
|
+
|
|
50
|
+
echo ================================================
|
|
51
|
+
echo SSH MCP Setup ^(Windows^)
|
|
52
|
+
echo ================================================
|
|
53
|
+
echo.
|
|
54
|
+
echo This script will:
|
|
55
|
+
echo 1. Create ~/.ssh folder
|
|
56
|
+
echo 2. Generate ed25519 SSH key ^(if missing^)
|
|
57
|
+
echo 3. Add host alias to SSH config
|
|
58
|
+
echo.
|
|
59
|
+
echo Press Ctrl+C to cancel, or
|
|
60
|
+
pause
|
|
61
|
+
echo.
|
|
62
|
+
echo ------------------------------------------------
|
|
63
|
+
|
|
64
|
+
:: ------------------------------------------------
|
|
65
|
+
:: Prompt: Alias
|
|
66
|
+
:: ------------------------------------------------
|
|
67
|
+
:ask_alias
|
|
68
|
+
set "ALIAS="
|
|
69
|
+
set /p "ALIAS= Alias (e.g. prod) : "
|
|
70
|
+
|
|
71
|
+
:: Trim leading/trailing spaces via a for loop trick
|
|
72
|
+
for /f "tokens=* delims= " %%A in ("!ALIAS!") do set "ALIAS=%%A"
|
|
73
|
+
|
|
74
|
+
if "!ALIAS!"=="" (
|
|
75
|
+
echo [!] Alias cannot be empty.
|
|
76
|
+
goto :ask_alias
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
:: Reject spaces inside alias
|
|
80
|
+
echo !ALIAS!| find " " >nul 2>nul && (
|
|
81
|
+
echo [!] Alias cannot contain spaces.
|
|
82
|
+
goto :ask_alias
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
:: Reject characters that break SSH config or findstr: * ? \ / " < > |
|
|
86
|
+
echo !ALIAS!| findstr /r "[*?/\\\""<>|]" >nul 2>nul && (
|
|
87
|
+
echo [!] Alias contains invalid characters.
|
|
88
|
+
goto :ask_alias
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
:: ------------------------------------------------
|
|
92
|
+
:: Prompt: Host
|
|
93
|
+
:: ------------------------------------------------
|
|
94
|
+
:ask_host
|
|
95
|
+
set "HOST="
|
|
96
|
+
set /p "HOST= IP / Hostname : "
|
|
97
|
+
for /f "tokens=* delims= " %%A in ("!HOST!") do set "HOST=%%A"
|
|
98
|
+
|
|
99
|
+
if "!HOST!"=="" (
|
|
100
|
+
echo [!] Host cannot be empty.
|
|
101
|
+
goto :ask_host
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
echo !HOST!| find " " >nul 2>nul && (
|
|
105
|
+
echo [!] Hostname cannot contain spaces.
|
|
106
|
+
goto :ask_host
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
:: ------------------------------------------------
|
|
110
|
+
:: Prompt: User
|
|
111
|
+
:: ------------------------------------------------
|
|
112
|
+
:ask_user
|
|
113
|
+
set "SSHUSER="
|
|
114
|
+
set /p "SSHUSER= SSH Username : "
|
|
115
|
+
for /f "tokens=* delims= " %%A in ("!SSHUSER!") do set "SSHUSER=%%A"
|
|
116
|
+
|
|
117
|
+
if "!SSHUSER!"=="" (
|
|
118
|
+
echo [!] Username cannot be empty.
|
|
119
|
+
goto :ask_user
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
echo !SSHUSER!| find " " >nul 2>nul && (
|
|
123
|
+
echo [!] Username cannot contain spaces.
|
|
124
|
+
goto :ask_user
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
:: ------------------------------------------------
|
|
128
|
+
:: Prompt: Port (validated via PowerShell)
|
|
129
|
+
:: ------------------------------------------------
|
|
130
|
+
:ask_port
|
|
131
|
+
set "PORT="
|
|
132
|
+
set /p "PORT= SSH Port [default 22] : "
|
|
133
|
+
for /f "tokens=* delims= " %%A in ("!PORT!") do set "PORT=%%A"
|
|
134
|
+
|
|
135
|
+
if "!PORT!"=="" set "PORT=22"
|
|
136
|
+
|
|
137
|
+
:: Use PowerShell to safely validate numeric range (avoids batch integer parsing bugs)
|
|
138
|
+
powershell -NoProfile -Command ^
|
|
139
|
+
"param([string]$p) $n=0; if(-not[int]::TryParse($p,[ref]$n)-or $n -lt 1 -or $n -gt 65535){exit 1}" ^
|
|
140
|
+
-p "!PORT!" >nul 2>nul
|
|
141
|
+
|
|
142
|
+
if errorlevel 1 (
|
|
143
|
+
echo [!] Invalid port. Must be a number between 1 and 65535. Using 22.
|
|
144
|
+
set "PORT=22"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
echo.
|
|
148
|
+
|
|
149
|
+
:: ------------------------------------------------
|
|
150
|
+
:: [1/4] Prepare .ssh folder
|
|
151
|
+
:: ------------------------------------------------
|
|
152
|
+
echo [1/4] Preparing .ssh folder ...
|
|
153
|
+
if not exist "%SSHDIR%\" (
|
|
154
|
+
mkdir "%SSHDIR%"
|
|
155
|
+
if errorlevel 1 (
|
|
156
|
+
echo [X] Failed to create: %SSHDIR%
|
|
157
|
+
pause & exit /b 1
|
|
158
|
+
)
|
|
159
|
+
echo [+] Created: %SSHDIR%
|
|
160
|
+
) else (
|
|
161
|
+
echo [=] Already exists: %SSHDIR%
|
|
162
|
+
)
|
|
163
|
+
echo.
|
|
164
|
+
|
|
165
|
+
:: ------------------------------------------------
|
|
166
|
+
:: [2/4] Generate SSH key pair
|
|
167
|
+
:: ------------------------------------------------
|
|
168
|
+
echo [2/4] Generating SSH key pair ...
|
|
169
|
+
if not exist "%PRIVKEY%" (
|
|
170
|
+
if exist "%PUBKEY%" (
|
|
171
|
+
echo [W] Public key found but private key is missing.
|
|
172
|
+
echo Delete %PUBKEY% manually and re-run this script.
|
|
173
|
+
pause & exit /b 1
|
|
174
|
+
)
|
|
175
|
+
"!SSHKEYGEN!" -t ed25519 -f "%PRIVKEY%" -N "" -C "mcp-!ALIAS!"
|
|
176
|
+
if errorlevel 1 (
|
|
177
|
+
echo [X] ssh-keygen failed.
|
|
178
|
+
pause & exit /b 1
|
|
179
|
+
)
|
|
180
|
+
echo [+] Key saved: %PRIVKEY%
|
|
181
|
+
) else (
|
|
182
|
+
if not exist "%PUBKEY%" (
|
|
183
|
+
echo [W] Private key found but public key is missing.
|
|
184
|
+
echo Delete %PRIVKEY% manually and re-run this script.
|
|
185
|
+
pause & exit /b 1
|
|
186
|
+
)
|
|
187
|
+
echo [=] Key already exists, skipping.
|
|
188
|
+
echo %PRIVKEY%
|
|
189
|
+
)
|
|
190
|
+
echo.
|
|
191
|
+
|
|
192
|
+
:: ------------------------------------------------
|
|
193
|
+
:: [3/4] Update SSH config
|
|
194
|
+
:: ------------------------------------------------
|
|
195
|
+
echo [3/4] Updating SSH config ...
|
|
196
|
+
|
|
197
|
+
if not exist "%CONFIG%" (
|
|
198
|
+
type nul > "%CONFIG%"
|
|
199
|
+
echo [+] Config file created: %CONFIG%
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
:: Use word-boundary match: "^Host <alias>$" to avoid partial matches
|
|
203
|
+
:: (e.g. alias "prod" must not match "production")
|
|
204
|
+
findstr /r /c:"^Host !ALIAS!$" "%CONFIG%" >nul 2>nul
|
|
205
|
+
if not errorlevel 1 (
|
|
206
|
+
echo [=] Alias [!ALIAS!] already exists in config, skipped.
|
|
207
|
+
goto :config_done
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
:: Write each line individually — parenthesised blocks are unreliable
|
|
211
|
+
:: with delayed expansion enabled on some Windows versions.
|
|
212
|
+
:: NOTE: no space before ">>" so trailing spaces are not written to the file.
|
|
213
|
+
>>"%CONFIG%" echo.
|
|
214
|
+
>>"%CONFIG%" echo Host !ALIAS!
|
|
215
|
+
>>"%CONFIG%" echo HostName !HOST!
|
|
216
|
+
>>"%CONFIG%" echo User !SSHUSER!
|
|
217
|
+
>>"%CONFIG%" echo Port !PORT!
|
|
218
|
+
>>"%CONFIG%" echo IdentityFile !PRIVKEY!
|
|
219
|
+
>>"%CONFIG%" echo ServerAliveInterval 60
|
|
220
|
+
>>"%CONFIG%" echo ServerAliveCountMax 3
|
|
221
|
+
>>"%CONFIG%" echo StrictHostKeyChecking accept-new
|
|
222
|
+
|
|
223
|
+
if errorlevel 1 (
|
|
224
|
+
echo [X] Failed to write to: %CONFIG%
|
|
225
|
+
pause & exit /b 1
|
|
226
|
+
)
|
|
227
|
+
echo [+] Alias [!ALIAS!] added to config.
|
|
228
|
+
|
|
229
|
+
:config_done
|
|
230
|
+
echo.
|
|
231
|
+
|
|
232
|
+
:: ------------------------------------------------
|
|
233
|
+
:: [4/4] Key permission hint
|
|
234
|
+
:: ------------------------------------------------
|
|
235
|
+
echo [4/4] Key permissions ...
|
|
236
|
+
echo [i] Windows OpenSSH enforces strict ACLs.
|
|
237
|
+
echo If ssh fails with "Bad permissions", run:
|
|
238
|
+
echo.
|
|
239
|
+
echo icacls "%PRIVKEY%" /inheritance:r /grant:r "%USERNAME%:R"
|
|
240
|
+
echo.
|
|
241
|
+
|
|
242
|
+
:: ------------------------------------------------
|
|
243
|
+
:: Summary
|
|
244
|
+
:: ------------------------------------------------
|
|
245
|
+
echo ================================================
|
|
246
|
+
echo Summary
|
|
247
|
+
echo ================================================
|
|
248
|
+
echo.
|
|
249
|
+
echo Alias : !ALIAS!
|
|
250
|
+
echo Host : !HOST!
|
|
251
|
+
echo User : !SSHUSER!
|
|
252
|
+
echo Port : !PORT!
|
|
253
|
+
echo Private Key : !PRIVKEY!
|
|
254
|
+
echo Config : !CONFIG!
|
|
255
|
+
echo.
|
|
256
|
+
echo Test your connection:
|
|
257
|
+
echo ssh !ALIAS!
|
|
258
|
+
echo.
|
|
259
|
+
|
|
260
|
+
:: ------------------------------------------------
|
|
261
|
+
:: Read public key — write to temp file first
|
|
262
|
+
:: so we never echo a raw key string directly
|
|
263
|
+
:: (avoids issues with = signs and long lines)
|
|
264
|
+
:: ------------------------------------------------
|
|
265
|
+
set "PUBKEYLINE="
|
|
266
|
+
if exist "%PUBKEY%" (
|
|
267
|
+
for /f "usebackq delims=" %%i in ("%PUBKEY%") do (
|
|
268
|
+
if "!PUBKEYLINE!"=="" set "PUBKEYLINE=%%i"
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
if "!PUBKEYLINE!"=="" (
|
|
273
|
+
echo [X] Could not read public key: %PUBKEY%
|
|
274
|
+
echo [i] Copy the key manually to your server.
|
|
275
|
+
) else (
|
|
276
|
+
echo ================================================
|
|
277
|
+
echo Add your public key to the server
|
|
278
|
+
echo ================================================
|
|
279
|
+
echo.
|
|
280
|
+
echo Option A — paste this command on the server:
|
|
281
|
+
echo.
|
|
282
|
+
|
|
283
|
+
:: Write the server command to a temp file to avoid echo mangling long keys
|
|
284
|
+
set "TMPFILE=%TEMP%\mcp_pubkey_cmd.txt"
|
|
285
|
+
(
|
|
286
|
+
echo mkdir -p ~/.ssh ^&^& echo !PUBKEYLINE! ^>^> ~/.ssh/authorized_keys ^&^& chmod 700 ~/.ssh ^&^& chmod 600 ~/.ssh/authorized_keys
|
|
287
|
+
) > "!TMPFILE!"
|
|
288
|
+
type "!TMPFILE!"
|
|
289
|
+
del "!TMPFILE!" >nul 2>nul
|
|
290
|
+
|
|
291
|
+
echo.
|
|
292
|
+
echo Option B — if ssh-copy-id is available ^(e.g. via Git Bash^):
|
|
293
|
+
echo.
|
|
294
|
+
echo ssh-copy-id -i "%PUBKEY%" !SSHUSER!@!HOST! -p !PORT!
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
echo.
|
|
298
|
+
|
|
299
|
+
:: ------------------------------------------------
|
|
300
|
+
:: Optional: Passwordless sudo
|
|
301
|
+
:: ------------------------------------------------
|
|
302
|
+
echo ================================================
|
|
303
|
+
echo OPTIONAL: Passwordless sudo for AI agent
|
|
304
|
+
echo ================================================
|
|
305
|
+
echo.
|
|
306
|
+
echo Allows the agent to run sudo without a password prompt.
|
|
307
|
+
echo.
|
|
308
|
+
powershell -NoProfile -Command "Write-Host ' WARNING: USE AT YOUR OWN RISK!' -ForegroundColor Red"
|
|
309
|
+
powershell -NoProfile -Command "Write-Host ' The AI agent can execute privileged commands.' -ForegroundColor Red"
|
|
310
|
+
powershell -NoProfile -Command "Write-Host ' Recommended only for local/dev/homelab servers.' -ForegroundColor Yellow"
|
|
311
|
+
echo.
|
|
312
|
+
echo [FULL ACCESS — easiest, least safe]
|
|
313
|
+
echo sudo bash -c "echo '!SSHUSER! ALL=(ALL) NOPASSWD: ALL' ^> /etc/sudoers.d/99-mcp-!SSHUSER!"
|
|
314
|
+
echo.
|
|
315
|
+
echo [LIMITED ACCESS — safer, restrict to specific commands]
|
|
316
|
+
echo sudo bash -c "echo '!SSHUSER! ALL=(ALL) NOPASSWD: /usr/bin/systemctl, /usr/bin/apt' ^> /etc/sudoers.d/99-mcp-!SSHUSER!"
|
|
317
|
+
echo.
|
|
318
|
+
echo Validate after applying:
|
|
319
|
+
echo sudo visudo -cf /etc/sudoers.d/99-mcp-!SSHUSER!
|
|
320
|
+
echo.
|
|
321
|
+
echo ================================================
|
|
322
|
+
echo.
|
|
323
|
+
|
|
324
|
+
pause
|
|
325
|
+
endlocal
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ssh-agent-workspace",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Persistent SSH workspaces for AI agents. Stateful tmux-backed sessions that survive reconnects, restarts, and network drops — with runtime security and tool configuration.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"ssh-agent-workspace": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:watch": "vitest"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"ssh",
|
|
20
|
+
"tmux",
|
|
21
|
+
"stateful",
|
|
22
|
+
"workspace",
|
|
23
|
+
"persistent",
|
|
24
|
+
"opencode",
|
|
25
|
+
"claude",
|
|
26
|
+
"ai-agent"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
32
|
+
"pino": "^9.5.0",
|
|
33
|
+
"ssh-config": "^5.0.0",
|
|
34
|
+
"ssh2": "^1.16.0",
|
|
35
|
+
"uuid": "^11.0.0",
|
|
36
|
+
"zod": "^3.23.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.0.0",
|
|
40
|
+
"@types/ssh2": "^1.15.0",
|
|
41
|
+
"@types/uuid": "^10.0.0",
|
|
42
|
+
"typescript": "^5.6.0",
|
|
43
|
+
"vitest": "^4.1.7"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/test_check.bat
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableDelayedExpansion
|
|
3
|
+
set "SSHKEYGEN="
|
|
4
|
+
where ssh-keygen >nul 2>&1
|
|
5
|
+
echo errorlevel after where: %errorlevel%
|
|
6
|
+
if not errorlevel 1 set "SSHKEYGEN=ssh-keygen"
|
|
7
|
+
echo SSHKEYGEN after where check: [!SSHKEYGEN!]
|
|
8
|
+
echo defined check:
|
|
9
|
+
if defined SSHKEYGEN (echo YES) else (echo NO)
|
package/test_delayed.bat
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal EnableDelayedExpansion
|
|
3
|
+
set BAR=worked
|
|
4
|
+
echo NORMAL: [%BAR%]
|
|
5
|
+
echo DELAYED: [!BAR!]
|
|
6
|
+
echo WHERE:
|
|
7
|
+
where ssh-keygen >nul 2>&1 && echo FOUND || echo NOTFOUND
|
|
8
|
+
set SSHKEYGEN=
|
|
9
|
+
where ssh-keygen >nul 2>&1 && set "SSHKEYGEN=ssh-keygen"
|
|
10
|
+
if defined SSHKEYGEN (echo SSHKEYGEN defined: [!SSHKEYGEN!]) else (echo SSHKEYGEN NOT defined)
|
|
11
|
+
echo.
|
|
12
|
+
if exist "%SYSTEMROOT%\System32\OpenSSH\ssh-keygen.exe" (echo FILE EXISTS) else (echo FILE NOT EXISTS)
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: ['src/**/*.test.ts'],
|
|
8
|
+
coverage: {
|
|
9
|
+
provider: 'v8',
|
|
10
|
+
include: ['src/**/*.ts'],
|
|
11
|
+
exclude: ['src/**/*.test.ts', 'src/index.ts', 'src/server.ts'],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|