@vibecontrols/vibe-plugin-ssh 2026.416.1

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.
@@ -0,0 +1,144 @@
1
+ /**
2
+ * SSH config scanning routes.
3
+ *
4
+ * Reads and parses SSH config files (e.g. ~/.ssh/config) from the local
5
+ * filesystem or from a remote server via SSH. Presents discovered hosts
6
+ * so users can batch-install vibecontrols-agent on them.
7
+ */
8
+ import { Elysia } from "elysia";
9
+ import type { HostServices } from "../types.js";
10
+ export interface SSHConfigHost {
11
+ name: string;
12
+ hostname: string;
13
+ port: number;
14
+ user: string;
15
+ identityFile?: string;
16
+ proxyJump?: string;
17
+ extra: Record<string, string>;
18
+ }
19
+ export declare function createSSHConfigScanRoutes(hostServices: HostServices): Elysia<"/api/ssh/config-scan", {
20
+ decorator: {};
21
+ store: {};
22
+ derive: {};
23
+ resolve: {};
24
+ }, {
25
+ typebox: {};
26
+ error: {};
27
+ }, {
28
+ schema: {};
29
+ standaloneSchema: {};
30
+ macro: {};
31
+ macroFn: {};
32
+ parser: {};
33
+ response: {};
34
+ }, {
35
+ api: {
36
+ ssh: {
37
+ "config-scan": {
38
+ local: {
39
+ post: {
40
+ body: unknown;
41
+ params: {};
42
+ query: unknown;
43
+ headers: unknown;
44
+ response: {
45
+ 200: {
46
+ error: string;
47
+ configPath?: undefined;
48
+ hosts?: undefined;
49
+ total?: undefined;
50
+ details?: undefined;
51
+ } | {
52
+ configPath: string;
53
+ hosts: SSHConfigHost[];
54
+ total: number;
55
+ error?: undefined;
56
+ details?: undefined;
57
+ } | {
58
+ error: string;
59
+ details: string;
60
+ configPath?: undefined;
61
+ hosts?: undefined;
62
+ total?: undefined;
63
+ };
64
+ };
65
+ };
66
+ };
67
+ };
68
+ };
69
+ };
70
+ } & {
71
+ api: {
72
+ ssh: {
73
+ "config-scan": {
74
+ remote: {
75
+ post: {
76
+ body: unknown;
77
+ params: {};
78
+ query: unknown;
79
+ headers: unknown;
80
+ response: {};
81
+ };
82
+ };
83
+ };
84
+ };
85
+ };
86
+ } & {
87
+ api: {
88
+ ssh: {
89
+ "config-scan": {
90
+ "batch-create": {
91
+ post: {
92
+ body: unknown;
93
+ params: {};
94
+ query: unknown;
95
+ headers: unknown;
96
+ response: {
97
+ 200: {
98
+ error: string;
99
+ created?: undefined;
100
+ skipped?: undefined;
101
+ skippedNames?: undefined;
102
+ connections?: undefined;
103
+ details?: undefined;
104
+ } | {
105
+ created: number;
106
+ skipped: number;
107
+ skippedNames: string[];
108
+ connections: {
109
+ id: string;
110
+ serverName: string;
111
+ host: string;
112
+ port: number;
113
+ username: string;
114
+ }[];
115
+ error?: undefined;
116
+ details?: undefined;
117
+ } | {
118
+ error: string;
119
+ details: string;
120
+ created?: undefined;
121
+ skipped?: undefined;
122
+ skippedNames?: undefined;
123
+ connections?: undefined;
124
+ };
125
+ };
126
+ };
127
+ };
128
+ };
129
+ };
130
+ };
131
+ }, {
132
+ derive: {};
133
+ resolve: {};
134
+ schema: {};
135
+ standaloneSchema: {};
136
+ response: {};
137
+ }, {
138
+ derive: {};
139
+ resolve: {};
140
+ schema: {};
141
+ standaloneSchema: {};
142
+ response: {};
143
+ }>;
144
+ //# sourceMappingURL=ssh-config-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-config-scan.d.ts","sourceRoot":"","sources":["../../src/routes/ssh-config-scan.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAM/D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAmID,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiLnE"}
@@ -0,0 +1,271 @@
1
+ /**
2
+ * SSH config scanning routes.
3
+ *
4
+ * Reads and parses SSH config files (e.g. ~/.ssh/config) from the local
5
+ * filesystem or from a remote server via SSH. Presents discovered hosts
6
+ * so users can batch-install vibecontrols-agent on them.
7
+ */
8
+ import { Elysia } from "elysia";
9
+ import { Client } from "ssh2";
10
+ function parseSSHConfig(content) {
11
+ const hosts = [];
12
+ let current = null;
13
+ for (const rawLine of content.split("\n")) {
14
+ const line = rawLine.trim();
15
+ if (!line || line.startsWith("#"))
16
+ continue;
17
+ const match = line.match(/^(\S+)\s+(.+)$/);
18
+ if (!match)
19
+ continue;
20
+ const [, key, value] = match;
21
+ const keyLower = key.toLowerCase();
22
+ if (keyLower === "host") {
23
+ // Save previous host
24
+ if (current?.name && current.name !== "*") {
25
+ hosts.push({
26
+ name: current.name,
27
+ hostname: current.hostname || current.name,
28
+ port: current.port || 22,
29
+ user: current.user || "root",
30
+ identityFile: current.identityFile,
31
+ proxyJump: current.proxyJump,
32
+ extra: current.extra || {},
33
+ });
34
+ }
35
+ current = { name: value, extra: {} };
36
+ }
37
+ else if (current) {
38
+ switch (keyLower) {
39
+ case "hostname":
40
+ current.hostname = value;
41
+ break;
42
+ case "port":
43
+ current.port = parseInt(value, 10);
44
+ break;
45
+ case "user":
46
+ current.user = value;
47
+ break;
48
+ case "identityfile":
49
+ current.identityFile = value.replace(/^~/, process.env.HOME || "~");
50
+ break;
51
+ case "proxyjump":
52
+ current.proxyJump = value;
53
+ break;
54
+ default:
55
+ if (!current.extra)
56
+ current.extra = {};
57
+ current.extra[key] = value;
58
+ }
59
+ }
60
+ }
61
+ // Save last host
62
+ if (current?.name && current.name !== "*") {
63
+ hosts.push({
64
+ name: current.name,
65
+ hostname: current.hostname || current.name,
66
+ port: current.port || 22,
67
+ user: current.user || "root",
68
+ identityFile: current.identityFile,
69
+ proxyJump: current.proxyJump,
70
+ extra: current.extra || {},
71
+ });
72
+ }
73
+ return hosts;
74
+ }
75
+ // ---------------------------------------------------------------------------
76
+ // SSH helpers
77
+ // ---------------------------------------------------------------------------
78
+ async function getConnectionById(storage, id) {
79
+ const raw = await storage.get("ssh", "connections");
80
+ if (!raw)
81
+ return undefined;
82
+ const all = JSON.parse(raw);
83
+ return all.find((c) => c.id === id);
84
+ }
85
+ async function buildConnectConfig(conn) {
86
+ const cfg = {
87
+ host: conn.host,
88
+ port: conn.port,
89
+ username: conn.username,
90
+ };
91
+ if (conn.privateKeyPath) {
92
+ const file = Bun.file(conn.privateKeyPath);
93
+ cfg.privateKey = Buffer.from(await file.arrayBuffer());
94
+ }
95
+ else if (conn.password) {
96
+ cfg.password = conn.password;
97
+ }
98
+ return cfg;
99
+ }
100
+ function sshExec(client, command) {
101
+ return new Promise((resolve, reject) => {
102
+ client.exec(command, (err, stream) => {
103
+ if (err)
104
+ return reject(err);
105
+ let stdout = "";
106
+ let stderr = "";
107
+ stream.on("data", (data) => {
108
+ stdout += data.toString();
109
+ });
110
+ stream.stderr.on("data", (data) => {
111
+ stderr += data.toString();
112
+ });
113
+ stream.on("close", (code) => {
114
+ resolve({ stdout: stdout.trim(), stderr: stderr.trim(), code });
115
+ });
116
+ });
117
+ });
118
+ }
119
+ // ---------------------------------------------------------------------------
120
+ // Route factory
121
+ // ---------------------------------------------------------------------------
122
+ export function createSSHConfigScanRoutes(hostServices) {
123
+ const { storage } = hostServices;
124
+ return (new Elysia({ prefix: "/api/ssh/config-scan" })
125
+ // -----------------------------------------------------------------------
126
+ // POST /api/ssh/config-scan/local — scan a local SSH config file
127
+ // -----------------------------------------------------------------------
128
+ .post("/local", async ({ body, set }) => {
129
+ const { configPath = "~/.ssh/config" } = body;
130
+ const resolved = configPath.replace(/^~/, process.env.HOME || "~");
131
+ try {
132
+ const file = Bun.file(resolved);
133
+ const exists = await file.exists();
134
+ if (!exists) {
135
+ set.status = 404;
136
+ return { error: `SSH config not found at ${resolved}` };
137
+ }
138
+ const content = await file.text();
139
+ const hosts = parseSSHConfig(content);
140
+ return {
141
+ configPath: resolved,
142
+ hosts,
143
+ total: hosts.length,
144
+ };
145
+ }
146
+ catch (error) {
147
+ set.status = 500;
148
+ return {
149
+ error: "Failed to read SSH config",
150
+ details: error instanceof Error ? error.message : "Unknown error",
151
+ };
152
+ }
153
+ })
154
+ // -----------------------------------------------------------------------
155
+ // POST /api/ssh/config-scan/remote — scan SSH config on a remote server
156
+ // via an existing SSH connection
157
+ // -----------------------------------------------------------------------
158
+ .post("/remote", async ({ body, set }) => {
159
+ const { connectionId, configPath = "~/.ssh/config" } = body;
160
+ try {
161
+ const connConfig = await getConnectionById(storage, connectionId);
162
+ if (!connConfig) {
163
+ set.status = 404;
164
+ return { error: "SSH connection not found" };
165
+ }
166
+ const sshClient = new Client();
167
+ const connectConfig = await buildConnectConfig(connConfig);
168
+ return new Promise((resolve) => {
169
+ sshClient.on("ready", async () => {
170
+ try {
171
+ const { stdout, code } = await sshExec(sshClient, `cat ${configPath} 2>/dev/null`);
172
+ if (code !== 0 || !stdout) {
173
+ sshClient.end();
174
+ set.status = 404;
175
+ return resolve({
176
+ error: `SSH config not found at ${configPath} on remote server`,
177
+ });
178
+ }
179
+ const hosts = parseSSHConfig(stdout);
180
+ sshClient.end();
181
+ resolve({
182
+ configPath,
183
+ remoteHost: connConfig.host,
184
+ hosts,
185
+ total: hosts.length,
186
+ });
187
+ }
188
+ catch (err) {
189
+ sshClient.end();
190
+ set.status = 500;
191
+ resolve({
192
+ error: "Failed to read remote SSH config",
193
+ details: err instanceof Error ? err.message : "Unknown error",
194
+ });
195
+ }
196
+ });
197
+ sshClient.on("error", (err) => {
198
+ set.status = 500;
199
+ resolve({
200
+ error: "SSH connection failed",
201
+ details: err.message,
202
+ });
203
+ });
204
+ sshClient.connect(connectConfig);
205
+ });
206
+ }
207
+ catch (error) {
208
+ set.status = 500;
209
+ return {
210
+ error: "Failed to scan remote SSH config",
211
+ details: error instanceof Error ? error.message : "Unknown error",
212
+ };
213
+ }
214
+ })
215
+ // -----------------------------------------------------------------------
216
+ // POST /api/ssh/config-scan/batch-create — create SSH connections from
217
+ // scanned hosts (bulk import from SSH config)
218
+ // -----------------------------------------------------------------------
219
+ .post("/batch-create", async ({ body, set }) => {
220
+ const { hosts } = body;
221
+ if (!hosts || !Array.isArray(hosts) || hosts.length === 0) {
222
+ set.status = 400;
223
+ return { error: "No hosts provided" };
224
+ }
225
+ try {
226
+ const raw = await storage.get("ssh", "connections");
227
+ const connections = raw ? JSON.parse(raw) : [];
228
+ const created = [];
229
+ const skipped = [];
230
+ for (const host of hosts) {
231
+ // Skip if connection with same name already exists
232
+ if (connections.find((c) => c.serverName === host.name)) {
233
+ skipped.push(host.name);
234
+ continue;
235
+ }
236
+ const newConn = {
237
+ id: globalThis.crypto.randomUUID(),
238
+ serverName: host.name,
239
+ host: host.hostname,
240
+ port: host.port,
241
+ username: host.user,
242
+ privateKeyPath: host.identityFile,
243
+ createdAt: new Date().toISOString(),
244
+ };
245
+ connections.push(newConn);
246
+ created.push(newConn);
247
+ }
248
+ await storage.set("ssh", "connections", JSON.stringify(connections));
249
+ return {
250
+ created: created.length,
251
+ skipped: skipped.length,
252
+ skippedNames: skipped,
253
+ connections: created.map((c) => ({
254
+ id: c.id,
255
+ serverName: c.serverName,
256
+ host: c.host,
257
+ port: c.port,
258
+ username: c.username,
259
+ })),
260
+ };
261
+ }
262
+ catch (error) {
263
+ set.status = 500;
264
+ return {
265
+ error: "Failed to batch create connections",
266
+ details: error instanceof Error ? error.message : "Unknown error",
267
+ };
268
+ }
269
+ }));
270
+ }
271
+ //# sourceMappingURL=ssh-config-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-config-scan.js","sourceRoot":"","sources":["../../src/routes/ssh-config-scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
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";
9
+ import type { HostServices, SSHConnection } from "../types.js";
10
+ export declare function createSSHRoutes(hostServices: HostServices): Elysia<"/api/ssh", {
11
+ decorator: {};
12
+ store: {};
13
+ derive: {};
14
+ resolve: {};
15
+ }, {
16
+ typebox: {};
17
+ error: {};
18
+ }, {
19
+ schema: {};
20
+ standaloneSchema: {};
21
+ macro: {};
22
+ macroFn: {};
23
+ parser: {};
24
+ response: {};
25
+ }, {
26
+ api: {
27
+ ssh: {
28
+ connections: {
29
+ get: {
30
+ body: unknown;
31
+ params: {};
32
+ query: unknown;
33
+ headers: unknown;
34
+ response: {
35
+ 200: {
36
+ connections: (Omit<SSHConnection, "password" | "privateKeyPath"> & {
37
+ privateKeyPath?: string;
38
+ })[];
39
+ };
40
+ };
41
+ };
42
+ };
43
+ };
44
+ };
45
+ } & {
46
+ api: {
47
+ ssh: {
48
+ connections: {
49
+ post: {
50
+ body: unknown;
51
+ params: {};
52
+ query: unknown;
53
+ headers: unknown;
54
+ response: {
55
+ 200: {
56
+ connection: Omit<SSHConnection, "password" | "privateKeyPath"> & {
57
+ privateKeyPath?: string;
58
+ };
59
+ error?: undefined;
60
+ details?: undefined;
61
+ } | {
62
+ error: string;
63
+ details: string;
64
+ connection?: undefined;
65
+ };
66
+ };
67
+ };
68
+ };
69
+ };
70
+ };
71
+ } & {
72
+ api: {
73
+ ssh: {
74
+ execute: {
75
+ post: {
76
+ body: unknown;
77
+ params: {};
78
+ query: unknown;
79
+ headers: unknown;
80
+ response: {};
81
+ };
82
+ };
83
+ };
84
+ };
85
+ } & {
86
+ api: {
87
+ ssh: {
88
+ test: {
89
+ ":connectionId": {
90
+ post: {
91
+ body: unknown;
92
+ params: {
93
+ connectionId: string;
94
+ } & {};
95
+ query: unknown;
96
+ headers: unknown;
97
+ response: {
98
+ 422: {
99
+ type: "validation";
100
+ on: string;
101
+ summary?: string;
102
+ message?: string;
103
+ found?: unknown;
104
+ property?: string;
105
+ expected?: string;
106
+ };
107
+ };
108
+ };
109
+ };
110
+ };
111
+ };
112
+ };
113
+ } & {
114
+ api: {
115
+ ssh: {
116
+ connections: {
117
+ ":id": {
118
+ get: {
119
+ body: unknown;
120
+ params: {
121
+ id: string;
122
+ } & {};
123
+ query: unknown;
124
+ headers: unknown;
125
+ response: {
126
+ 200: {
127
+ error: string;
128
+ connection?: undefined;
129
+ } | {
130
+ connection: Omit<SSHConnection, "password" | "privateKeyPath"> & {
131
+ privateKeyPath?: string;
132
+ };
133
+ error?: undefined;
134
+ };
135
+ 422: {
136
+ type: "validation";
137
+ on: string;
138
+ summary?: string;
139
+ message?: string;
140
+ found?: unknown;
141
+ property?: string;
142
+ expected?: string;
143
+ };
144
+ };
145
+ };
146
+ };
147
+ };
148
+ };
149
+ };
150
+ } & {
151
+ api: {
152
+ ssh: {
153
+ connections: {
154
+ ":id": {
155
+ put: {
156
+ body: unknown;
157
+ params: {
158
+ id: string;
159
+ } & {};
160
+ query: unknown;
161
+ headers: unknown;
162
+ response: {
163
+ 200: {
164
+ error: string;
165
+ connection?: undefined;
166
+ details?: undefined;
167
+ } | {
168
+ connection: Omit<SSHConnection, "password" | "privateKeyPath"> & {
169
+ privateKeyPath?: string;
170
+ };
171
+ error?: undefined;
172
+ details?: undefined;
173
+ } | {
174
+ error: string;
175
+ details: string;
176
+ connection?: undefined;
177
+ };
178
+ 422: {
179
+ type: "validation";
180
+ on: string;
181
+ summary?: string;
182
+ message?: string;
183
+ found?: unknown;
184
+ property?: string;
185
+ expected?: string;
186
+ };
187
+ };
188
+ };
189
+ };
190
+ };
191
+ };
192
+ };
193
+ } & {
194
+ api: {
195
+ ssh: {
196
+ connections: {
197
+ ":id": {
198
+ delete: {
199
+ body: unknown;
200
+ params: {
201
+ id: string;
202
+ } & {};
203
+ query: unknown;
204
+ headers: unknown;
205
+ response: {
206
+ 200: {
207
+ error: string;
208
+ success?: undefined;
209
+ details?: undefined;
210
+ } | {
211
+ success: boolean;
212
+ error?: undefined;
213
+ details?: undefined;
214
+ } | {
215
+ error: string;
216
+ details: string;
217
+ success?: undefined;
218
+ };
219
+ 422: {
220
+ type: "validation";
221
+ on: string;
222
+ summary?: string;
223
+ message?: string;
224
+ found?: unknown;
225
+ property?: string;
226
+ expected?: string;
227
+ };
228
+ };
229
+ };
230
+ };
231
+ };
232
+ };
233
+ };
234
+ }, {
235
+ derive: {};
236
+ resolve: {};
237
+ schema: {};
238
+ standaloneSchema: {};
239
+ response: {};
240
+ }, {
241
+ derive: {};
242
+ resolve: {};
243
+ schema: {};
244
+ standaloneSchema: {};
245
+ response: {};
246
+ }>;
247
+ //# sourceMappingURL=ssh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../src/routes/ssh.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EAGd,MAAM,aAAa,CAAC;AA8ErB,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAzCvC,MAAM;;;;;;;;;;;;;;;;;;;;iDAAN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAAN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAAN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoUxB"}