@burdenoff/vibe-plugin-ssh 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 +70 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/port-forward.d.ts +3 -0
- package/dist/routes/port-forward.d.ts.map +1 -0
- package/dist/routes/port-forward.js +202 -0
- package/dist/routes/port-forward.js.map +1 -0
- package/dist/routes/ssh.d.ts +3 -0
- package/dist/routes/ssh.d.ts.map +1 -0
- package/dist/routes/ssh.js +184 -0
- package/dist/routes/ssh.js.map +1 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @burdenoff/vibe-plugin-ssh
|
|
2
|
+
|
|
3
|
+
SSH connections & port forwarding plugin for [VibeControls Agent](https://www.npmjs.com/package/@burdenoff/vibe-agent).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
vibe plugin install @burdenoff/vibe-plugin-ssh
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or install globally alongside the agent:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @burdenoff/vibe-plugin-ssh
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then register it:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
vibe plugin list # verify it shows up
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **SSH Connections** — Save, test, and manage SSH connection configs
|
|
26
|
+
- **Remote Execution** — Execute commands on remote servers via SSH
|
|
27
|
+
- **Port Forwarding** — Create and manage SSH port forwards (local → remote)
|
|
28
|
+
- **Real-time Output** — SSH command output streamed via Socket.IO events
|
|
29
|
+
|
|
30
|
+
## API Routes
|
|
31
|
+
|
|
32
|
+
Once installed, the plugin registers these routes on the agent:
|
|
33
|
+
|
|
34
|
+
| Method | Path | Description |
|
|
35
|
+
|--------|------|-------------|
|
|
36
|
+
| GET | `/api/ssh/connections` | List all SSH connections |
|
|
37
|
+
| POST | `/api/ssh/connections` | Create a new SSH connection |
|
|
38
|
+
| POST | `/api/ssh/execute` | Execute a remote command |
|
|
39
|
+
| POST | `/api/ssh/test/:id` | Test an SSH connection |
|
|
40
|
+
| DELETE | `/api/ssh/connections/:id` | Delete a connection |
|
|
41
|
+
| GET | `/api/port-forward/` | List all port forwards |
|
|
42
|
+
| POST | `/api/port-forward/` | Create a port forward |
|
|
43
|
+
| POST | `/api/port-forward/:id/start` | Start forwarding |
|
|
44
|
+
| POST | `/api/port-forward/:id/stop` | Stop forwarding |
|
|
45
|
+
| DELETE | `/api/port-forward/:id` | Delete a forward |
|
|
46
|
+
|
|
47
|
+
## CLI Commands
|
|
48
|
+
|
|
49
|
+
SSH and port forward CLI commands are built into the `vibe` CLI:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
vibe ssh list # List saved connections
|
|
53
|
+
vibe ssh add --name my-server ... # Add a connection
|
|
54
|
+
vibe ssh test -i <id> # Test connectivity
|
|
55
|
+
vibe ssh exec -i <id> -c "uptime" # Run remote command
|
|
56
|
+
|
|
57
|
+
vibe forward list # List port forwards
|
|
58
|
+
vibe forward create --local 5432 --remote-host db --remote-port 5432 --server my-server
|
|
59
|
+
vibe forward start -i <id> # Start forwarding
|
|
60
|
+
vibe forward stop -i <id> # Stop forwarding
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Requirements
|
|
64
|
+
|
|
65
|
+
- VibeControls Agent >= 1.1.0
|
|
66
|
+
- Node.js >= 18.0.0
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
Proprietary — Copyright Burdenoff Consultancy Services Pvt. Ltd.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
/**
|
|
4
|
+
* @burdenoff/vibe-plugin-ssh
|
|
5
|
+
*
|
|
6
|
+
* SSH connections, remote command execution, and port forwarding plugin
|
|
7
|
+
* for the VibeControls Agent. This plugin registers:
|
|
8
|
+
*
|
|
9
|
+
* - Fastify routes: /api/ssh/*, /api/port-forward/*
|
|
10
|
+
* - CLI commands: vibe ssh list|add|remove|test|exec
|
|
11
|
+
* vibe forward list|create|start|stop|delete
|
|
12
|
+
*
|
|
13
|
+
* Install: vibe plugin install @burdenoff/vibe-plugin-ssh
|
|
14
|
+
*/
|
|
15
|
+
export interface VibePlugin {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
onCliSetup?: (program: Command) => void | Promise<void>;
|
|
20
|
+
onServerStart?: (app: FastifyInstance) => void | Promise<void>;
|
|
21
|
+
onServerStop?: (app: FastifyInstance) => void | Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare const vibePlugin: VibePlugin;
|
|
24
|
+
export default vibePlugin;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;;;;;GAWG;AAGH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAED,eAAO,MAAM,UAAU,EAAE,UAsBxB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const vibePlugin = {
|
|
2
|
+
name: "ssh",
|
|
3
|
+
version: "1.0.0",
|
|
4
|
+
description: "SSH connections & port forwarding for VibeControls Agent",
|
|
5
|
+
async onServerStart(app) {
|
|
6
|
+
// Dynamically import ssh2 — this is the whole point of the plugin:
|
|
7
|
+
// ssh2 (with native cpu-features) is only loaded when the plugin is installed.
|
|
8
|
+
const { sshRoutes } = await import("./routes/ssh.js");
|
|
9
|
+
const { portForwardRoutes } = await import("./routes/port-forward.js");
|
|
10
|
+
await app.register(sshRoutes, { prefix: "/api/ssh" });
|
|
11
|
+
await app.register(portForwardRoutes, { prefix: "/api/port-forward" });
|
|
12
|
+
console.log(" 🔌 Plugin 'ssh' registered routes: /api/ssh, /api/port-forward");
|
|
13
|
+
},
|
|
14
|
+
onCliSetup(program) {
|
|
15
|
+
// SSH CLI commands are registered by the agent's built-in CLI for now.
|
|
16
|
+
// In a future version, the CLI commands will also move into this plugin.
|
|
17
|
+
// For now, the plugin only contributes server-side routes.
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export default vibePlugin;
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,MAAM,CAAC,MAAM,UAAU,GAAe;IACpC,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,OAAO;IAChB,WAAW,EAAE,0DAA0D;IAEvE,KAAK,CAAC,aAAa,CAAC,GAAoB;QACtC,mEAAmE;QACnE,+EAA+E;QAC/E,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACtD,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QAEvE,MAAM,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QACtD,MAAM,GAAG,CAAC,QAAQ,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAEvE,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAClF,CAAC;IAED,UAAU,CAAC,OAAgB;QACzB,uEAAuE;QACvE,yEAAyE;QACzE,2DAA2D;IAC7D,CAAC;CACF,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-forward.d.ts","sourceRoot":"","sources":["../../src/routes/port-forward.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAgB7C,eAAO,MAAM,iBAAiB,EAAE,kBAuP/B,CAAC"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { Client } from "ssh2";
|
|
3
|
+
import { createServer } from "net";
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
// Store active connections and servers
|
|
6
|
+
const activeConnections = new Map();
|
|
7
|
+
export const portForwardRoutes = async (fastify) => {
|
|
8
|
+
// Get all port forwards
|
|
9
|
+
fastify.get("/", async (_request, _reply) => {
|
|
10
|
+
const portForwards = fastify.db.getAllPortForwards();
|
|
11
|
+
return { portForwards };
|
|
12
|
+
});
|
|
13
|
+
// Create new port forward
|
|
14
|
+
fastify.post("/", async (request, reply) => {
|
|
15
|
+
const { localPort, remoteHost, remotePort, connectionId } = request.body;
|
|
16
|
+
try {
|
|
17
|
+
const existing = fastify.db
|
|
18
|
+
.getAllPortForwards()
|
|
19
|
+
.find((pf) => pf.localPort === localPort && pf.status === "active");
|
|
20
|
+
if (existing) {
|
|
21
|
+
return reply.code(409).send({ error: "Local port is already in use" });
|
|
22
|
+
}
|
|
23
|
+
const connectionConfig = fastify.db.getSSHConnection(connectionId);
|
|
24
|
+
if (!connectionConfig) {
|
|
25
|
+
return reply.code(404).send({ error: "SSH connection not found" });
|
|
26
|
+
}
|
|
27
|
+
const portForward = fastify.db.createPortForward({
|
|
28
|
+
id: crypto.randomUUID(),
|
|
29
|
+
localPort,
|
|
30
|
+
remoteHost,
|
|
31
|
+
remotePort,
|
|
32
|
+
serverName: connectionConfig.serverName,
|
|
33
|
+
connectionId,
|
|
34
|
+
status: "inactive",
|
|
35
|
+
});
|
|
36
|
+
return { portForward };
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return reply.code(500).send({
|
|
40
|
+
error: "Failed to create port forward",
|
|
41
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// Start port forwarding
|
|
46
|
+
fastify.post("/:id/start", async (request, reply) => {
|
|
47
|
+
const { id } = request.params;
|
|
48
|
+
try {
|
|
49
|
+
const portForward = fastify.db.getPortForward(id);
|
|
50
|
+
if (!portForward) {
|
|
51
|
+
return reply.code(404).send({ error: "Port forward not found" });
|
|
52
|
+
}
|
|
53
|
+
if (portForward.status === "active") {
|
|
54
|
+
return reply
|
|
55
|
+
.code(400)
|
|
56
|
+
.send({ error: "Port forward is already active" });
|
|
57
|
+
}
|
|
58
|
+
const connectionConfig = portForward.connectionId
|
|
59
|
+
? fastify.db.getSSHConnection(portForward.connectionId)
|
|
60
|
+
: fastify.db.getSSHConnectionByName(portForward.serverName);
|
|
61
|
+
if (!connectionConfig) {
|
|
62
|
+
return reply.code(404).send({ error: "SSH connection not found" });
|
|
63
|
+
}
|
|
64
|
+
const sshClient = new Client();
|
|
65
|
+
const server = createServer((localSocket) => {
|
|
66
|
+
sshClient.forwardOut("localhost", portForward.localPort, portForward.remoteHost, portForward.remotePort, (err, stream) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
localSocket.end();
|
|
69
|
+
console.error("Forward error:", err);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
localSocket.pipe(stream).pipe(localSocket);
|
|
73
|
+
localSocket.on("close", () => {
|
|
74
|
+
stream.end();
|
|
75
|
+
});
|
|
76
|
+
stream.on("close", () => {
|
|
77
|
+
localSocket.end();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
sshClient.on("ready", () => {
|
|
83
|
+
server.listen(portForward.localPort, () => {
|
|
84
|
+
activeConnections.set(id, { client: sshClient, server });
|
|
85
|
+
fastify.db.updatePortForward(id, {
|
|
86
|
+
status: "active",
|
|
87
|
+
connectionId: id,
|
|
88
|
+
});
|
|
89
|
+
fastify.io.emit("portforward:started", {
|
|
90
|
+
id,
|
|
91
|
+
localPort: portForward.localPort,
|
|
92
|
+
});
|
|
93
|
+
resolve({
|
|
94
|
+
success: true,
|
|
95
|
+
message: `Port forwarding started on localhost:${portForward.localPort}`,
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
server.on("error", (err) => {
|
|
99
|
+
sshClient.end();
|
|
100
|
+
resolve(reply.code(500).send({
|
|
101
|
+
error: "Failed to start local server",
|
|
102
|
+
details: err.message,
|
|
103
|
+
}));
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
sshClient.on("error", (err) => {
|
|
107
|
+
resolve(reply.code(500).send({
|
|
108
|
+
error: "SSH connection failed",
|
|
109
|
+
details: err.message,
|
|
110
|
+
}));
|
|
111
|
+
});
|
|
112
|
+
const connectConfig = {
|
|
113
|
+
host: connectionConfig.host,
|
|
114
|
+
port: connectionConfig.port,
|
|
115
|
+
username: connectionConfig.username,
|
|
116
|
+
};
|
|
117
|
+
if (connectionConfig.privateKeyPath) {
|
|
118
|
+
connectConfig.privateKey = readFileSync(connectionConfig.privateKeyPath);
|
|
119
|
+
}
|
|
120
|
+
else if (connectionConfig.password) {
|
|
121
|
+
connectConfig.password = connectionConfig.password;
|
|
122
|
+
}
|
|
123
|
+
sshClient.connect(connectConfig);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
return reply.code(500).send({
|
|
128
|
+
error: "Failed to start port forward",
|
|
129
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
// Stop port forwarding
|
|
134
|
+
fastify.post("/:id/stop", async (request, reply) => {
|
|
135
|
+
const { id } = request.params;
|
|
136
|
+
try {
|
|
137
|
+
const portForward = fastify.db.getPortForward(id);
|
|
138
|
+
if (!portForward) {
|
|
139
|
+
return reply.code(404).send({ error: "Port forward not found" });
|
|
140
|
+
}
|
|
141
|
+
if (portForward.status !== "active") {
|
|
142
|
+
return reply.code(400).send({ error: "Port forward is not active" });
|
|
143
|
+
}
|
|
144
|
+
const active = activeConnections.get(id);
|
|
145
|
+
if (active) {
|
|
146
|
+
active.server.close();
|
|
147
|
+
active.client.end();
|
|
148
|
+
activeConnections.delete(id);
|
|
149
|
+
}
|
|
150
|
+
fastify.db.updatePortForward(id, {
|
|
151
|
+
status: "inactive",
|
|
152
|
+
connectionId: undefined,
|
|
153
|
+
});
|
|
154
|
+
fastify.io.emit("portforward:stopped", {
|
|
155
|
+
id,
|
|
156
|
+
localPort: portForward.localPort,
|
|
157
|
+
});
|
|
158
|
+
return { success: true };
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return reply.code(500).send({
|
|
162
|
+
error: "Failed to stop port forward",
|
|
163
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
// Delete port forward
|
|
168
|
+
fastify.delete("/:id", async (request, reply) => {
|
|
169
|
+
const { id } = request.params;
|
|
170
|
+
try {
|
|
171
|
+
const portForward = fastify.db.getPortForward(id);
|
|
172
|
+
if (!portForward) {
|
|
173
|
+
return reply.code(404).send({ error: "Port forward not found" });
|
|
174
|
+
}
|
|
175
|
+
if (portForward.status === "active") {
|
|
176
|
+
const active = activeConnections.get(id);
|
|
177
|
+
if (active) {
|
|
178
|
+
active.server.close();
|
|
179
|
+
active.client.end();
|
|
180
|
+
activeConnections.delete(id);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
fastify.db.deletePortForward(id);
|
|
184
|
+
return { success: true };
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return reply.code(500).send({
|
|
188
|
+
error: "Failed to delete port forward",
|
|
189
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
// Cleanup on server close
|
|
194
|
+
fastify.addHook("onClose", async () => {
|
|
195
|
+
for (const [, { client, server }] of activeConnections) {
|
|
196
|
+
server.close();
|
|
197
|
+
client.end();
|
|
198
|
+
}
|
|
199
|
+
activeConnections.clear();
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=port-forward.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-forward.js","sourceRoot":"","sources":["../../src/routes/port-forward.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../src/routes/ssh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAoB7C,eAAO,MAAM,SAAS,EAAE,kBAsOvB,CAAC"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { Client } from "ssh2";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
export const sshRoutes = async (fastify) => {
|
|
5
|
+
// Get all SSH connections
|
|
6
|
+
fastify.get("/connections", async (_request, _reply) => {
|
|
7
|
+
const connections = fastify.db.getAllSSHConnections();
|
|
8
|
+
const safeConnections = connections.map((conn) => ({
|
|
9
|
+
...conn,
|
|
10
|
+
password: undefined,
|
|
11
|
+
privateKeyPath: conn.privateKeyPath ? "***" : undefined,
|
|
12
|
+
}));
|
|
13
|
+
return { connections: safeConnections };
|
|
14
|
+
});
|
|
15
|
+
// Create SSH connection config
|
|
16
|
+
fastify.post("/connections", async (request, reply) => {
|
|
17
|
+
const { serverName, host, port = 22, username, privateKeyPath, password, } = request.body;
|
|
18
|
+
try {
|
|
19
|
+
const connection = fastify.db.createSSHConnection({
|
|
20
|
+
id: crypto.randomUUID(),
|
|
21
|
+
serverName,
|
|
22
|
+
host,
|
|
23
|
+
port,
|
|
24
|
+
username,
|
|
25
|
+
privateKeyPath,
|
|
26
|
+
password,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
connection: {
|
|
30
|
+
...connection,
|
|
31
|
+
password: undefined,
|
|
32
|
+
privateKeyPath: connection.privateKeyPath ? "***" : undefined,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return reply.code(500).send({
|
|
38
|
+
error: "Failed to create SSH connection",
|
|
39
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// Execute command on remote server
|
|
44
|
+
fastify.post("/execute", async (request, reply) => {
|
|
45
|
+
const { connectionId, command, workingDirectory } = request.body;
|
|
46
|
+
try {
|
|
47
|
+
const connectionConfig = fastify.db.getSSHConnection(connectionId);
|
|
48
|
+
if (!connectionConfig) {
|
|
49
|
+
return reply.code(404).send({ error: "SSH connection not found" });
|
|
50
|
+
}
|
|
51
|
+
const conn = new Client();
|
|
52
|
+
let output = "";
|
|
53
|
+
let errorOutput = "";
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
conn.on("ready", () => {
|
|
56
|
+
const fullCommand = workingDirectory
|
|
57
|
+
? `cd ${workingDirectory} && ${command}`
|
|
58
|
+
: command;
|
|
59
|
+
conn.exec(fullCommand, (err, stream) => {
|
|
60
|
+
if (err) {
|
|
61
|
+
conn.end();
|
|
62
|
+
return resolve(reply.code(500).send({
|
|
63
|
+
error: "Failed to execute command",
|
|
64
|
+
details: err.message,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
stream.on("close", (code) => {
|
|
68
|
+
conn.end();
|
|
69
|
+
resolve({
|
|
70
|
+
output,
|
|
71
|
+
errorOutput,
|
|
72
|
+
exitCode: code,
|
|
73
|
+
success: code === 0,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
stream.on("data", (data) => {
|
|
77
|
+
output += data.toString();
|
|
78
|
+
fastify.io.emit("ssh:output", {
|
|
79
|
+
connectionId,
|
|
80
|
+
data: data.toString(),
|
|
81
|
+
type: "stdout",
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
stream.stderr.on("data", (data) => {
|
|
85
|
+
errorOutput += data.toString();
|
|
86
|
+
fastify.io.emit("ssh:output", {
|
|
87
|
+
connectionId,
|
|
88
|
+
data: data.toString(),
|
|
89
|
+
type: "stderr",
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
conn.on("error", (err) => {
|
|
95
|
+
resolve(reply.code(500).send({
|
|
96
|
+
error: "SSH connection failed",
|
|
97
|
+
details: err.message,
|
|
98
|
+
}));
|
|
99
|
+
});
|
|
100
|
+
const connectConfig = {
|
|
101
|
+
host: connectionConfig.host,
|
|
102
|
+
port: connectionConfig.port,
|
|
103
|
+
username: connectionConfig.username,
|
|
104
|
+
};
|
|
105
|
+
if (connectionConfig.privateKeyPath) {
|
|
106
|
+
connectConfig.privateKey = readFileSync(connectionConfig.privateKeyPath);
|
|
107
|
+
}
|
|
108
|
+
else if (connectionConfig.password) {
|
|
109
|
+
connectConfig.password = connectionConfig.password;
|
|
110
|
+
}
|
|
111
|
+
conn.connect(connectConfig);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
return reply.code(500).send({
|
|
116
|
+
error: "Failed to execute SSH command",
|
|
117
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
// Test SSH connection
|
|
122
|
+
fastify.post("/test/:connectionId", async (request, reply) => {
|
|
123
|
+
const { connectionId } = request.params;
|
|
124
|
+
try {
|
|
125
|
+
const connectionConfig = fastify.db.getSSHConnection(connectionId);
|
|
126
|
+
if (!connectionConfig) {
|
|
127
|
+
return reply.code(404).send({ error: "SSH connection not found" });
|
|
128
|
+
}
|
|
129
|
+
const conn = new Client();
|
|
130
|
+
return new Promise((resolve) => {
|
|
131
|
+
conn.on("ready", () => {
|
|
132
|
+
conn.end();
|
|
133
|
+
resolve({ success: true, message: "Connection successful" });
|
|
134
|
+
});
|
|
135
|
+
conn.on("error", (err) => {
|
|
136
|
+
resolve(reply.code(500).send({
|
|
137
|
+
success: false,
|
|
138
|
+
error: "Connection failed",
|
|
139
|
+
details: err.message,
|
|
140
|
+
}));
|
|
141
|
+
});
|
|
142
|
+
const connectConfig = {
|
|
143
|
+
host: connectionConfig.host,
|
|
144
|
+
port: connectionConfig.port,
|
|
145
|
+
username: connectionConfig.username,
|
|
146
|
+
readyTimeout: 10000,
|
|
147
|
+
};
|
|
148
|
+
if (connectionConfig.privateKeyPath) {
|
|
149
|
+
connectConfig.privateKey = readFileSync(connectionConfig.privateKeyPath);
|
|
150
|
+
}
|
|
151
|
+
else if (connectionConfig.password) {
|
|
152
|
+
connectConfig.password = connectionConfig.password;
|
|
153
|
+
}
|
|
154
|
+
conn.connect(connectConfig);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
return reply.code(500).send({
|
|
159
|
+
success: false,
|
|
160
|
+
error: "Failed to test connection",
|
|
161
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// Delete SSH connection
|
|
166
|
+
fastify.delete("/connections/:id", async (request, reply) => {
|
|
167
|
+
const { id } = request.params;
|
|
168
|
+
try {
|
|
169
|
+
const connection = fastify.db.getSSHConnection(id);
|
|
170
|
+
if (!connection) {
|
|
171
|
+
return reply.code(404).send({ error: "Connection not found" });
|
|
172
|
+
}
|
|
173
|
+
fastify.db.deleteSSHConnection(id);
|
|
174
|
+
return { success: true };
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
return reply.code(500).send({
|
|
178
|
+
error: "Failed to delete connection",
|
|
179
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
//# sourceMappingURL=ssh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../src/routes/ssh.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for Fastify decorations provided by the vibe-agent host.
|
|
3
|
+
* These are available at runtime when the plugin is loaded by the agent.
|
|
4
|
+
*/
|
|
5
|
+
import "fastify";
|
|
6
|
+
import type { Server as SocketIOServer } from "socket.io";
|
|
7
|
+
declare module "fastify" {
|
|
8
|
+
interface FastifyInstance {
|
|
9
|
+
db: any;
|
|
10
|
+
io: SocketIOServer;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;AAG1D,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,EAAE,EAAE,GAAG,CAAC;QACR,EAAE,EAAE,cAAc,CAAC;KACpB;CACF"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,SAAS,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@burdenoff/vibe-plugin-ssh",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18.0.0"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"lint": "eslint ./src",
|
|
12
|
+
"format": "npx prettier . --write",
|
|
13
|
+
"format:check": "npx prettier . --check",
|
|
14
|
+
"type:check": "tsc --noEmit",
|
|
15
|
+
"clean": "rimraf dist",
|
|
16
|
+
"prebuild": "npm run clean",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"sanity": "npm run format:check && npm run lint && npm run type:check && npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"vibecontrols",
|
|
22
|
+
"vibe",
|
|
23
|
+
"vibe-plugin",
|
|
24
|
+
"ssh",
|
|
25
|
+
"port-forward",
|
|
26
|
+
"remote-development"
|
|
27
|
+
],
|
|
28
|
+
"author": {
|
|
29
|
+
"name": "Vignesh T.V",
|
|
30
|
+
"email": "vignesh@burdenoff.com",
|
|
31
|
+
"url": "https://github.com/tvvignesh"
|
|
32
|
+
},
|
|
33
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
34
|
+
"description": "SSH connections & port forwarding plugin for VibeControls Agent",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"ssh2": "^1.16.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^24.0.11",
|
|
40
|
+
"@types/ssh2": "^1.15.5",
|
|
41
|
+
"commander": "^14.0.3",
|
|
42
|
+
"eslint": "^9.30.1",
|
|
43
|
+
"fastify": "^5.7.4",
|
|
44
|
+
"prettier": "^3.6.2",
|
|
45
|
+
"rimraf": "^6.0.1",
|
|
46
|
+
"socket.io": "^4.8.3",
|
|
47
|
+
"typescript": "^5.8.3"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@burdenoff/vibe-agent": ">=1.1.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependenciesMeta": {
|
|
53
|
+
"@burdenoff/vibe-agent": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"trustedDependencies": [
|
|
58
|
+
"cpu-features",
|
|
59
|
+
"ssh2"
|
|
60
|
+
],
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/algoshred/vibe-plugin-ssh.git"
|
|
64
|
+
},
|
|
65
|
+
"bugs": {
|
|
66
|
+
"url": "https://github.com/algoshred/vibe-plugin-ssh/issues"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://vibecontrols.com",
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public",
|
|
71
|
+
"registry": "https://registry.npmjs.org/"
|
|
72
|
+
},
|
|
73
|
+
"files": [
|
|
74
|
+
"dist/**/*",
|
|
75
|
+
"README.md",
|
|
76
|
+
"LICENSE"
|
|
77
|
+
]
|
|
78
|
+
}
|