@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.
- package/README.md +70 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/port-forward.d.ts +190 -0
- package/dist/routes/port-forward.d.ts.map +1 -0
- package/dist/routes/port-forward.js +303 -0
- package/dist/routes/port-forward.js.map +1 -0
- package/dist/routes/remote-agent-install.d.ts +179 -0
- package/dist/routes/remote-agent-install.d.ts.map +1 -0
- package/dist/routes/remote-agent-install.js +537 -0
- package/dist/routes/remote-agent-install.js.map +1 -0
- package/dist/routes/remote-terminal.d.ts +154 -0
- package/dist/routes/remote-terminal.d.ts.map +1 -0
- package/dist/routes/remote-terminal.js +437 -0
- package/dist/routes/remote-terminal.js.map +1 -0
- package/dist/routes/ssh-config-scan.d.ts +144 -0
- package/dist/routes/ssh-config-scan.d.ts.map +1 -0
- package/dist/routes/ssh-config-scan.js +271 -0
- package/dist/routes/ssh-config-scan.js.map +1 -0
- package/dist/routes/ssh.d.ts +247 -0
- package/dist/routes/ssh.d.ts.map +1 -0
- package/dist/routes/ssh.js +295 -0
- package/dist/routes/ssh.js.map +1 -0
- package/dist/types.d.ts +171 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote agent installation routes.
|
|
3
|
+
*
|
|
4
|
+
* Installs vibecontrols-agent on a target server via SSH. This is a
|
|
5
|
+
* long-running operation — progress is reported via WebSocket events.
|
|
6
|
+
*
|
|
7
|
+
* Registry URL resolution (for @vibecontrols packages):
|
|
8
|
+
* 1. hostServices.getPluginRegistry() — reads from agent config/env
|
|
9
|
+
* 2. Fallback: https://registry.npmjs.org
|
|
10
|
+
*/
|
|
11
|
+
import { Elysia } from "elysia";
|
|
12
|
+
import { Client } from "ssh2";
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Constants
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Common PATH setup prepended to all remote commands after bun is installed. */
|
|
17
|
+
const REMOTE_PATH = 'export BUN_INSTALL="$HOME/.bun" && export PATH="$BUN_INSTALL/bin:$HOME/.local/bin:$PATH"';
|
|
18
|
+
const DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// In-memory job tracking
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
const installJobs = new Map();
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// KV / SSH helpers
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
async function getConnectionById(storage, id) {
|
|
27
|
+
const raw = await storage.get("ssh", "connections");
|
|
28
|
+
if (!raw)
|
|
29
|
+
return undefined;
|
|
30
|
+
const all = JSON.parse(raw);
|
|
31
|
+
return all.find((c) => c.id === id);
|
|
32
|
+
}
|
|
33
|
+
async function buildConnectConfig(conn) {
|
|
34
|
+
const cfg = {
|
|
35
|
+
host: conn.host,
|
|
36
|
+
port: conn.port,
|
|
37
|
+
username: conn.username,
|
|
38
|
+
};
|
|
39
|
+
if (conn.privateKeyPath) {
|
|
40
|
+
const file = Bun.file(conn.privateKeyPath);
|
|
41
|
+
cfg.privateKey = Buffer.from(await file.arrayBuffer());
|
|
42
|
+
}
|
|
43
|
+
else if (conn.password) {
|
|
44
|
+
cfg.password = conn.password;
|
|
45
|
+
}
|
|
46
|
+
return cfg;
|
|
47
|
+
}
|
|
48
|
+
function sshExec(client, command, timeoutMs = 60_000) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const timer = setTimeout(() => {
|
|
51
|
+
reject(new Error(`Command timed out after ${timeoutMs}ms`));
|
|
52
|
+
}, timeoutMs);
|
|
53
|
+
client.exec(command, (err, stream) => {
|
|
54
|
+
if (err) {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
return reject(err);
|
|
57
|
+
}
|
|
58
|
+
let stdout = "";
|
|
59
|
+
let stderr = "";
|
|
60
|
+
stream.on("data", (data) => {
|
|
61
|
+
stdout += data.toString();
|
|
62
|
+
});
|
|
63
|
+
stream.stderr.on("data", (data) => {
|
|
64
|
+
stderr += data.toString();
|
|
65
|
+
});
|
|
66
|
+
stream.on("close", (code) => {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
resolve({ stdout: stdout.trim(), stderr: stderr.trim(), code });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Installation step definitions
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
const INSTALL_STEPS = [
|
|
77
|
+
{ name: "connect" },
|
|
78
|
+
{ name: "detect_os" },
|
|
79
|
+
{ name: "install_bun" },
|
|
80
|
+
{ name: "install_agent" },
|
|
81
|
+
{ name: "configure" },
|
|
82
|
+
{ name: "start" },
|
|
83
|
+
{ name: "verify" },
|
|
84
|
+
{ name: "retrieve" },
|
|
85
|
+
{ name: "register" },
|
|
86
|
+
];
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Run the installation pipeline
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
async function runInstallation(job, connConfig, agentPort, hostServices, options = {}) {
|
|
91
|
+
const { broadcast } = hostServices;
|
|
92
|
+
const sshClient = new Client();
|
|
93
|
+
// Resolve registry URL from agent config
|
|
94
|
+
const registryUrl = hostServices.getPluginRegistry?.() ?? DEFAULT_REGISTRY;
|
|
95
|
+
function emitProgress() {
|
|
96
|
+
if (broadcast)
|
|
97
|
+
broadcast("ssh:install:progress", { ...job });
|
|
98
|
+
}
|
|
99
|
+
function updateStep(stepIdx, status, message) {
|
|
100
|
+
job.steps[stepIdx].status = status;
|
|
101
|
+
if (message)
|
|
102
|
+
job.steps[stepIdx].message = message;
|
|
103
|
+
job.currentStep = stepIdx;
|
|
104
|
+
emitProgress();
|
|
105
|
+
}
|
|
106
|
+
function fail(stepIdx, error) {
|
|
107
|
+
updateStep(stepIdx, "failed", error);
|
|
108
|
+
job.status = "failed";
|
|
109
|
+
job.error = error;
|
|
110
|
+
job.completedAt = new Date().toISOString();
|
|
111
|
+
if (broadcast)
|
|
112
|
+
broadcast("ssh:install:failed", { ...job });
|
|
113
|
+
sshClient.end();
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const connectConfig = await buildConnectConfig(connConfig);
|
|
117
|
+
// ── Step 0: Connect ──────────────────────────────────────────────
|
|
118
|
+
updateStep(0, "running");
|
|
119
|
+
await new Promise((resolve, reject) => {
|
|
120
|
+
sshClient.on("ready", () => resolve());
|
|
121
|
+
sshClient.on("error", (err) => reject(err));
|
|
122
|
+
sshClient.connect({ ...connectConfig, readyTimeout: 15_000 });
|
|
123
|
+
});
|
|
124
|
+
updateStep(0, "completed", "Connected successfully");
|
|
125
|
+
// ── Step 1: Detect OS and architecture ───────────────────────────
|
|
126
|
+
updateStep(1, "running");
|
|
127
|
+
const { stdout: osInfo } = await sshExec(sshClient, "uname -s && uname -m");
|
|
128
|
+
const [osName, arch] = osInfo.split("\n");
|
|
129
|
+
updateStep(1, "completed", `${osName} ${arch}`);
|
|
130
|
+
if (osName !== "Linux" && osName !== "Darwin") {
|
|
131
|
+
return fail(1, `Unsupported OS: ${osName}. Only Linux and macOS.`);
|
|
132
|
+
}
|
|
133
|
+
// ── Step 2: Install Bun ──────────────────────────────────────────
|
|
134
|
+
updateStep(2, "running");
|
|
135
|
+
const { code: bunCheck } = await sshExec(sshClient, `${REMOTE_PATH} && which bun 2>/dev/null`);
|
|
136
|
+
if (bunCheck !== 0) {
|
|
137
|
+
// Install prerequisites (unzip) — try without sudo first
|
|
138
|
+
updateStep(2, "running", "Installing prerequisites...");
|
|
139
|
+
await sshExec(sshClient, "which unzip >/dev/null 2>&1 || " +
|
|
140
|
+
"(apt-get update -qq && apt-get install -y -qq unzip 2>/dev/null || " +
|
|
141
|
+
"sudo apt-get update -qq && sudo apt-get install -y -qq unzip 2>/dev/null || " +
|
|
142
|
+
"yum install -y -q unzip 2>/dev/null || " +
|
|
143
|
+
"sudo yum install -y -q unzip 2>/dev/null || " +
|
|
144
|
+
"apk add --quiet unzip 2>/dev/null || true)", 60_000);
|
|
145
|
+
updateStep(2, "running", "Installing Bun...");
|
|
146
|
+
const { code: bunInstall, stderr: bunErr } = await sshExec(sshClient, `curl -fsSL https://bun.sh/install | bash && ${REMOTE_PATH} && bun --version`, 120_000);
|
|
147
|
+
if (bunInstall !== 0) {
|
|
148
|
+
return fail(2, `Failed to install Bun: ${bunErr}`);
|
|
149
|
+
}
|
|
150
|
+
updateStep(2, "completed", "Bun installed");
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
updateStep(2, "skipped", "Bun already installed");
|
|
154
|
+
}
|
|
155
|
+
// ── Step 3: Install vibecontrols-agent ────────────────────────────
|
|
156
|
+
updateStep(3, "running");
|
|
157
|
+
const { code: agentCheck } = await sshExec(sshClient, `${REMOTE_PATH} && which vibe 2>/dev/null`);
|
|
158
|
+
if (agentCheck !== 0) {
|
|
159
|
+
updateStep(3, "running", `Installing agent (registry: ${registryUrl})...`);
|
|
160
|
+
// Strategy 1: Try bun install -g from registry
|
|
161
|
+
const { code: installCode } = await sshExec(sshClient, `${REMOTE_PATH} && bun install -g @vibecontrols/vibecontrols-agent --registry ${registryUrl}`, 120_000);
|
|
162
|
+
if (installCode !== 0) {
|
|
163
|
+
// Strategy 2: npm pack locally, SCP tarball, extract on remote
|
|
164
|
+
updateStep(3, "running", "Registry unavailable, transferring directly...");
|
|
165
|
+
try {
|
|
166
|
+
const agentDir = hostServices.getConfig?.("agent:packageDir") ||
|
|
167
|
+
`${process.env.HOME}/products/vibecontrols/vibecontrols-agent`;
|
|
168
|
+
const packResult = Bun.spawnSync(["npm", "pack", "--pack-destination", "/tmp"], { cwd: agentDir, stdout: "pipe", stderr: "pipe" });
|
|
169
|
+
const tgzName = packResult.stdout
|
|
170
|
+
.toString()
|
|
171
|
+
.trim()
|
|
172
|
+
.split("\n")
|
|
173
|
+
.pop();
|
|
174
|
+
const tgzPath = tgzName ? `/tmp/${tgzName}` : "";
|
|
175
|
+
if (!tgzPath || !(await Bun.file(tgzPath).exists())) {
|
|
176
|
+
return fail(3, "Failed to pack agent for transfer");
|
|
177
|
+
}
|
|
178
|
+
// SCP to remote
|
|
179
|
+
const scpArgs = [
|
|
180
|
+
"-o", "StrictHostKeyChecking=accept-new",
|
|
181
|
+
"-P", String(connConfig.port),
|
|
182
|
+
];
|
|
183
|
+
if (connConfig.privateKeyPath) {
|
|
184
|
+
scpArgs.push("-i", connConfig.privateKeyPath);
|
|
185
|
+
}
|
|
186
|
+
scpArgs.push(tgzPath, `${connConfig.username}@${connConfig.host}:/tmp/vibecontrols-agent.tgz`);
|
|
187
|
+
const scpResult = Bun.spawnSync(["scp", ...scpArgs]);
|
|
188
|
+
if (scpResult.exitCode !== 0) {
|
|
189
|
+
return fail(3, "Failed to transfer agent package via SCP");
|
|
190
|
+
}
|
|
191
|
+
// Extract and set up on remote
|
|
192
|
+
const { code: setupCode2, stderr: setupErr2 } = await sshExec(sshClient, `${REMOTE_PATH} && ` +
|
|
193
|
+
`mkdir -p $HOME/.vibecontrols/agent && ` +
|
|
194
|
+
`cd $HOME/.vibecontrols/agent && ` +
|
|
195
|
+
`tar xzf /tmp/vibecontrols-agent.tgz --strip-components=1 && ` +
|
|
196
|
+
`bun install --production --ignore-scripts 2>/dev/null; ` +
|
|
197
|
+
`mkdir -p $HOME/.local/bin && ` +
|
|
198
|
+
`ln -sf $HOME/.vibecontrols/agent/dist/cli.js $HOME/.local/bin/vibe && ` +
|
|
199
|
+
`chmod +x $HOME/.vibecontrols/agent/dist/cli.js && ` +
|
|
200
|
+
`rm -f /tmp/vibecontrols-agent.tgz`, 120_000);
|
|
201
|
+
if (setupCode2 !== 0) {
|
|
202
|
+
return fail(3, `Failed to set up agent: ${setupErr2?.slice(0, 200)}`);
|
|
203
|
+
}
|
|
204
|
+
// Verify vibe is available
|
|
205
|
+
const { code: vibeCheck } = await sshExec(sshClient, `${REMOTE_PATH} && which vibe`);
|
|
206
|
+
if (vibeCheck !== 0) {
|
|
207
|
+
return fail(3, "Agent installed but 'vibe' command not found in PATH");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (transferErr) {
|
|
211
|
+
return fail(3, `Failed to install agent: ${transferErr instanceof Error ? transferErr.message : "transfer failed"}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
updateStep(3, "completed", "Agent installed");
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
updateStep(3, "skipped", "Agent already installed");
|
|
218
|
+
}
|
|
219
|
+
// ── Step 4: Configure agent ──────────────────────────────────────
|
|
220
|
+
updateStep(4, "running");
|
|
221
|
+
// Check if cloudflared is available
|
|
222
|
+
const { code: cfCheck } = await sshExec(sshClient, "which cloudflared 2>/dev/null");
|
|
223
|
+
const hasCloudflared = cfCheck === 0;
|
|
224
|
+
const { code: setupCode, stderr: setupErr } = await sshExec(sshClient, `${REMOTE_PATH} && vibe setup --non-interactive --port ${agentPort}`, 30_000);
|
|
225
|
+
if (setupCode !== 0) {
|
|
226
|
+
updateStep(4, "completed", setupErr
|
|
227
|
+
? `Warning: ${setupErr.slice(0, 120)}`
|
|
228
|
+
: "Configured with defaults");
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
updateStep(4, "completed", "Agent configured");
|
|
232
|
+
}
|
|
233
|
+
// ── Step 5: Start agent daemon ───────────────────────────────────
|
|
234
|
+
updateStep(5, "running");
|
|
235
|
+
// Check if agent already running on this port
|
|
236
|
+
const { code: portCheck } = await sshExec(sshClient, `curl -sf http://127.0.0.1:${agentPort}/health`, 5_000);
|
|
237
|
+
if (portCheck === 0) {
|
|
238
|
+
updateStep(5, "skipped", "Agent already running on this port");
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
const tunnelEnv = hasCloudflared ? "" : "AGENT_TUNNEL=false ";
|
|
242
|
+
// Try vibe start first, fall back to direct bun run for extraction-based installs
|
|
243
|
+
const { code: startCode, stderr: startErr } = await sshExec(sshClient, `${REMOTE_PATH} && ${tunnelEnv}PORT=${agentPort} nohup vibe start > /dev/null 2>&1 & sleep 3 && echo started || ` +
|
|
244
|
+
`(cd $HOME/.vibecontrols/agent && ${tunnelEnv}PORT=${agentPort} nohup bun run dist/index.js > /tmp/vibe-agent.log 2>&1 & sleep 3 && echo started)`, 30_000);
|
|
245
|
+
if (startCode !== 0 && !startErr.includes("already running")) {
|
|
246
|
+
return fail(5, `Failed to start agent: ${startErr}`);
|
|
247
|
+
}
|
|
248
|
+
updateStep(5, "completed", "Agent started");
|
|
249
|
+
}
|
|
250
|
+
// ── Step 6: Verify health ────────────────────────────────────────
|
|
251
|
+
updateStep(6, "running");
|
|
252
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
253
|
+
let healthy = false;
|
|
254
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
255
|
+
const { code: healthCode } = await sshExec(sshClient, `curl -sf http://127.0.0.1:${agentPort}/health`, 5_000);
|
|
256
|
+
if (healthCode === 0) {
|
|
257
|
+
healthy = true;
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
261
|
+
}
|
|
262
|
+
if (!healthy) {
|
|
263
|
+
return fail(6, "Agent health check failed after 8 attempts");
|
|
264
|
+
}
|
|
265
|
+
updateStep(6, "completed", "Agent is healthy");
|
|
266
|
+
// ── Step 7: Retrieve agent details ───────────────────────────────
|
|
267
|
+
updateStep(7, "running");
|
|
268
|
+
let apiKey;
|
|
269
|
+
let tunnelUrl;
|
|
270
|
+
let hostname = connConfig.host;
|
|
271
|
+
let platform = "linux";
|
|
272
|
+
let architecture = "x86_64";
|
|
273
|
+
// Get API key
|
|
274
|
+
const { stdout: keyOut } = await sshExec(sshClient, `curl -sf http://127.0.0.1:${agentPort}/api/agent/api-key`, 5_000).catch(() => ({ stdout: "", stderr: "", code: 1 }));
|
|
275
|
+
if (keyOut) {
|
|
276
|
+
try {
|
|
277
|
+
apiKey = JSON.parse(keyOut).apiKey;
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
/* ignore */
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Get identity
|
|
284
|
+
const { stdout: identityOut } = await sshExec(sshClient, `curl -sf http://127.0.0.1:${agentPort}/api/agent/identity`, 5_000).catch(() => ({ stdout: "", stderr: "", code: 1 }));
|
|
285
|
+
if (identityOut) {
|
|
286
|
+
try {
|
|
287
|
+
const id = JSON.parse(identityOut);
|
|
288
|
+
hostname = id.hostname || hostname;
|
|
289
|
+
platform = id.platform || platform;
|
|
290
|
+
architecture = id.arch || architecture;
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
/* ignore */
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Poll for tunnel URL (if cloudflared is present)
|
|
297
|
+
if (hasCloudflared) {
|
|
298
|
+
for (let i = 0; i < 6; i++) {
|
|
299
|
+
await new Promise((r) => setTimeout(r, 5000));
|
|
300
|
+
const { stdout: statusOut } = await sshExec(sshClient, `curl -sf http://127.0.0.1:${agentPort}/api/agent/status`, 5_000).catch(() => ({ stdout: "", stderr: "", code: 1 }));
|
|
301
|
+
if (statusOut) {
|
|
302
|
+
try {
|
|
303
|
+
const s = JSON.parse(statusOut);
|
|
304
|
+
if (s.tunnelUrl) {
|
|
305
|
+
tunnelUrl = s.tunnelUrl;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
/* ignore */
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
updateStep(7, "completed", tunnelUrl ? `Tunnel: ${tunnelUrl}` : "Details retrieved (no tunnel)");
|
|
316
|
+
job.result = {
|
|
317
|
+
agentUrl: tunnelUrl || `http://${connConfig.host}:${agentPort}`,
|
|
318
|
+
agentPort,
|
|
319
|
+
apiKey,
|
|
320
|
+
tunnelUrl,
|
|
321
|
+
hostname,
|
|
322
|
+
platform,
|
|
323
|
+
architecture,
|
|
324
|
+
};
|
|
325
|
+
// ── Step 8: Auto-register with backend ───────────────────────────
|
|
326
|
+
if (options.autoRegister &&
|
|
327
|
+
hostServices.isGatewayConfigured?.() &&
|
|
328
|
+
hostServices.workspaceQuery) {
|
|
329
|
+
updateStep(8, "running");
|
|
330
|
+
const workspaceId = hostServices.getWorkspaceId?.();
|
|
331
|
+
if (!workspaceId) {
|
|
332
|
+
updateStep(8, "skipped", "No workspace ID configured");
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
try {
|
|
336
|
+
const agentName = options.agentName || hostname || connConfig.serverName;
|
|
337
|
+
const mutation = `
|
|
338
|
+
mutation RegisterInstalledAgent($workspaceId: ID!, $input: RegisterInstalledAgentInput!) {
|
|
339
|
+
registerInstalledAgent(workspaceId: $workspaceId, input: $input) {
|
|
340
|
+
id name hostname
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
`;
|
|
344
|
+
const result = await hostServices.workspaceQuery(mutation, {
|
|
345
|
+
workspaceId,
|
|
346
|
+
input: {
|
|
347
|
+
name: agentName,
|
|
348
|
+
hostname,
|
|
349
|
+
platform,
|
|
350
|
+
architecture,
|
|
351
|
+
apiUrl: `http://${connConfig.host}:${agentPort}`,
|
|
352
|
+
tunnelUrl: tunnelUrl || undefined,
|
|
353
|
+
agentApiKey: apiKey || undefined,
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
if (result.errors?.length) {
|
|
357
|
+
updateStep(8, "failed", result.errors[0].message);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
const agentRecord = result.data?.registerInstalledAgent;
|
|
361
|
+
if (agentRecord) {
|
|
362
|
+
job.result.backendAgentId = agentRecord.id;
|
|
363
|
+
// Push gateway auth to the remote agent so it can
|
|
364
|
+
// authenticate with the backend independently
|
|
365
|
+
if (apiKey && hostServices.getConfig) {
|
|
366
|
+
const gwPayload = JSON.stringify({
|
|
367
|
+
tenantApiUrl: hostServices.getConfig("gateway-auth:globalGatewayUrl") ||
|
|
368
|
+
"",
|
|
369
|
+
workspacesApiUrl: hostServices.getConfig("gateway-auth:workspaceGatewayUrl") || "",
|
|
370
|
+
appClientId: hostServices.getConfig("gateway-auth:clientId") || "",
|
|
371
|
+
appClientSecret: hostServices.getConfig("gateway-auth:clientSecret") || "",
|
|
372
|
+
workspaceId,
|
|
373
|
+
agentRecordId: agentRecord.id,
|
|
374
|
+
});
|
|
375
|
+
// Write to a temp file to avoid shell escaping issues
|
|
376
|
+
await sshExec(sshClient, `echo '${gwPayload.replace(/'/g, "'\\''")}' > /tmp/.vc-gw-auth.json && ` +
|
|
377
|
+
`curl -sf -X POST http://127.0.0.1:${agentPort}/api/agent/gateway-auth ` +
|
|
378
|
+
`-H 'Content-Type: application/json' ` +
|
|
379
|
+
`-H 'x-agent-api-key: ${apiKey}' ` +
|
|
380
|
+
`-d @/tmp/.vc-gw-auth.json && ` +
|
|
381
|
+
`rm -f /tmp/.vc-gw-auth.json`, 15_000).catch(() => {
|
|
382
|
+
/* gateway push is best-effort */
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
updateStep(8, "completed", `Registered as "${agentRecord.name}" (${agentRecord.id.slice(0, 8)})`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch (regErr) {
|
|
390
|
+
updateStep(8, "failed", regErr instanceof Error ? regErr.message : "Registration failed");
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
updateStep(8, "skipped", "Auto-registration not requested or gateway not configured");
|
|
396
|
+
}
|
|
397
|
+
// Done
|
|
398
|
+
job.status = "completed";
|
|
399
|
+
job.completedAt = new Date().toISOString();
|
|
400
|
+
if (broadcast)
|
|
401
|
+
broadcast("ssh:install:complete", { ...job });
|
|
402
|
+
sshClient.end();
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
const errMsg = error instanceof Error ? error.message : "Unknown error";
|
|
406
|
+
job.status = "failed";
|
|
407
|
+
job.error = errMsg;
|
|
408
|
+
job.completedAt = new Date().toISOString();
|
|
409
|
+
if (broadcast)
|
|
410
|
+
broadcast("ssh:install:failed", { ...job });
|
|
411
|
+
sshClient.end();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// ---------------------------------------------------------------------------
|
|
415
|
+
// Route factory
|
|
416
|
+
// ---------------------------------------------------------------------------
|
|
417
|
+
export function createRemoteAgentInstallRoutes(hostServices) {
|
|
418
|
+
const { storage, broadcast } = hostServices;
|
|
419
|
+
return (new Elysia({ prefix: "/api/ssh/agent-install" })
|
|
420
|
+
// -----------------------------------------------------------------------
|
|
421
|
+
// GET /api/ssh/agent-install/jobs — list all install jobs
|
|
422
|
+
// -----------------------------------------------------------------------
|
|
423
|
+
.get("/jobs", () => {
|
|
424
|
+
return { jobs: Array.from(installJobs.values()) };
|
|
425
|
+
})
|
|
426
|
+
// -----------------------------------------------------------------------
|
|
427
|
+
// GET /api/ssh/agent-install/jobs/:id — get a specific job
|
|
428
|
+
// -----------------------------------------------------------------------
|
|
429
|
+
.get("/jobs/:id", ({ params, set }) => {
|
|
430
|
+
const job = installJobs.get(params.id);
|
|
431
|
+
if (!job) {
|
|
432
|
+
set.status = 404;
|
|
433
|
+
return { error: "Install job not found" };
|
|
434
|
+
}
|
|
435
|
+
return { job };
|
|
436
|
+
})
|
|
437
|
+
// -----------------------------------------------------------------------
|
|
438
|
+
// POST /api/ssh/agent-install/start — begin remote agent installation
|
|
439
|
+
// -----------------------------------------------------------------------
|
|
440
|
+
.post("/start", async ({ body, set }) => {
|
|
441
|
+
const { connectionId, agentPort = 3005, autoRegister = false, agentName, } = body;
|
|
442
|
+
const connConfig = await getConnectionById(storage, connectionId);
|
|
443
|
+
if (!connConfig) {
|
|
444
|
+
set.status = 404;
|
|
445
|
+
return { error: "SSH connection not found" };
|
|
446
|
+
}
|
|
447
|
+
const jobId = globalThis.crypto.randomUUID();
|
|
448
|
+
const job = {
|
|
449
|
+
id: jobId,
|
|
450
|
+
connectionId,
|
|
451
|
+
status: "running",
|
|
452
|
+
steps: INSTALL_STEPS.map((s) => ({
|
|
453
|
+
name: s.name,
|
|
454
|
+
status: "pending",
|
|
455
|
+
})),
|
|
456
|
+
currentStep: 0,
|
|
457
|
+
startedAt: new Date().toISOString(),
|
|
458
|
+
};
|
|
459
|
+
installJobs.set(jobId, job);
|
|
460
|
+
// Run installation asynchronously
|
|
461
|
+
runInstallation(job, connConfig, agentPort, hostServices, {
|
|
462
|
+
autoRegister,
|
|
463
|
+
agentName,
|
|
464
|
+
}).catch(() => {
|
|
465
|
+
// Errors handled inside runInstallation
|
|
466
|
+
});
|
|
467
|
+
return { jobId, status: "running" };
|
|
468
|
+
})
|
|
469
|
+
// -----------------------------------------------------------------------
|
|
470
|
+
// POST /api/ssh/agent-install/batch-start — install on multiple servers
|
|
471
|
+
// -----------------------------------------------------------------------
|
|
472
|
+
.post("/batch-start", async ({ body, set }) => {
|
|
473
|
+
const { connectionIds, agentPort = 3005, autoRegister = false, } = body;
|
|
474
|
+
if (!connectionIds?.length) {
|
|
475
|
+
set.status = 400;
|
|
476
|
+
return { error: "No connection IDs provided" };
|
|
477
|
+
}
|
|
478
|
+
const jobs = [];
|
|
479
|
+
for (const connectionId of connectionIds) {
|
|
480
|
+
const connConfig = await getConnectionById(storage, connectionId);
|
|
481
|
+
if (!connConfig)
|
|
482
|
+
continue;
|
|
483
|
+
const jobId = globalThis.crypto.randomUUID();
|
|
484
|
+
const job = {
|
|
485
|
+
id: jobId,
|
|
486
|
+
connectionId,
|
|
487
|
+
status: "running",
|
|
488
|
+
steps: INSTALL_STEPS.map((s) => ({
|
|
489
|
+
name: s.name,
|
|
490
|
+
status: "pending",
|
|
491
|
+
})),
|
|
492
|
+
currentStep: 0,
|
|
493
|
+
startedAt: new Date().toISOString(),
|
|
494
|
+
};
|
|
495
|
+
installJobs.set(jobId, job);
|
|
496
|
+
jobs.push({ connectionId, jobId });
|
|
497
|
+
// Run each installation asynchronously (in parallel)
|
|
498
|
+
runInstallation(job, connConfig, agentPort, hostServices, {
|
|
499
|
+
autoRegister,
|
|
500
|
+
}).catch(() => { });
|
|
501
|
+
}
|
|
502
|
+
return { jobs, total: jobs.length };
|
|
503
|
+
})
|
|
504
|
+
// -----------------------------------------------------------------------
|
|
505
|
+
// POST /api/ssh/agent-install/uninstall — uninstall agent from remote
|
|
506
|
+
// -----------------------------------------------------------------------
|
|
507
|
+
.post("/uninstall", async ({ body, set }) => {
|
|
508
|
+
const { connectionId } = body;
|
|
509
|
+
const connConfig = await getConnectionById(storage, connectionId);
|
|
510
|
+
if (!connConfig) {
|
|
511
|
+
set.status = 404;
|
|
512
|
+
return { error: "SSH connection not found" };
|
|
513
|
+
}
|
|
514
|
+
const sshClient = new Client();
|
|
515
|
+
const connectConfig = await buildConnectConfig(connConfig);
|
|
516
|
+
await new Promise((resolve, reject) => {
|
|
517
|
+
sshClient.on("ready", () => resolve());
|
|
518
|
+
sshClient.on("error", (err) => reject(err));
|
|
519
|
+
sshClient.connect({ ...connectConfig, readyTimeout: 15_000 });
|
|
520
|
+
});
|
|
521
|
+
try {
|
|
522
|
+
// Stop running agent processes
|
|
523
|
+
await sshExec(sshClient, 'pkill -f "bun.*index.ts" 2>/dev/null; pkill -f "vibe" 2>/dev/null', 10_000).catch(() => { });
|
|
524
|
+
// Remove agent files
|
|
525
|
+
await sshExec(sshClient, "rm -rf $HOME/.vibecontrols/agent", 10_000);
|
|
526
|
+
// Remove symlink
|
|
527
|
+
await sshExec(sshClient, "rm -f $HOME/.local/bin/vibe", 10_000);
|
|
528
|
+
// Remove vibecontrols state
|
|
529
|
+
await sshExec(sshClient, "rm -rf $HOME/.vibecontrols", 10_000);
|
|
530
|
+
}
|
|
531
|
+
finally {
|
|
532
|
+
sshClient.end();
|
|
533
|
+
}
|
|
534
|
+
return { success: true, message: "Agent uninstalled" };
|
|
535
|
+
}));
|
|
536
|
+
}
|
|
537
|
+
//# sourceMappingURL=remote-agent-install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-agent-install.js","sourceRoot":"","sources":["../../src/routes/remote-agent-install.ts"],"names":[],"mappings":"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"}
|