@burdenoff/vibe-plugin-ssh 1.0.1 → 2.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 +12 -12
- package/dist/index.d.ts +7 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -14
- package/dist/index.js.map +1 -1
- package/dist/routes/port-forward.d.ts +189 -2
- package/dist/routes/port-forward.d.ts.map +1 -1
- package/dist/routes/port-forward.js +196 -95
- package/dist/routes/port-forward.js.map +1 -1
- package/dist/routes/ssh.d.ts +166 -2
- package/dist/routes/ssh.d.ts.map +1 -1
- package/dist/routes/ssh.js +155 -93
- package/dist/routes/ssh.js.map +1 -1
- package/dist/types.d.ts +79 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -3
- package/dist/types.js.map +1 -1
- package/package.json +16 -15
package/dist/routes/ssh.js
CHANGED
|
@@ -1,22 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH connection management routes (Elysia + KV storage).
|
|
3
|
+
*
|
|
4
|
+
* Namespace: "ssh"
|
|
5
|
+
* Keys:
|
|
6
|
+
* "connections" → JSON array of SSHConnection objects
|
|
7
|
+
*/
|
|
8
|
+
import { Elysia } from "elysia";
|
|
1
9
|
import crypto from "node:crypto";
|
|
2
10
|
import { Client } from "ssh2";
|
|
3
|
-
import { readFileSync } from "fs";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// KV helpers
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
async function getAllConnections(storage) {
|
|
16
|
+
const raw = await storage.get("ssh", "connections");
|
|
17
|
+
if (!raw)
|
|
18
|
+
return [];
|
|
19
|
+
return JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
async function getConnectionById(storage, id) {
|
|
22
|
+
const all = await getAllConnections(storage);
|
|
23
|
+
return all.find((c) => c.id === id);
|
|
24
|
+
}
|
|
25
|
+
async function saveConnections(storage, connections) {
|
|
26
|
+
await storage.set("ssh", "connections", JSON.stringify(connections));
|
|
27
|
+
}
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Sanitise a connection for API responses (strip secrets)
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
function sanitise(conn) {
|
|
32
|
+
const { password: _pw, privateKeyPath: _pk, ...rest } = conn;
|
|
33
|
+
return {
|
|
34
|
+
...rest,
|
|
35
|
+
privateKeyPath: conn.privateKeyPath ? "***" : undefined,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Build an ssh2 connect config from a stored connection
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
function buildConnectConfig(conn) {
|
|
42
|
+
const cfg = {
|
|
43
|
+
host: conn.host,
|
|
44
|
+
port: conn.port,
|
|
45
|
+
username: conn.username,
|
|
46
|
+
};
|
|
47
|
+
if (conn.privateKeyPath) {
|
|
48
|
+
cfg.privateKey = readFileSync(conn.privateKeyPath);
|
|
49
|
+
}
|
|
50
|
+
else if (conn.password) {
|
|
51
|
+
cfg.password = conn.password;
|
|
52
|
+
}
|
|
53
|
+
return cfg;
|
|
54
|
+
}
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Route factory
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
export function createSSHRoutes(hostServices) {
|
|
59
|
+
const { storage, eventBus } = hostServices;
|
|
60
|
+
return new Elysia({ prefix: "/api/ssh" })
|
|
61
|
+
// -----------------------------------------------------------------------
|
|
62
|
+
// GET /api/ssh/connections — list all saved SSH connections
|
|
63
|
+
// -----------------------------------------------------------------------
|
|
64
|
+
.get("/connections", async () => {
|
|
65
|
+
const connections = await getAllConnections(storage);
|
|
66
|
+
return { connections: connections.map(sanitise) };
|
|
67
|
+
})
|
|
68
|
+
// -----------------------------------------------------------------------
|
|
69
|
+
// POST /api/ssh/connections — create a new SSH connection config
|
|
70
|
+
// -----------------------------------------------------------------------
|
|
71
|
+
.post("/connections", async ({ body, set }) => {
|
|
72
|
+
const { serverName, host, port = 22, username, privateKeyPath, password, } = body;
|
|
18
73
|
try {
|
|
19
|
-
const
|
|
74
|
+
const connections = await getAllConnections(storage);
|
|
75
|
+
const newConn = {
|
|
20
76
|
id: crypto.randomUUID(),
|
|
21
77
|
serverName,
|
|
22
78
|
host,
|
|
@@ -24,29 +80,30 @@ export const sshRoutes = async (fastify) => {
|
|
|
24
80
|
username,
|
|
25
81
|
privateKeyPath,
|
|
26
82
|
password,
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
connection: {
|
|
30
|
-
...connection,
|
|
31
|
-
password: undefined,
|
|
32
|
-
privateKeyPath: connection.privateKeyPath ? "***" : undefined,
|
|
33
|
-
},
|
|
83
|
+
createdAt: new Date().toISOString(),
|
|
34
84
|
};
|
|
85
|
+
connections.push(newConn);
|
|
86
|
+
await saveConnections(storage, connections);
|
|
87
|
+
return { connection: sanitise(newConn) };
|
|
35
88
|
}
|
|
36
89
|
catch (error) {
|
|
37
|
-
|
|
90
|
+
set.status = 500;
|
|
91
|
+
return {
|
|
38
92
|
error: "Failed to create SSH connection",
|
|
39
93
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
40
|
-
}
|
|
94
|
+
};
|
|
41
95
|
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
96
|
+
})
|
|
97
|
+
// -----------------------------------------------------------------------
|
|
98
|
+
// POST /api/ssh/execute — execute a command on a remote server
|
|
99
|
+
// -----------------------------------------------------------------------
|
|
100
|
+
.post("/execute", async ({ body, set }) => {
|
|
101
|
+
const { connectionId, command, workingDirectory } = body;
|
|
46
102
|
try {
|
|
47
|
-
const connectionConfig =
|
|
103
|
+
const connectionConfig = await getConnectionById(storage, connectionId);
|
|
48
104
|
if (!connectionConfig) {
|
|
49
|
-
|
|
105
|
+
set.status = 404;
|
|
106
|
+
return { error: "SSH connection not found" };
|
|
50
107
|
}
|
|
51
108
|
const conn = new Client();
|
|
52
109
|
let output = "";
|
|
@@ -59,10 +116,12 @@ export const sshRoutes = async (fastify) => {
|
|
|
59
116
|
conn.exec(fullCommand, (err, stream) => {
|
|
60
117
|
if (err) {
|
|
61
118
|
conn.end();
|
|
62
|
-
|
|
119
|
+
set.status = 500;
|
|
120
|
+
resolve({
|
|
63
121
|
error: "Failed to execute command",
|
|
64
122
|
details: err.message,
|
|
65
|
-
})
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
66
125
|
}
|
|
67
126
|
stream.on("close", (code) => {
|
|
68
127
|
conn.end();
|
|
@@ -75,56 +134,60 @@ export const sshRoutes = async (fastify) => {
|
|
|
75
134
|
});
|
|
76
135
|
stream.on("data", (data) => {
|
|
77
136
|
output += data.toString();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
137
|
+
if (eventBus) {
|
|
138
|
+
eventBus.emit("ssh:output", {
|
|
139
|
+
connectionId,
|
|
140
|
+
data: data.toString(),
|
|
141
|
+
type: "stdout",
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.log(`[ssh:stdout] ${connectionId}: ${data.toString().trimEnd()}`);
|
|
146
|
+
}
|
|
83
147
|
});
|
|
84
148
|
stream.stderr.on("data", (data) => {
|
|
85
149
|
errorOutput += data.toString();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
150
|
+
if (eventBus) {
|
|
151
|
+
eventBus.emit("ssh:output", {
|
|
152
|
+
connectionId,
|
|
153
|
+
data: data.toString(),
|
|
154
|
+
type: "stderr",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
console.error(`[ssh:stderr] ${connectionId}: ${data.toString().trimEnd()}`);
|
|
159
|
+
}
|
|
91
160
|
});
|
|
92
161
|
});
|
|
93
162
|
});
|
|
94
163
|
conn.on("error", (err) => {
|
|
95
|
-
|
|
164
|
+
set.status = 500;
|
|
165
|
+
resolve({
|
|
96
166
|
error: "SSH connection failed",
|
|
97
167
|
details: err.message,
|
|
98
|
-
})
|
|
168
|
+
});
|
|
99
169
|
});
|
|
100
|
-
|
|
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);
|
|
170
|
+
conn.connect(buildConnectConfig(connectionConfig));
|
|
112
171
|
});
|
|
113
172
|
}
|
|
114
173
|
catch (error) {
|
|
115
|
-
|
|
174
|
+
set.status = 500;
|
|
175
|
+
return {
|
|
116
176
|
error: "Failed to execute SSH command",
|
|
117
177
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
118
|
-
}
|
|
178
|
+
};
|
|
119
179
|
}
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
180
|
+
})
|
|
181
|
+
// -----------------------------------------------------------------------
|
|
182
|
+
// POST /api/ssh/test/:connectionId — test an SSH connection
|
|
183
|
+
// -----------------------------------------------------------------------
|
|
184
|
+
.post("/test/:connectionId", async ({ params, set }) => {
|
|
185
|
+
const { connectionId } = params;
|
|
124
186
|
try {
|
|
125
|
-
const connectionConfig =
|
|
187
|
+
const connectionConfig = await getConnectionById(storage, connectionId);
|
|
126
188
|
if (!connectionConfig) {
|
|
127
|
-
|
|
189
|
+
set.status = 404;
|
|
190
|
+
return { error: "SSH connection not found" };
|
|
128
191
|
}
|
|
129
192
|
const conn = new Client();
|
|
130
193
|
return new Promise((resolve) => {
|
|
@@ -133,52 +196,51 @@ export const sshRoutes = async (fastify) => {
|
|
|
133
196
|
resolve({ success: true, message: "Connection successful" });
|
|
134
197
|
});
|
|
135
198
|
conn.on("error", (err) => {
|
|
136
|
-
|
|
199
|
+
set.status = 500;
|
|
200
|
+
resolve({
|
|
137
201
|
success: false,
|
|
138
202
|
error: "Connection failed",
|
|
139
203
|
details: err.message,
|
|
140
|
-
})
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
conn.connect({
|
|
207
|
+
...buildConnectConfig(connectionConfig),
|
|
208
|
+
readyTimeout: 10_000,
|
|
141
209
|
});
|
|
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
210
|
});
|
|
156
211
|
}
|
|
157
212
|
catch (error) {
|
|
158
|
-
|
|
213
|
+
set.status = 500;
|
|
214
|
+
return {
|
|
159
215
|
success: false,
|
|
160
216
|
error: "Failed to test connection",
|
|
161
217
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
162
|
-
}
|
|
218
|
+
};
|
|
163
219
|
}
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
220
|
+
})
|
|
221
|
+
// -----------------------------------------------------------------------
|
|
222
|
+
// DELETE /api/ssh/connections/:id — remove a saved SSH connection
|
|
223
|
+
// -----------------------------------------------------------------------
|
|
224
|
+
.delete("/connections/:id", async ({ params, set }) => {
|
|
225
|
+
const { id } = params;
|
|
168
226
|
try {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
227
|
+
const connections = await getAllConnections(storage);
|
|
228
|
+
const idx = connections.findIndex((c) => c.id === id);
|
|
229
|
+
if (idx === -1) {
|
|
230
|
+
set.status = 404;
|
|
231
|
+
return { error: "Connection not found" };
|
|
172
232
|
}
|
|
173
|
-
|
|
233
|
+
connections.splice(idx, 1);
|
|
234
|
+
await saveConnections(storage, connections);
|
|
174
235
|
return { success: true };
|
|
175
236
|
}
|
|
176
237
|
catch (error) {
|
|
177
|
-
|
|
238
|
+
set.status = 500;
|
|
239
|
+
return {
|
|
178
240
|
error: "Failed to delete connection",
|
|
179
241
|
details: error instanceof Error ? error.message : "Unknown error",
|
|
180
|
-
}
|
|
242
|
+
};
|
|
181
243
|
}
|
|
182
244
|
});
|
|
183
|
-
}
|
|
245
|
+
}
|
|
184
246
|
//# sourceMappingURL=ssh.js.map
|
package/dist/routes/ssh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../src/routes/ssh.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../src/routes/ssh.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,13 +1,83 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Type declarations for
|
|
3
|
-
*
|
|
2
|
+
* Type declarations for the vibe-plugin-ssh plugin.
|
|
3
|
+
*
|
|
4
|
+
* All interfaces are defined locally so the plugin does not hard-import
|
|
5
|
+
* from the core agent package. At runtime the host agent injects concrete
|
|
6
|
+
* implementations via HostServices.
|
|
4
7
|
*/
|
|
5
|
-
import "
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
import type { Elysia } from "elysia";
|
|
9
|
+
import type { Command } from "commander";
|
|
10
|
+
export interface StorageProvider {
|
|
11
|
+
/** Retrieve a value by namespace + key. Returns `null` when missing. */
|
|
12
|
+
get(namespace: string, key: string): Promise<string | null>;
|
|
13
|
+
/** Persist a value under namespace + key. */
|
|
14
|
+
set(namespace: string, key: string, value: string): Promise<void>;
|
|
15
|
+
/** Delete a single key. */
|
|
16
|
+
delete(namespace: string, key: string): Promise<boolean>;
|
|
17
|
+
/** List all keys in a namespace. */
|
|
18
|
+
keys(namespace: string): Promise<string[]>;
|
|
19
|
+
}
|
|
20
|
+
export interface EventBus {
|
|
21
|
+
emit(event: string, payload: unknown): void;
|
|
22
|
+
on(event: string, handler: (payload: unknown) => void): void;
|
|
23
|
+
off(event: string, handler: (payload: unknown) => void): void;
|
|
24
|
+
}
|
|
25
|
+
export interface ServiceRegistry {
|
|
26
|
+
get<T = unknown>(name: string): T | undefined;
|
|
27
|
+
}
|
|
28
|
+
export interface HostServices {
|
|
29
|
+
storage: StorageProvider;
|
|
30
|
+
eventBus?: EventBus;
|
|
31
|
+
serviceRegistry?: ServiceRegistry;
|
|
32
|
+
}
|
|
33
|
+
export interface VibePlugin {
|
|
34
|
+
name: string;
|
|
35
|
+
version: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
tags?: Array<"backend" | "frontend" | "cli" | "provider" | "adapter" | "integration">;
|
|
38
|
+
cliCommand?: string;
|
|
39
|
+
apiPrefix?: string;
|
|
40
|
+
onCliSetup?: (program: Command) => void | Promise<void>;
|
|
41
|
+
onServerStart?: (app: Elysia, hostServices: HostServices) => void | Promise<void>;
|
|
42
|
+
onServerStop?: () => void | Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export interface SSHConnection {
|
|
45
|
+
id: string;
|
|
46
|
+
serverName: string;
|
|
47
|
+
host: string;
|
|
48
|
+
port: number;
|
|
49
|
+
username: string;
|
|
50
|
+
privateKeyPath?: string;
|
|
51
|
+
password?: string;
|
|
52
|
+
createdAt?: string;
|
|
53
|
+
}
|
|
54
|
+
export interface PortForward {
|
|
55
|
+
id: string;
|
|
56
|
+
localPort: number;
|
|
57
|
+
remoteHost: string;
|
|
58
|
+
remotePort: number;
|
|
59
|
+
serverName: string;
|
|
60
|
+
connectionId: string;
|
|
61
|
+
status: "active" | "inactive";
|
|
62
|
+
createdAt?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface CreateConnectionBody {
|
|
65
|
+
serverName: string;
|
|
66
|
+
host: string;
|
|
67
|
+
port?: number;
|
|
68
|
+
username: string;
|
|
69
|
+
privateKeyPath?: string;
|
|
70
|
+
password?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface ExecuteCommandBody {
|
|
73
|
+
connectionId: string;
|
|
74
|
+
command: string;
|
|
75
|
+
workingDirectory?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface CreatePortForwardBody {
|
|
78
|
+
localPort: number;
|
|
79
|
+
remoteHost: string;
|
|
80
|
+
remotePort: number;
|
|
81
|
+
connectionId: string;
|
|
12
82
|
}
|
|
13
83
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Type declarations for
|
|
3
|
-
*
|
|
2
|
+
* Type declarations for the vibe-plugin-ssh plugin.
|
|
3
|
+
*
|
|
4
|
+
* All interfaces are defined locally so the plugin does not hard-import
|
|
5
|
+
* from the core agent package. At runtime the host agent injects concrete
|
|
6
|
+
* implementations via HostServices.
|
|
4
7
|
*/
|
|
5
|
-
|
|
8
|
+
export {};
|
|
6
9
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/vibe-plugin-ssh",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
|
-
"
|
|
7
|
+
"bun": ">=1.3.0"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "tsc",
|
|
10
|
+
"build": "bun run tsc",
|
|
11
11
|
"lint": "eslint ./src",
|
|
12
|
-
"format": "
|
|
13
|
-
"format:check": "
|
|
12
|
+
"format": "bunx prettier . --write",
|
|
13
|
+
"format:check": "bunx prettier . --check",
|
|
14
14
|
"type:check": "tsc --noEmit",
|
|
15
15
|
"clean": "rimraf dist",
|
|
16
|
-
"prebuild": "
|
|
17
|
-
"prepublishOnly": "
|
|
18
|
-
"sanity": "
|
|
16
|
+
"prebuild": "bun run clean",
|
|
17
|
+
"prepublishOnly": "bun run build",
|
|
18
|
+
"sanity": "bun run format:check && bun run lint && bun run type:check && bun run build"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"vibecontrols",
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"vibe-plugin",
|
|
24
24
|
"ssh",
|
|
25
25
|
"port-forward",
|
|
26
|
-
"remote-development"
|
|
26
|
+
"remote-development",
|
|
27
|
+
"elysia",
|
|
28
|
+
"bun"
|
|
27
29
|
],
|
|
28
30
|
"author": {
|
|
29
31
|
"name": "Vignesh T.V",
|
|
@@ -31,26 +33,25 @@
|
|
|
31
33
|
"url": "https://github.com/tvvignesh"
|
|
32
34
|
},
|
|
33
35
|
"license": "SEE LICENSE IN LICENSE",
|
|
34
|
-
"description": "SSH connections & port forwarding plugin for VibeControls Agent",
|
|
36
|
+
"description": "SSH connections & port forwarding plugin for VibeControls Agent (Bun/Elysia)",
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"ssh2": "^1.16.0"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
|
-
"@types/
|
|
41
|
+
"@types/bun": "^1.2.10",
|
|
40
42
|
"@types/ssh2": "^1.15.5",
|
|
41
43
|
"commander": "^14.0.3",
|
|
44
|
+
"elysia": "^1.3.0",
|
|
42
45
|
"eslint": "^9.30.1",
|
|
43
|
-
"fastify": "^5.7.4",
|
|
44
46
|
"prettier": "^3.6.2",
|
|
45
47
|
"rimraf": "^6.0.1",
|
|
46
|
-
"socket.io": "^4.8.3",
|
|
47
48
|
"typescript": "^5.8.3"
|
|
48
49
|
},
|
|
49
50
|
"peerDependencies": {
|
|
50
|
-
"
|
|
51
|
+
"elysia": ">=1.3.0"
|
|
51
52
|
},
|
|
52
53
|
"peerDependenciesMeta": {
|
|
53
|
-
"
|
|
54
|
+
"elysia": {
|
|
54
55
|
"optional": true
|
|
55
56
|
}
|
|
56
57
|
},
|