@burdenoff/vibe-agent 2.1.1 → 2.2.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/dist/app-6mmbmske.js +1166 -0
- package/dist/app-6mmbmske.js.map +19 -0
- package/dist/cli.js +152 -2036
- package/dist/cli.js.map +6 -28
- package/dist/index-05qfwz8r.js +122 -0
- package/dist/index-05qfwz8r.js.map +10 -0
- package/dist/index-30p492yv.js +294 -0
- package/dist/index-30p492yv.js.map +13 -0
- package/dist/index-3v78e2cn.js +373 -0
- package/dist/index-3v78e2cn.js.map +11 -0
- package/dist/index-41m1exz7.js +269 -0
- package/dist/index-41m1exz7.js.map +13 -0
- package/dist/index-88ym10cs.js +194 -0
- package/dist/index-88ym10cs.js.map +10 -0
- package/dist/index-9tgyd3ep.js +513 -0
- package/dist/index-9tgyd3ep.js.map +19 -0
- package/dist/index-a9g7hbj9.js +229 -0
- package/dist/index-a9g7hbj9.js.map +13 -0
- package/dist/index-atjhkm74.js +149 -0
- package/dist/index-atjhkm74.js.map +10 -0
- package/dist/index-c7zy3n33.js +167 -0
- package/dist/index-c7zy3n33.js.map +13 -0
- package/dist/index-hefqxwht.js +270 -0
- package/dist/index-hefqxwht.js.map +13 -0
- package/dist/index-k9hb0b93.js +280 -0
- package/dist/index-k9hb0b93.js.map +13 -0
- package/dist/index-npmvh1x9.js +385 -0
- package/dist/index-npmvh1x9.js.map +13 -0
- package/dist/index-q4ytrfx7.js +286 -0
- package/dist/index-q4ytrfx7.js.map +13 -0
- package/dist/index-qthbtg9n.js +302 -0
- package/dist/index-qthbtg9n.js.map +13 -0
- package/dist/index-rdm6e3rr.js +587 -0
- package/dist/index-rdm6e3rr.js.map +13 -0
- package/dist/index-wdtxbebz.js +339 -0
- package/dist/index-wdtxbebz.js.map +13 -0
- package/dist/{app-31chs2a1.js → index-wr0mkm57.js} +8 -3201
- package/dist/{app-31chs2a1.js.map → index-wr0mkm57.js.map} +4 -25
- package/dist/index-xmeskdnb.js +292 -0
- package/dist/index-xmeskdnb.js.map +11 -0
- package/dist/index-xn4tarcd.js +287 -0
- package/dist/index-xn4tarcd.js.map +13 -0
- package/dist/index.js +9 -6
- package/dist/index.js.map +2 -2
- package/dist/{package-hb6db316.js → package-ywexp6sg.js} +3 -3
- package/dist/{package-hb6db316.js.map → package-ywexp6sg.js.map} +1 -1
- package/dist/plugin-system-v7a7xnhk.js +475 -0
- package/dist/plugin-system-v7a7xnhk.js.map +10 -0
- package/package.json +1 -1
- package/dist/index-t06ktmx9.js +0 -216
- package/dist/index-t06ktmx9.js.map +0 -11
- package/dist/plugin-system-bg1pzjj9.js +0 -450
- package/dist/plugin-system-bg1pzjj9.js.map +0 -11
package/dist/cli.js
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
3
|
import {
|
|
4
|
-
ServiceRegistry
|
|
4
|
+
ServiceRegistry
|
|
5
|
+
} from "./index-atjhkm74.js";
|
|
6
|
+
import {
|
|
7
|
+
ServiceManager,
|
|
5
8
|
checkDependencies,
|
|
6
9
|
installDependencies
|
|
7
|
-
} from "./index-
|
|
10
|
+
} from "./index-3v78e2cn.js";
|
|
11
|
+
import {
|
|
12
|
+
logger
|
|
13
|
+
} from "./index-88ym10cs.js";
|
|
14
|
+
import {
|
|
15
|
+
blank,
|
|
16
|
+
colors,
|
|
17
|
+
fail,
|
|
18
|
+
formatStatus,
|
|
19
|
+
formatTable,
|
|
20
|
+
header,
|
|
21
|
+
icons,
|
|
22
|
+
info,
|
|
23
|
+
kv,
|
|
24
|
+
printAgentDetails,
|
|
25
|
+
success,
|
|
26
|
+
timeAgo,
|
|
27
|
+
warn
|
|
28
|
+
} from "./index-xmeskdnb.js";
|
|
8
29
|
import {
|
|
9
30
|
__commonJS,
|
|
10
31
|
__require,
|
|
11
32
|
__toESM
|
|
12
33
|
} from "./index-g8dczzvv.js";
|
|
13
34
|
import {
|
|
14
|
-
PluginManager
|
|
15
|
-
|
|
16
|
-
} from "./plugin-system-bg1pzjj9.js";
|
|
35
|
+
PluginManager
|
|
36
|
+
} from "./plugin-system-v7a7xnhk.js";
|
|
17
37
|
|
|
18
38
|
// node_modules/commander/lib/error.js
|
|
19
39
|
var require_error = __commonJS((exports) => {
|
|
@@ -2125,537 +2145,14 @@ var {
|
|
|
2125
2145
|
} = import__.default;
|
|
2126
2146
|
|
|
2127
2147
|
// src/cli.ts
|
|
2128
|
-
import { readFileSync as
|
|
2129
|
-
import { join as
|
|
2130
|
-
import { fileURLToPath
|
|
2148
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
2149
|
+
import { join as join3, dirname } from "path";
|
|
2150
|
+
import { fileURLToPath } from "url";
|
|
2131
2151
|
|
|
2132
2152
|
// src/cli/commands/start.cmd.ts
|
|
2133
|
-
import { existsSync
|
|
2134
|
-
import { join
|
|
2135
|
-
import { homedir as homedir2 } from "os";
|
|
2136
|
-
|
|
2137
|
-
// src/cli/utils/api-client.ts
|
|
2138
|
-
var DEFAULT_AGENT_URL = "http://localhost:3005";
|
|
2139
|
-
var _apiKeyCache = new Map;
|
|
2140
|
-
function getAgentUrl(opts) {
|
|
2141
|
-
return opts?.agentUrl || process.env.AGENT_URL || DEFAULT_AGENT_URL;
|
|
2142
|
-
}
|
|
2143
|
-
async function resolveApiKey(agentUrl) {
|
|
2144
|
-
if (process.env.AGENT_API_KEY)
|
|
2145
|
-
return process.env.AGENT_API_KEY;
|
|
2146
|
-
if (_apiKeyCache.has(agentUrl))
|
|
2147
|
-
return _apiKeyCache.get(agentUrl);
|
|
2148
|
-
try {
|
|
2149
|
-
const res = await fetch(`${agentUrl}/api/agent/api-key`);
|
|
2150
|
-
if (res.ok) {
|
|
2151
|
-
const data = await res.json();
|
|
2152
|
-
if (data.apiKey) {
|
|
2153
|
-
_apiKeyCache.set(agentUrl, data.apiKey);
|
|
2154
|
-
return data.apiKey;
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
} catch {}
|
|
2158
|
-
return;
|
|
2159
|
-
}
|
|
2160
|
-
async function agentFetch(agentUrl, path, options = {}) {
|
|
2161
|
-
const apiKey = await resolveApiKey(agentUrl);
|
|
2162
|
-
const headers = {
|
|
2163
|
-
...options.body ? { "Content-Type": "application/json" } : {},
|
|
2164
|
-
...apiKey ? { "x-agent-api-key": apiKey } : {},
|
|
2165
|
-
...options.headers ?? {}
|
|
2166
|
-
};
|
|
2167
|
-
const res = await fetch(`${agentUrl}${path}`, { ...options, headers });
|
|
2168
|
-
const data = await res.json().catch(() => ({}));
|
|
2169
|
-
return { ok: res.ok, status: res.status, data };
|
|
2170
|
-
}
|
|
2171
|
-
async function apiGet(agentUrl, path) {
|
|
2172
|
-
const { ok, status, data } = await agentFetch(agentUrl, path);
|
|
2173
|
-
if (!ok) {
|
|
2174
|
-
const errorMsg = data?.error || data?.message || `Agent returned ${status}`;
|
|
2175
|
-
throw new Error(String(errorMsg));
|
|
2176
|
-
}
|
|
2177
|
-
return data;
|
|
2178
|
-
}
|
|
2179
|
-
async function apiPost(agentUrl, path, body) {
|
|
2180
|
-
const { ok, status, data } = await agentFetch(agentUrl, path, {
|
|
2181
|
-
method: "POST",
|
|
2182
|
-
body: body != null ? JSON.stringify(body) : undefined
|
|
2183
|
-
});
|
|
2184
|
-
if (!ok) {
|
|
2185
|
-
const errorMsg = data?.error || data?.message || `Agent returned ${status}`;
|
|
2186
|
-
throw new Error(String(errorMsg));
|
|
2187
|
-
}
|
|
2188
|
-
return data;
|
|
2189
|
-
}
|
|
2190
|
-
async function apiPut(agentUrl, path, body) {
|
|
2191
|
-
const { ok, status, data } = await agentFetch(agentUrl, path, {
|
|
2192
|
-
method: "PUT",
|
|
2193
|
-
body: body != null ? JSON.stringify(body) : undefined
|
|
2194
|
-
});
|
|
2195
|
-
if (!ok) {
|
|
2196
|
-
const errorMsg = data?.error || data?.message || `Agent returned ${status}`;
|
|
2197
|
-
throw new Error(String(errorMsg));
|
|
2198
|
-
}
|
|
2199
|
-
return data;
|
|
2200
|
-
}
|
|
2201
|
-
async function apiDelete(agentUrl, path) {
|
|
2202
|
-
const { ok, status, data } = await agentFetch(agentUrl, path, {
|
|
2203
|
-
method: "DELETE"
|
|
2204
|
-
});
|
|
2205
|
-
if (!ok) {
|
|
2206
|
-
const errorMsg = data?.error || data?.message || `Agent returned ${status}`;
|
|
2207
|
-
throw new Error(String(errorMsg));
|
|
2208
|
-
}
|
|
2209
|
-
return data;
|
|
2210
|
-
}
|
|
2211
|
-
// src/cli/utils/format.ts
|
|
2212
|
-
var colors = {
|
|
2213
|
-
bold: (text) => `\x1B[1m${text}\x1B[22m`,
|
|
2214
|
-
dim: (text) => `\x1B[2m${text}\x1B[22m`,
|
|
2215
|
-
italic: (text) => `\x1B[3m${text}\x1B[23m`,
|
|
2216
|
-
underline: (text) => `\x1B[4m${text}\x1B[24m`,
|
|
2217
|
-
red: (text) => `\x1B[31m${text}\x1B[39m`,
|
|
2218
|
-
green: (text) => `\x1B[32m${text}\x1B[39m`,
|
|
2219
|
-
yellow: (text) => `\x1B[33m${text}\x1B[39m`,
|
|
2220
|
-
blue: (text) => `\x1B[34m${text}\x1B[39m`,
|
|
2221
|
-
magenta: (text) => `\x1B[35m${text}\x1B[39m`,
|
|
2222
|
-
cyan: (text) => `\x1B[36m${text}\x1B[39m`,
|
|
2223
|
-
white: (text) => `\x1B[37m${text}\x1B[39m`,
|
|
2224
|
-
gray: (text) => `\x1B[90m${text}\x1B[39m`,
|
|
2225
|
-
brightRed: (text) => `\x1B[91m${text}\x1B[39m`,
|
|
2226
|
-
brightGreen: (text) => `\x1B[92m${text}\x1B[39m`,
|
|
2227
|
-
brightYellow: (text) => `\x1B[93m${text}\x1B[39m`,
|
|
2228
|
-
brightBlue: (text) => `\x1B[94m${text}\x1B[39m`,
|
|
2229
|
-
reset: "\x1B[0m"
|
|
2230
|
-
};
|
|
2231
|
-
var icons = {
|
|
2232
|
-
success: colors.green("\u2713"),
|
|
2233
|
-
error: colors.red("\u2717"),
|
|
2234
|
-
warning: colors.yellow("\u26A0"),
|
|
2235
|
-
info: colors.blue("\u25CF"),
|
|
2236
|
-
running: colors.green("\u25CF"),
|
|
2237
|
-
stopped: colors.red("\u25CB"),
|
|
2238
|
-
pending: colors.yellow("\u25CC"),
|
|
2239
|
-
arrow: colors.gray("\u2192"),
|
|
2240
|
-
bullet: colors.gray("\u2022"),
|
|
2241
|
-
check: colors.green("\u2714")
|
|
2242
|
-
};
|
|
2243
|
-
function fail(msg) {
|
|
2244
|
-
console.error(`${colors.red("Error:")} ${msg}`);
|
|
2245
|
-
process.exit(1);
|
|
2246
|
-
}
|
|
2247
|
-
function success(msg) {
|
|
2248
|
-
console.log(` ${icons.success} ${msg}`);
|
|
2249
|
-
}
|
|
2250
|
-
function warn(msg) {
|
|
2251
|
-
console.log(` ${icons.warning} ${msg}`);
|
|
2252
|
-
}
|
|
2253
|
-
function info(msg) {
|
|
2254
|
-
console.log(` ${icons.info} ${msg}`);
|
|
2255
|
-
}
|
|
2256
|
-
function header(title) {
|
|
2257
|
-
console.log(`
|
|
2258
|
-
${colors.bold(`\u2500\u2500 ${title} \u2500\u2500`)}
|
|
2259
|
-
`);
|
|
2260
|
-
}
|
|
2261
|
-
function kv(key, value) {
|
|
2262
|
-
const display = value === null || value === undefined ? colors.gray("(none)") : String(value);
|
|
2263
|
-
console.log(` ${colors.bold(key.padEnd(14))} ${display}`);
|
|
2264
|
-
}
|
|
2265
|
-
function blank() {
|
|
2266
|
-
console.log();
|
|
2267
|
-
}
|
|
2268
|
-
function formatTable(rows) {
|
|
2269
|
-
if (rows.length === 0) {
|
|
2270
|
-
console.log(" (none)");
|
|
2271
|
-
return;
|
|
2272
|
-
}
|
|
2273
|
-
console.table(rows);
|
|
2274
|
-
}
|
|
2275
|
-
function timeAgo(dateStr) {
|
|
2276
|
-
const diff = Date.now() - new Date(dateStr).getTime();
|
|
2277
|
-
const s = Math.floor(diff / 1000);
|
|
2278
|
-
if (s < 0)
|
|
2279
|
-
return "just now";
|
|
2280
|
-
if (s < 60)
|
|
2281
|
-
return `${s}s ago`;
|
|
2282
|
-
const m = Math.floor(s / 60);
|
|
2283
|
-
if (m < 60)
|
|
2284
|
-
return `${m}m ago`;
|
|
2285
|
-
const h = Math.floor(m / 60);
|
|
2286
|
-
if (h < 24)
|
|
2287
|
-
return `${h}h ago`;
|
|
2288
|
-
const d = Math.floor(h / 24);
|
|
2289
|
-
if (d < 30)
|
|
2290
|
-
return `${d}d ago`;
|
|
2291
|
-
return `${Math.floor(d / 30)}mo ago`;
|
|
2292
|
-
}
|
|
2293
|
-
function formatDuration(seconds) {
|
|
2294
|
-
if (seconds < 60)
|
|
2295
|
-
return `${Math.floor(seconds)}s`;
|
|
2296
|
-
const m = Math.floor(seconds / 60);
|
|
2297
|
-
const s = Math.floor(seconds % 60);
|
|
2298
|
-
if (m < 60)
|
|
2299
|
-
return `${m}m ${s}s`;
|
|
2300
|
-
const h = Math.floor(m / 60);
|
|
2301
|
-
const rm = m % 60;
|
|
2302
|
-
return `${h}h ${rm}m`;
|
|
2303
|
-
}
|
|
2304
|
-
function formatBytes(bytes) {
|
|
2305
|
-
if (bytes < 1024)
|
|
2306
|
-
return `${bytes} B`;
|
|
2307
|
-
if (bytes < 1024 * 1024)
|
|
2308
|
-
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2309
|
-
if (bytes < 1024 * 1024 * 1024)
|
|
2310
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2311
|
-
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
2312
|
-
}
|
|
2313
|
-
function formatStatus(status) {
|
|
2314
|
-
switch (status) {
|
|
2315
|
-
case "running":
|
|
2316
|
-
case "active":
|
|
2317
|
-
case "healthy":
|
|
2318
|
-
case "success":
|
|
2319
|
-
case "completed":
|
|
2320
|
-
return colors.green(status);
|
|
2321
|
-
case "stopped":
|
|
2322
|
-
case "inactive":
|
|
2323
|
-
case "terminated":
|
|
2324
|
-
case "failed":
|
|
2325
|
-
return colors.red(status);
|
|
2326
|
-
case "starting":
|
|
2327
|
-
case "stopping":
|
|
2328
|
-
case "pending":
|
|
2329
|
-
case "warning":
|
|
2330
|
-
return colors.yellow(status);
|
|
2331
|
-
case "error":
|
|
2332
|
-
return colors.red(status);
|
|
2333
|
-
default:
|
|
2334
|
-
return status;
|
|
2335
|
-
}
|
|
2336
|
-
}
|
|
2337
|
-
function formatNotificationType(type) {
|
|
2338
|
-
switch (type) {
|
|
2339
|
-
case "error":
|
|
2340
|
-
return colors.red("\u25CF");
|
|
2341
|
-
case "warning":
|
|
2342
|
-
return colors.yellow("\u25CF");
|
|
2343
|
-
case "success":
|
|
2344
|
-
return colors.green("\u25CF");
|
|
2345
|
-
case "info":
|
|
2346
|
-
default:
|
|
2347
|
-
return colors.blue("\u25CF");
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
function shortId(id, len = 10) {
|
|
2351
|
-
if (id.length <= len)
|
|
2352
|
-
return id;
|
|
2353
|
-
return id.substring(0, len) + "...";
|
|
2354
|
-
}
|
|
2355
|
-
async function printAgentDetails(agentUrl, maxWaitMs = 15000) {
|
|
2356
|
-
const startTime = Date.now();
|
|
2357
|
-
let healthy = false;
|
|
2358
|
-
while (Date.now() - startTime < maxWaitMs) {
|
|
2359
|
-
try {
|
|
2360
|
-
const res = await fetch(`${agentUrl}/health`);
|
|
2361
|
-
if (res.ok) {
|
|
2362
|
-
healthy = true;
|
|
2363
|
-
break;
|
|
2364
|
-
}
|
|
2365
|
-
} catch {}
|
|
2366
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
2367
|
-
}
|
|
2368
|
-
if (!healthy) {
|
|
2369
|
-
console.log(`
|
|
2370
|
-
${icons.warning} Agent not yet responding at ${agentUrl}. Check ${colors.bold("vibe logs")} for details.
|
|
2371
|
-
`);
|
|
2372
|
-
return;
|
|
2373
|
-
}
|
|
2374
|
-
let apiKey = "(unavailable)";
|
|
2375
|
-
try {
|
|
2376
|
-
const res = await fetch(`${agentUrl}/api/agent/api-key`);
|
|
2377
|
-
if (res.ok) {
|
|
2378
|
-
const data = await res.json();
|
|
2379
|
-
apiKey = data.apiKey;
|
|
2380
|
-
}
|
|
2381
|
-
} catch {}
|
|
2382
|
-
let tunnelUrl = "(not running)";
|
|
2383
|
-
let tunnelWaiting = false;
|
|
2384
|
-
try {
|
|
2385
|
-
const res = await fetch(`${agentUrl}/api/agent/tunnel`);
|
|
2386
|
-
if (res.ok) {
|
|
2387
|
-
const data = await res.json();
|
|
2388
|
-
if (data.tunnelUrl) {
|
|
2389
|
-
tunnelUrl = data.tunnelUrl;
|
|
2390
|
-
} else if (data.status !== "inactive") {
|
|
2391
|
-
tunnelWaiting = true;
|
|
2392
|
-
}
|
|
2393
|
-
}
|
|
2394
|
-
} catch {}
|
|
2395
|
-
if (tunnelWaiting || tunnelUrl === "(not running)") {
|
|
2396
|
-
const tunnelWaitMs = 20000;
|
|
2397
|
-
const tunnelStart = Date.now();
|
|
2398
|
-
while (Date.now() - tunnelStart < tunnelWaitMs) {
|
|
2399
|
-
try {
|
|
2400
|
-
const res = await fetch(`${agentUrl}/api/agent/tunnel`);
|
|
2401
|
-
if (res.ok) {
|
|
2402
|
-
const data = await res.json();
|
|
2403
|
-
if (data.tunnelUrl) {
|
|
2404
|
-
tunnelUrl = data.tunnelUrl;
|
|
2405
|
-
break;
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
} catch {}
|
|
2409
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
header("Agent Connection Details");
|
|
2413
|
-
kv("Agent URL:", agentUrl);
|
|
2414
|
-
kv("API Key:", apiKey);
|
|
2415
|
-
kv("Tunnel URL:", tunnelUrl === "(not running)" ? colors.yellow(tunnelUrl) : colors.green(tunnelUrl));
|
|
2416
|
-
blank();
|
|
2417
|
-
console.log(" Copy the API Key and Tunnel URL into the VibeControls UI agent configuration.");
|
|
2418
|
-
if (tunnelUrl === "(not running)") {
|
|
2419
|
-
console.log(` Start a tunnel manually: ${colors.bold(`vibe tunnel agent --start --agent-url ${agentUrl}`)}`);
|
|
2420
|
-
}
|
|
2421
|
-
blank();
|
|
2422
|
-
}
|
|
2423
|
-
// src/services/service-manager.ts
|
|
2424
|
-
import { spawn } from "child_process";
|
|
2425
|
-
import { promisify } from "util";
|
|
2426
|
-
import {
|
|
2427
|
-
existsSync,
|
|
2428
|
-
readFileSync,
|
|
2429
|
-
writeFileSync,
|
|
2430
|
-
mkdirSync,
|
|
2431
|
-
openSync,
|
|
2432
|
-
closeSync
|
|
2433
|
-
} from "fs";
|
|
2434
|
-
import { join, dirname } from "path";
|
|
2435
|
-
import { fileURLToPath } from "url";
|
|
2153
|
+
import { existsSync } from "fs";
|
|
2154
|
+
import { join } from "path";
|
|
2436
2155
|
import { homedir } from "os";
|
|
2437
|
-
import { exec } from "child_process";
|
|
2438
|
-
var execAsync = promisify(exec);
|
|
2439
|
-
var __filename2 = fileURLToPath(import.meta.url);
|
|
2440
|
-
var __dirname2 = dirname(__filename2);
|
|
2441
|
-
|
|
2442
|
-
class ServiceManager {
|
|
2443
|
-
registryPath;
|
|
2444
|
-
logsDir;
|
|
2445
|
-
constructor() {
|
|
2446
|
-
const configDir = join(homedir(), ".vibecontrols");
|
|
2447
|
-
this.registryPath = join(configDir, "agents.json");
|
|
2448
|
-
this.logsDir = join(configDir, "logs");
|
|
2449
|
-
mkdirSync(configDir, { recursive: true });
|
|
2450
|
-
mkdirSync(this.logsDir, { recursive: true });
|
|
2451
|
-
}
|
|
2452
|
-
async startDaemon(config) {
|
|
2453
|
-
const existing = await this.findProcessByName(config.name);
|
|
2454
|
-
if (existing && existing.status === "running") {
|
|
2455
|
-
console.log(`\u26A0\uFE0F Agent '${config.name}' is already running on port ${existing.port}`);
|
|
2456
|
-
return;
|
|
2457
|
-
}
|
|
2458
|
-
const logFile = join(this.logsDir, `${config.name}.log`);
|
|
2459
|
-
const logFd = openSync(logFile, "a");
|
|
2460
|
-
const indexPath = join(__dirname2, "..", "index.js");
|
|
2461
|
-
const child = spawn("bun", ["run", indexPath], {
|
|
2462
|
-
detached: true,
|
|
2463
|
-
stdio: ["ignore", logFd, logFd],
|
|
2464
|
-
env: {
|
|
2465
|
-
...process.env,
|
|
2466
|
-
PORT: config.port.toString(),
|
|
2467
|
-
DB_PATH: config.dbPath,
|
|
2468
|
-
NODE_ENV: "production"
|
|
2469
|
-
}
|
|
2470
|
-
});
|
|
2471
|
-
closeSync(logFd);
|
|
2472
|
-
child.unref();
|
|
2473
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2474
|
-
const isRunning = await this.isProcessRunning(child.pid);
|
|
2475
|
-
if (!isRunning) {
|
|
2476
|
-
throw new Error(`Failed to start agent '${config.name}'`);
|
|
2477
|
-
}
|
|
2478
|
-
await this.saveProcessInfo(config.name, child.pid, config);
|
|
2479
|
-
console.log(`\uD83D\uDE80 Agent '${config.name}' started (PID: ${child.pid}, Port: ${config.port})`);
|
|
2480
|
-
}
|
|
2481
|
-
async stop(name) {
|
|
2482
|
-
const agentProcess = await this.findProcessByName(name);
|
|
2483
|
-
if (!agentProcess || agentProcess.status !== "running") {
|
|
2484
|
-
console.log(`\u26A0\uFE0F Agent '${name}' is not running`);
|
|
2485
|
-
return;
|
|
2486
|
-
}
|
|
2487
|
-
try {
|
|
2488
|
-
process.kill(agentProcess.pid, "SIGTERM");
|
|
2489
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
2490
|
-
const stillRunning = await this.isProcessRunning(agentProcess.pid);
|
|
2491
|
-
if (stillRunning) {
|
|
2492
|
-
process.kill(agentProcess.pid, "SIGKILL");
|
|
2493
|
-
}
|
|
2494
|
-
await this.updateProcessStatus(name, "stopped");
|
|
2495
|
-
console.log(`\u2705 Agent '${name}' stopped`);
|
|
2496
|
-
} catch (err) {
|
|
2497
|
-
throw new Error(`Failed to stop agent '${name}': ${err}`, { cause: err });
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
|
-
async restart(name, config) {
|
|
2501
|
-
const existing = await this.findProcessByName(name);
|
|
2502
|
-
if (existing && existing.status === "running") {
|
|
2503
|
-
await this.stop(name);
|
|
2504
|
-
}
|
|
2505
|
-
await this.startDaemon(config);
|
|
2506
|
-
console.log(`\uD83D\uDD04 Agent '${name}' restarted`);
|
|
2507
|
-
}
|
|
2508
|
-
async kill(name) {
|
|
2509
|
-
const agentProcess = await this.findProcessByName(name);
|
|
2510
|
-
if (!agentProcess || agentProcess.status !== "running") {
|
|
2511
|
-
console.log(`\u26A0\uFE0F Agent '${name}' is not running`);
|
|
2512
|
-
return;
|
|
2513
|
-
}
|
|
2514
|
-
await this.killProcessTree(agentProcess.pid);
|
|
2515
|
-
await this.updateProcessStatus(name, "stopped");
|
|
2516
|
-
console.log(`\uD83D\uDC80 Agent '${name}' killed`);
|
|
2517
|
-
}
|
|
2518
|
-
async getStatus(name) {
|
|
2519
|
-
return this.findProcessByName(name);
|
|
2520
|
-
}
|
|
2521
|
-
async getStatusAll() {
|
|
2522
|
-
const registry = this.loadRegistry();
|
|
2523
|
-
const processes = [];
|
|
2524
|
-
for (const processInfo of registry) {
|
|
2525
|
-
const isRunning = await this.isProcessRunning(processInfo.pid);
|
|
2526
|
-
processes.push({
|
|
2527
|
-
...processInfo,
|
|
2528
|
-
status: isRunning ? "running" : "stopped"
|
|
2529
|
-
});
|
|
2530
|
-
}
|
|
2531
|
-
return processes;
|
|
2532
|
-
}
|
|
2533
|
-
async listInstances() {
|
|
2534
|
-
return this.getStatusAll();
|
|
2535
|
-
}
|
|
2536
|
-
async showLogs(name, options) {
|
|
2537
|
-
const logFile = join(this.logsDir, `${name}.log`);
|
|
2538
|
-
if (!existsSync(logFile)) {
|
|
2539
|
-
console.log(`No logs found for agent '${name}'`);
|
|
2540
|
-
return;
|
|
2541
|
-
}
|
|
2542
|
-
if (options.follow) {
|
|
2543
|
-
const tail = spawn("tail", [
|
|
2544
|
-
"-f",
|
|
2545
|
-
"-n",
|
|
2546
|
-
options.tail.toString(),
|
|
2547
|
-
logFile
|
|
2548
|
-
]);
|
|
2549
|
-
tail.stdout?.on("data", (data) => process.stdout.write(data));
|
|
2550
|
-
tail.stderr?.on("data", (data) => process.stderr.write(data));
|
|
2551
|
-
process.on("SIGINT", () => {
|
|
2552
|
-
tail.kill();
|
|
2553
|
-
process.exit(0);
|
|
2554
|
-
});
|
|
2555
|
-
} else {
|
|
2556
|
-
try {
|
|
2557
|
-
const { stdout } = await execAsync(`tail -n ${options.tail} "${logFile}"`);
|
|
2558
|
-
console.log(stdout);
|
|
2559
|
-
} catch (err) {
|
|
2560
|
-
console.error("Failed to read logs:", err);
|
|
2561
|
-
}
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
async checkHealth(name) {
|
|
2565
|
-
const proc = await this.findProcessByName(name);
|
|
2566
|
-
if (!proc || proc.status !== "running") {
|
|
2567
|
-
return { healthy: false, details: { error: "Process not running" } };
|
|
2568
|
-
}
|
|
2569
|
-
try {
|
|
2570
|
-
const response = await fetch(`http://localhost:${proc.port}/health`);
|
|
2571
|
-
const data = await response.json();
|
|
2572
|
-
return { healthy: response.ok, details: data };
|
|
2573
|
-
} catch (err) {
|
|
2574
|
-
return {
|
|
2575
|
-
healthy: false,
|
|
2576
|
-
details: {
|
|
2577
|
-
error: "Health check failed",
|
|
2578
|
-
message: err.message
|
|
2579
|
-
}
|
|
2580
|
-
};
|
|
2581
|
-
}
|
|
2582
|
-
}
|
|
2583
|
-
async setConfig(key, value) {
|
|
2584
|
-
const configFile = join(homedir(), ".vibecontrols", "config.json");
|
|
2585
|
-
let config = {};
|
|
2586
|
-
if (existsSync(configFile)) {
|
|
2587
|
-
config = JSON.parse(readFileSync(configFile, "utf8"));
|
|
2588
|
-
}
|
|
2589
|
-
config[key] = value;
|
|
2590
|
-
writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
2591
|
-
}
|
|
2592
|
-
async getConfig(key) {
|
|
2593
|
-
const configFile = join(homedir(), ".vibecontrols", "config.json");
|
|
2594
|
-
if (!existsSync(configFile))
|
|
2595
|
-
return key ? undefined : {};
|
|
2596
|
-
const config = JSON.parse(readFileSync(configFile, "utf8"));
|
|
2597
|
-
return key ? config[key] : config;
|
|
2598
|
-
}
|
|
2599
|
-
loadRegistry() {
|
|
2600
|
-
if (!existsSync(this.registryPath))
|
|
2601
|
-
return [];
|
|
2602
|
-
try {
|
|
2603
|
-
return JSON.parse(readFileSync(this.registryPath, "utf8"));
|
|
2604
|
-
} catch {
|
|
2605
|
-
return [];
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
saveRegistry(processes) {
|
|
2609
|
-
writeFileSync(this.registryPath, JSON.stringify(processes, null, 2));
|
|
2610
|
-
}
|
|
2611
|
-
async saveProcessInfo(name, pid, config) {
|
|
2612
|
-
const registry = this.loadRegistry();
|
|
2613
|
-
const filtered = registry.filter((p) => p.name !== name);
|
|
2614
|
-
filtered.push({
|
|
2615
|
-
name,
|
|
2616
|
-
pid,
|
|
2617
|
-
port: config.port,
|
|
2618
|
-
config,
|
|
2619
|
-
startTime: new Date().toISOString(),
|
|
2620
|
-
status: "running"
|
|
2621
|
-
});
|
|
2622
|
-
this.saveRegistry(filtered);
|
|
2623
|
-
}
|
|
2624
|
-
async updateProcessStatus(name, status) {
|
|
2625
|
-
const registry = this.loadRegistry();
|
|
2626
|
-
const proc = registry.find((p) => p.name === name);
|
|
2627
|
-
if (proc) {
|
|
2628
|
-
proc.status = status;
|
|
2629
|
-
this.saveRegistry(registry);
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2632
|
-
async findProcessByName(name) {
|
|
2633
|
-
const registry = this.loadRegistry();
|
|
2634
|
-
const proc = registry.find((p) => p.name === name);
|
|
2635
|
-
if (!proc)
|
|
2636
|
-
return null;
|
|
2637
|
-
const isRunning = await this.isProcessRunning(proc.pid);
|
|
2638
|
-
proc.status = isRunning ? "running" : "stopped";
|
|
2639
|
-
return proc;
|
|
2640
|
-
}
|
|
2641
|
-
async isProcessRunning(pid) {
|
|
2642
|
-
try {
|
|
2643
|
-
process.kill(pid, 0);
|
|
2644
|
-
return true;
|
|
2645
|
-
} catch {
|
|
2646
|
-
return false;
|
|
2647
|
-
}
|
|
2648
|
-
}
|
|
2649
|
-
async killProcessTree(pid) {
|
|
2650
|
-
try {
|
|
2651
|
-
process.kill(-pid, "SIGKILL");
|
|
2652
|
-
} catch {
|
|
2653
|
-
try {
|
|
2654
|
-
process.kill(pid, "SIGKILL");
|
|
2655
|
-
} catch {}
|
|
2656
|
-
}
|
|
2657
|
-
}
|
|
2658
|
-
}
|
|
2659
2156
|
|
|
2660
2157
|
// src/services/port-utils.ts
|
|
2661
2158
|
import { createServer } from "net";
|
|
@@ -2682,12 +2179,12 @@ async function findFreePortFrom(startPort, host = "0.0.0.0") {
|
|
|
2682
2179
|
|
|
2683
2180
|
// src/cli/commands/start.cmd.ts
|
|
2684
2181
|
function register(program2) {
|
|
2685
|
-
program2.command("start").description("Start a VibeControls agent instance").option("-p, --port <port>", "Port to listen on", "3005").option("-n, --name <name>", "Agent instance name", "default").option("-
|
|
2182
|
+
program2.command("start").description("Start a VibeControls agent instance").option("-p, --port <port>", "Port to listen on", "3005").option("-n, --name <name>", "Agent instance name", "default").option("-f, --foreground", "Run in foreground mode (default: daemon)", false).option("--db-path <path>", "Path to the SQLite database", "./vibecontrols-agent.db").option("--host <host>", "Host to bind to", "0.0.0.0").action(async (opts) => {
|
|
2686
2183
|
try {
|
|
2687
2184
|
const serviceManager = new ServiceManager;
|
|
2688
2185
|
const dbPath = opts.dbPath;
|
|
2689
|
-
const configDir =
|
|
2690
|
-
const firstRun = !
|
|
2186
|
+
const configDir = join(homedir(), ".vibecontrols");
|
|
2187
|
+
const firstRun = !existsSync(dbPath) && !existsSync(join(configDir, "agents.json"));
|
|
2691
2188
|
if (firstRun) {
|
|
2692
2189
|
info("First run detected \u2014 running setup...");
|
|
2693
2190
|
blank();
|
|
@@ -2720,47 +2217,49 @@ function register(program2) {
|
|
|
2720
2217
|
}
|
|
2721
2218
|
const host = opts.host;
|
|
2722
2219
|
const agentUrl = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
|
|
2723
|
-
if (opts.
|
|
2724
|
-
header("Starting agent in daemon mode");
|
|
2725
|
-
kv("Name", opts.name);
|
|
2726
|
-
kv("Port", String(port));
|
|
2727
|
-
kv("Host", host);
|
|
2728
|
-
kv("Database", dbPath);
|
|
2729
|
-
blank();
|
|
2730
|
-
await serviceManager.startDaemon({
|
|
2731
|
-
port,
|
|
2732
|
-
name: opts.name,
|
|
2733
|
-
daemon: true,
|
|
2734
|
-
dbPath,
|
|
2735
|
-
host
|
|
2736
|
-
});
|
|
2737
|
-
await printAgentDetails(agentUrl);
|
|
2738
|
-
} else {
|
|
2220
|
+
if (opts.foreground) {
|
|
2739
2221
|
header("Starting agent in foreground");
|
|
2740
2222
|
kv("Name", opts.name);
|
|
2741
2223
|
kv("Port", String(port));
|
|
2742
2224
|
kv("Host", host);
|
|
2743
2225
|
kv("Database", dbPath);
|
|
2744
2226
|
blank();
|
|
2745
|
-
const { createApp } = await import("./app-
|
|
2227
|
+
const { createApp } = await import("./app-6mmbmske.js");
|
|
2746
2228
|
const appInstance = await createApp({
|
|
2747
2229
|
port,
|
|
2748
2230
|
host,
|
|
2749
2231
|
dbPath
|
|
2750
2232
|
});
|
|
2751
2233
|
await appInstance.start();
|
|
2234
|
+
await printAgentDetails(agentUrl);
|
|
2752
2235
|
const shutdown = async () => {
|
|
2753
2236
|
await appInstance.stop();
|
|
2754
2237
|
process.exit(0);
|
|
2755
2238
|
};
|
|
2756
2239
|
process.on("SIGTERM", shutdown);
|
|
2757
2240
|
process.on("SIGINT", shutdown);
|
|
2241
|
+
} else {
|
|
2242
|
+
header("Starting agent in daemon mode");
|
|
2243
|
+
kv("Name", opts.name);
|
|
2244
|
+
kv("Port", String(port));
|
|
2245
|
+
kv("Host", host);
|
|
2246
|
+
kv("Database", dbPath);
|
|
2247
|
+
blank();
|
|
2248
|
+
await serviceManager.startDaemon({
|
|
2249
|
+
port,
|
|
2250
|
+
name: opts.name,
|
|
2251
|
+
daemon: true,
|
|
2252
|
+
dbPath,
|
|
2253
|
+
host
|
|
2254
|
+
});
|
|
2255
|
+
await printAgentDetails(agentUrl);
|
|
2758
2256
|
}
|
|
2759
2257
|
} catch (err) {
|
|
2760
2258
|
fail(`Failed to start agent: ${err instanceof Error ? err.message : err}`);
|
|
2761
2259
|
}
|
|
2762
2260
|
});
|
|
2763
2261
|
}
|
|
2262
|
+
|
|
2764
2263
|
// src/cli/commands/stop.cmd.ts
|
|
2765
2264
|
function register2(program2) {
|
|
2766
2265
|
program2.command("stop").description("Stop a running VibeControls agent instance").option("-n, --name <name>", "Agent instance name", "default").option("--all", "Stop all running agent instances", false).action(async (opts) => {
|
|
@@ -2797,6 +2296,7 @@ function register2(program2) {
|
|
|
2797
2296
|
}
|
|
2798
2297
|
});
|
|
2799
2298
|
}
|
|
2299
|
+
|
|
2800
2300
|
// src/cli/commands/restart.cmd.ts
|
|
2801
2301
|
function register3(program2) {
|
|
2802
2302
|
program2.command("restart").description("Restart a running VibeControls agent instance").option("-n, --name <name>", "Agent instance name", "default").option("-p, --port <port>", "Port to listen on", "3005").option("--db-path <path>", "Path to the SQLite database", "./vibecontrols-agent.db").action(async (opts) => {
|
|
@@ -2838,54 +2338,49 @@ function register3(program2) {
|
|
|
2838
2338
|
}
|
|
2839
2339
|
});
|
|
2840
2340
|
}
|
|
2841
|
-
|
|
2341
|
+
|
|
2342
|
+
// src/cli/commands/kill.cmd.ts
|
|
2842
2343
|
function register4(program2) {
|
|
2843
|
-
program2.command("
|
|
2344
|
+
program2.command("kill").description("Force kill a VibeControls agent instance").option("-n, --name <name>", "Agent instance name", "default").option("--all", "Kill all agent instances", false).action(async (opts) => {
|
|
2844
2345
|
try {
|
|
2845
2346
|
const serviceManager = new ServiceManager;
|
|
2846
|
-
if (opts.
|
|
2847
|
-
header(
|
|
2347
|
+
if (opts.all) {
|
|
2348
|
+
header("Force killing all agent instances");
|
|
2848
2349
|
blank();
|
|
2849
|
-
const
|
|
2850
|
-
if (!
|
|
2851
|
-
|
|
2350
|
+
const instances = await serviceManager.listInstances();
|
|
2351
|
+
if (!instances || instances.length === 0) {
|
|
2352
|
+
info(`${icons.info} No agent instances found.`);
|
|
2852
2353
|
return;
|
|
2853
2354
|
}
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2355
|
+
let killed = 0;
|
|
2356
|
+
for (const instance of instances) {
|
|
2357
|
+
try {
|
|
2358
|
+
await serviceManager.kill(instance.name);
|
|
2359
|
+
success(`${icons.success} Killed ${colors.bold(instance.name)} (PID: ${instance.pid || "unknown"})`);
|
|
2360
|
+
killed++;
|
|
2361
|
+
} catch {
|
|
2362
|
+
warn(`${icons.warning} Could not kill ${colors.bold(instance.name)}`);
|
|
2363
|
+
}
|
|
2862
2364
|
}
|
|
2863
2365
|
blank();
|
|
2366
|
+
success(`${icons.success} Killed ${killed}/${instances.length} instance(s).`);
|
|
2864
2367
|
} else {
|
|
2865
|
-
header(
|
|
2368
|
+
header(`Force killing agent: ${opts.name}`);
|
|
2866
2369
|
blank();
|
|
2867
|
-
const
|
|
2868
|
-
if (!
|
|
2869
|
-
|
|
2870
|
-
info(`Run ${colors.bold("vibe start")} to start an agent.`);
|
|
2370
|
+
const instance = await serviceManager.getStatus(opts.name);
|
|
2371
|
+
if (!instance) {
|
|
2372
|
+
fail(`Agent instance ${colors.bold(opts.name)} not found.`);
|
|
2871
2373
|
return;
|
|
2872
2374
|
}
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
Status: formatStatus(inst.status),
|
|
2876
|
-
PID: inst.pid || "-",
|
|
2877
|
-
Port: inst.port || "-",
|
|
2878
|
-
Started: inst.startTime ? timeAgo(inst.startTime) : "-"
|
|
2879
|
-
}));
|
|
2880
|
-
formatTable(rows);
|
|
2881
|
-
blank();
|
|
2882
|
-
info(`${icons.info} ${instances.length} instance(s) found. Use ${colors.bold("vibe status -n <name>")} for details.`);
|
|
2375
|
+
await serviceManager.kill(opts.name);
|
|
2376
|
+
success(`${icons.success} Agent ${colors.bold(opts.name)} killed (PID: ${instance.pid || "unknown"}).`);
|
|
2883
2377
|
}
|
|
2884
2378
|
} catch (err) {
|
|
2885
|
-
fail(`Failed to
|
|
2379
|
+
fail(`Failed to kill agent: ${err.message}`);
|
|
2886
2380
|
}
|
|
2887
2381
|
});
|
|
2888
2382
|
}
|
|
2383
|
+
|
|
2889
2384
|
// src/cli/commands/list.cmd.ts
|
|
2890
2385
|
function register5(program2) {
|
|
2891
2386
|
program2.command("list").alias("ls").description("List all VibeControls agent instances").action(async () => {
|
|
@@ -2918,49 +2413,9 @@ function register5(program2) {
|
|
|
2918
2413
|
}
|
|
2919
2414
|
});
|
|
2920
2415
|
}
|
|
2921
|
-
|
|
2922
|
-
function register6(program2) {
|
|
2923
|
-
program2.command("kill").description("Force kill a VibeControls agent instance").option("-n, --name <name>", "Agent instance name", "default").option("--all", "Kill all agent instances", false).action(async (opts) => {
|
|
2924
|
-
try {
|
|
2925
|
-
const serviceManager = new ServiceManager;
|
|
2926
|
-
if (opts.all) {
|
|
2927
|
-
header("Force killing all agent instances");
|
|
2928
|
-
blank();
|
|
2929
|
-
const instances = await serviceManager.listInstances();
|
|
2930
|
-
if (!instances || instances.length === 0) {
|
|
2931
|
-
info(`${icons.info} No agent instances found.`);
|
|
2932
|
-
return;
|
|
2933
|
-
}
|
|
2934
|
-
let killed = 0;
|
|
2935
|
-
for (const instance of instances) {
|
|
2936
|
-
try {
|
|
2937
|
-
await serviceManager.kill(instance.name);
|
|
2938
|
-
success(`${icons.success} Killed ${colors.bold(instance.name)} (PID: ${instance.pid || "unknown"})`);
|
|
2939
|
-
killed++;
|
|
2940
|
-
} catch {
|
|
2941
|
-
warn(`${icons.warning} Could not kill ${colors.bold(instance.name)}`);
|
|
2942
|
-
}
|
|
2943
|
-
}
|
|
2944
|
-
blank();
|
|
2945
|
-
success(`${icons.success} Killed ${killed}/${instances.length} instance(s).`);
|
|
2946
|
-
} else {
|
|
2947
|
-
header(`Force killing agent: ${opts.name}`);
|
|
2948
|
-
blank();
|
|
2949
|
-
const instance = await serviceManager.getStatus(opts.name);
|
|
2950
|
-
if (!instance) {
|
|
2951
|
-
fail(`Agent instance ${colors.bold(opts.name)} not found.`);
|
|
2952
|
-
return;
|
|
2953
|
-
}
|
|
2954
|
-
await serviceManager.kill(opts.name);
|
|
2955
|
-
success(`${icons.success} Agent ${colors.bold(opts.name)} killed (PID: ${instance.pid || "unknown"}).`);
|
|
2956
|
-
}
|
|
2957
|
-
} catch (err) {
|
|
2958
|
-
fail(`Failed to kill agent: ${err.message}`);
|
|
2959
|
-
}
|
|
2960
|
-
});
|
|
2961
|
-
}
|
|
2416
|
+
|
|
2962
2417
|
// src/cli/commands/logs.cmd.ts
|
|
2963
|
-
function
|
|
2418
|
+
function register6(program2) {
|
|
2964
2419
|
program2.command("logs").description("View logs for a VibeControls agent instance").option("-n, --name <name>", "Agent instance name", "default").option("-f, --follow", "Follow log output", false).option("--tail <lines>", "Number of lines to show from the end", "100").action(async (opts) => {
|
|
2965
2420
|
try {
|
|
2966
2421
|
const serviceManager = new ServiceManager;
|
|
@@ -2989,134 +2444,13 @@ function register7(program2) {
|
|
|
2989
2444
|
}
|
|
2990
2445
|
});
|
|
2991
2446
|
}
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
function
|
|
2995
|
-
program2.command("
|
|
2447
|
+
|
|
2448
|
+
// src/cli/commands/setup.cmd.ts
|
|
2449
|
+
function register7(program2) {
|
|
2450
|
+
program2.command("setup").description("Install or verify system dependencies (tmux, ttyd, cloudflared)").option("--check", "Only check without installing", false).action(async (options) => {
|
|
2996
2451
|
try {
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
blank();
|
|
3000
|
-
const data = await apiGet(agentUrl, "/api/agent/api-key");
|
|
3001
|
-
kv("API Key", colors.bold(data.apiKey));
|
|
3002
|
-
blank();
|
|
3003
|
-
} catch (err) {
|
|
3004
|
-
fail(`Failed to get API key: ${err.message}`);
|
|
3005
|
-
}
|
|
3006
|
-
});
|
|
3007
|
-
}
|
|
3008
|
-
// src/cli/commands/health.cmd.ts
|
|
3009
|
-
var DEFAULT_AGENT_URL3 = "http://localhost:3005";
|
|
3010
|
-
function register9(program2) {
|
|
3011
|
-
program2.command("health").description("Check health of a VibeControls agent instance").option("-n, --name <name>", "Agent instance name").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL3).action(async (opts) => {
|
|
3012
|
-
try {
|
|
3013
|
-
header("Agent Health");
|
|
3014
|
-
blank();
|
|
3015
|
-
if (opts.name) {
|
|
3016
|
-
const serviceManager = new ServiceManager;
|
|
3017
|
-
const result = await serviceManager.checkHealth(opts.name);
|
|
3018
|
-
if (!result.healthy) {
|
|
3019
|
-
fail(`Agent instance ${colors.bold(opts.name)} is not responding.`);
|
|
3020
|
-
return;
|
|
3021
|
-
}
|
|
3022
|
-
const details = result.details;
|
|
3023
|
-
kv("Instance", opts.name);
|
|
3024
|
-
kv("Status", formatStatus(details.status ?? "healthy"));
|
|
3025
|
-
if (details.uptime !== undefined) {
|
|
3026
|
-
kv("Uptime", `${details.uptime}s`);
|
|
3027
|
-
}
|
|
3028
|
-
if (details.checks) {
|
|
3029
|
-
blank();
|
|
3030
|
-
info(`${icons.info} Health checks:`);
|
|
3031
|
-
for (const [name, check] of Object.entries(details.checks)) {
|
|
3032
|
-
const icon = check.status === "healthy" ? icons.success : icons.error;
|
|
3033
|
-
kv(` ${icon} ${name}`, formatStatus(check.status));
|
|
3034
|
-
}
|
|
3035
|
-
}
|
|
3036
|
-
} else {
|
|
3037
|
-
const agentUrl = getAgentUrl(opts);
|
|
3038
|
-
const data = await apiGet(agentUrl, "/health");
|
|
3039
|
-
kv("URL", agentUrl);
|
|
3040
|
-
kv("Status", formatStatus(data.status));
|
|
3041
|
-
if (data.version) {
|
|
3042
|
-
kv("Version", data.version);
|
|
3043
|
-
}
|
|
3044
|
-
if (data.uptime !== undefined) {
|
|
3045
|
-
kv("Uptime", `${data.uptime}s`);
|
|
3046
|
-
}
|
|
3047
|
-
if (data.timestamp) {
|
|
3048
|
-
kv("Timestamp", data.timestamp);
|
|
3049
|
-
}
|
|
3050
|
-
if (data.checks) {
|
|
3051
|
-
blank();
|
|
3052
|
-
info(`${icons.info} Health checks:`);
|
|
3053
|
-
for (const [name, check] of Object.entries(data.checks)) {
|
|
3054
|
-
const icon = check.status === "healthy" ? icons.success : icons.error;
|
|
3055
|
-
kv(` ${icon} ${name}`, formatStatus(check.status));
|
|
3056
|
-
}
|
|
3057
|
-
}
|
|
3058
|
-
}
|
|
3059
|
-
blank();
|
|
3060
|
-
success(`${icons.success} Agent is healthy.`);
|
|
3061
|
-
} catch (err) {
|
|
3062
|
-
fail(`Health check failed: ${err.message}`);
|
|
3063
|
-
}
|
|
3064
|
-
});
|
|
3065
|
-
}
|
|
3066
|
-
// src/cli/commands/info.cmd.ts
|
|
3067
|
-
import { platform, arch, release, hostname, cpus, totalmem } from "os";
|
|
3068
|
-
var DEFAULT_AGENT_URL4 = "http://localhost:3005";
|
|
3069
|
-
function register10(program2) {
|
|
3070
|
-
program2.command("info").description("Show local and remote VibeControls agent information").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL4).action(async (opts) => {
|
|
3071
|
-
try {
|
|
3072
|
-
header("VibeControls Agent Info");
|
|
3073
|
-
blank();
|
|
3074
|
-
info(`${icons.info} Local System`);
|
|
3075
|
-
kv("Hostname", hostname());
|
|
3076
|
-
kv("Platform", `${platform()} ${arch()}`);
|
|
3077
|
-
kv("OS Release", release());
|
|
3078
|
-
kv("CPUs", String(cpus().length));
|
|
3079
|
-
kv("Total Memory", formatBytes(totalmem()));
|
|
3080
|
-
kv("Node.js", process.version);
|
|
3081
|
-
if (process.versions.bun) {
|
|
3082
|
-
kv("Bun", process.versions.bun);
|
|
3083
|
-
}
|
|
3084
|
-
blank();
|
|
3085
|
-
const agentUrl = getAgentUrl(opts);
|
|
3086
|
-
try {
|
|
3087
|
-
const data = await apiGet(agentUrl, "/api/agent/version");
|
|
3088
|
-
info(`${icons.info} Remote Agent`);
|
|
3089
|
-
kv("URL", agentUrl);
|
|
3090
|
-
kv("Version", colors.bold(data.version));
|
|
3091
|
-
if (data.build) {
|
|
3092
|
-
kv("Build", data.build);
|
|
3093
|
-
}
|
|
3094
|
-
if (data.commit) {
|
|
3095
|
-
kv("Commit", data.commit);
|
|
3096
|
-
}
|
|
3097
|
-
if (data.nodeVersion) {
|
|
3098
|
-
kv("Node.js (remote)", data.nodeVersion);
|
|
3099
|
-
}
|
|
3100
|
-
if (data.bunVersion) {
|
|
3101
|
-
kv("Bun (remote)", data.bunVersion);
|
|
3102
|
-
}
|
|
3103
|
-
} catch {
|
|
3104
|
-
info(`${icons.info} Remote Agent`);
|
|
3105
|
-
kv("URL", agentUrl);
|
|
3106
|
-
kv("Status", colors.dim("not reachable"));
|
|
3107
|
-
}
|
|
3108
|
-
blank();
|
|
3109
|
-
} catch (err) {
|
|
3110
|
-
fail(`Failed to get info: ${err.message}`);
|
|
3111
|
-
}
|
|
3112
|
-
});
|
|
3113
|
-
}
|
|
3114
|
-
// src/cli/commands/setup.cmd.ts
|
|
3115
|
-
function register11(program2) {
|
|
3116
|
-
program2.command("setup").description("Install or verify system dependencies (tmux, ttyd, cloudflared)").option("--check", "Only check without installing", false).action(async (options) => {
|
|
3117
|
-
try {
|
|
3118
|
-
header("VibeControls Agent Setup");
|
|
3119
|
-
info("Checking dependencies...");
|
|
2452
|
+
header("VibeControls Agent Setup");
|
|
2453
|
+
info("Checking dependencies...");
|
|
3120
2454
|
blank();
|
|
3121
2455
|
const deps = checkDependencies();
|
|
3122
2456
|
const missing = [];
|
|
@@ -3154,17 +2488,18 @@ function register11(program2) {
|
|
|
3154
2488
|
}
|
|
3155
2489
|
});
|
|
3156
2490
|
}
|
|
2491
|
+
|
|
3157
2492
|
// src/cli/commands/update.cmd.ts
|
|
3158
2493
|
import { execSync } from "child_process";
|
|
3159
2494
|
var PACKAGE_NAME = "vibecontrols-agent";
|
|
3160
|
-
function
|
|
2495
|
+
function register8(program2) {
|
|
3161
2496
|
program2.command("update").description("Check for and install VibeControls agent updates").option("--check", "Only check for updates without installing", false).action(async (opts) => {
|
|
3162
2497
|
try {
|
|
3163
2498
|
header("VibeControls Agent Update");
|
|
3164
2499
|
blank();
|
|
3165
2500
|
let currentVersion;
|
|
3166
2501
|
try {
|
|
3167
|
-
const pkg = await import("./package-
|
|
2502
|
+
const pkg = await import("./package-ywexp6sg.js", {
|
|
3168
2503
|
with: { type: "json" }
|
|
3169
2504
|
});
|
|
3170
2505
|
currentVersion = pkg.default.version || pkg.version;
|
|
@@ -3213,1221 +2548,17 @@ function register12(program2) {
|
|
|
3213
2548
|
}
|
|
3214
2549
|
});
|
|
3215
2550
|
}
|
|
3216
|
-
|
|
3217
|
-
var DEFAULT_AGENT_URL5 = "http://localhost:3005";
|
|
3218
|
-
function register13(program2) {
|
|
3219
|
-
program2.command("system").description("Show system information for a running VibeControls agent").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL5).action(async (opts) => {
|
|
3220
|
-
try {
|
|
3221
|
-
const agentUrl = getAgentUrl(opts);
|
|
3222
|
-
header("Agent System Information");
|
|
3223
|
-
blank();
|
|
3224
|
-
const data = await apiGet(agentUrl, "/api/agent/system");
|
|
3225
|
-
info(`${icons.info} Agent`);
|
|
3226
|
-
kv("Version", colors.bold(data.agentVersion));
|
|
3227
|
-
if (data.bunVersion) {
|
|
3228
|
-
kv("Bun", data.bunVersion);
|
|
3229
|
-
}
|
|
3230
|
-
if (data.environment) {
|
|
3231
|
-
kv("Environment", data.environment);
|
|
3232
|
-
}
|
|
3233
|
-
kv("Uptime", formatDuration(data.uptime));
|
|
3234
|
-
blank();
|
|
3235
|
-
info(`${icons.info} Platform`);
|
|
3236
|
-
kv("OS", `${data.platform} ${data.arch}`);
|
|
3237
|
-
kv("Hostname", data.hostname);
|
|
3238
|
-
kv("Release", data.release);
|
|
3239
|
-
blank();
|
|
3240
|
-
info(`${icons.info} Resources`);
|
|
3241
|
-
kv("CPUs", String(data.cpus));
|
|
3242
|
-
kv("Total Memory", formatBytes(data.totalMemory));
|
|
3243
|
-
kv("Free Memory", formatBytes(data.freeMemory));
|
|
3244
|
-
blank();
|
|
3245
|
-
info(`${icons.info} Paths`);
|
|
3246
|
-
kv("Home", data.homeDir);
|
|
3247
|
-
kv("CWD", data.cwd);
|
|
3248
|
-
blank();
|
|
3249
|
-
} catch (err) {
|
|
3250
|
-
fail(`Failed to get system info: ${err.message}`);
|
|
3251
|
-
}
|
|
3252
|
-
});
|
|
3253
|
-
}
|
|
3254
|
-
// src/cli/commands/url.cmd.ts
|
|
3255
|
-
var DEFAULT_AGENT_URL6 = "http://localhost:3005";
|
|
3256
|
-
function register14(program2) {
|
|
3257
|
-
program2.command("url").description("Show the active URL for a running VibeControls agent").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL6).action(async (opts) => {
|
|
3258
|
-
try {
|
|
3259
|
-
const agentUrl = getAgentUrl(opts);
|
|
3260
|
-
header("Agent URL");
|
|
3261
|
-
blank();
|
|
3262
|
-
const data = await apiGet(agentUrl, "/api/agent/url");
|
|
3263
|
-
kv("Active URL", colors.bold(data.url));
|
|
3264
|
-
kv("Local URL", data.localUrl);
|
|
3265
|
-
if (data.tunnelUrl) {
|
|
3266
|
-
kv("Tunnel URL", colors.cyan(data.tunnelUrl));
|
|
3267
|
-
}
|
|
3268
|
-
kv("Mode", data.isTunnel ? `${icons.running} Tunnel active` : `${icons.info} Local only`);
|
|
3269
|
-
blank();
|
|
3270
|
-
if (data.isTunnel) {
|
|
3271
|
-
info(`${icons.info} Agent is accessible via tunnel at ${colors.bold(data.tunnelUrl)}`);
|
|
3272
|
-
} else {
|
|
3273
|
-
info(`${icons.info} Agent is running locally at ${colors.bold(data.localUrl)}`);
|
|
3274
|
-
}
|
|
3275
|
-
} catch (err) {
|
|
3276
|
-
fail(`Failed to get URL: ${err.message}`);
|
|
3277
|
-
}
|
|
3278
|
-
});
|
|
3279
|
-
}
|
|
3280
|
-
// src/cli/commands/config.cmd.ts
|
|
3281
|
-
var DEFAULT_AGENT_URL7 = "http://localhost:3005";
|
|
3282
|
-
function register15(program2) {
|
|
3283
|
-
program2.command("config").description("Manage VibeControls agent configuration").option("--set <key=value>", "Set a configuration value").option("--get <key>", "Get a configuration value").option("--delete <key>", "Delete a configuration value").option("--list", "List all configuration values", false).option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL7).action(async (opts) => {
|
|
3284
|
-
try {
|
|
3285
|
-
const agentUrl = getAgentUrl(opts);
|
|
3286
|
-
if (opts.set) {
|
|
3287
|
-
const eqIndex = opts.set.indexOf("=");
|
|
3288
|
-
if (eqIndex === -1) {
|
|
3289
|
-
fail(`Invalid format. Use ${colors.bold("--set key=value")}`);
|
|
3290
|
-
return;
|
|
3291
|
-
}
|
|
3292
|
-
const key = opts.set.slice(0, eqIndex).trim();
|
|
3293
|
-
const value = opts.set.slice(eqIndex + 1).trim();
|
|
3294
|
-
if (!key) {
|
|
3295
|
-
fail("Configuration key cannot be empty.");
|
|
3296
|
-
return;
|
|
3297
|
-
}
|
|
3298
|
-
try {
|
|
3299
|
-
await apiPut(agentUrl, `/api/config/${encodeURIComponent(key)}`, {
|
|
3300
|
-
value
|
|
3301
|
-
});
|
|
3302
|
-
} catch {
|
|
3303
|
-
await apiPost(agentUrl, "/api/config/", { key, value });
|
|
3304
|
-
}
|
|
3305
|
-
success(`${icons.success} Set ${colors.bold(key)} = ${colors.cyan(value)}`);
|
|
3306
|
-
} else if (opts.get) {
|
|
3307
|
-
header("Configuration");
|
|
3308
|
-
blank();
|
|
3309
|
-
const data = await apiGet(agentUrl, `/api/config/${encodeURIComponent(opts.get)}`);
|
|
3310
|
-
kv(data.key, colors.bold(data.value));
|
|
3311
|
-
blank();
|
|
3312
|
-
} else if (opts.delete) {
|
|
3313
|
-
await apiDelete(agentUrl, `/api/config/${encodeURIComponent(opts.delete)}`);
|
|
3314
|
-
success(`${icons.success} Deleted configuration key: ${colors.bold(opts.delete)}`);
|
|
3315
|
-
} else if (opts.list) {
|
|
3316
|
-
header("Agent Configuration");
|
|
3317
|
-
blank();
|
|
3318
|
-
const data = await apiGet(agentUrl, "/api/config/");
|
|
3319
|
-
if (!data.configs || data.configs.length === 0) {
|
|
3320
|
-
info(`${icons.info} No configuration entries found.`);
|
|
3321
|
-
return;
|
|
3322
|
-
}
|
|
3323
|
-
const rows = data.configs.map((c) => ({
|
|
3324
|
-
Key: c.key,
|
|
3325
|
-
Value: c.value
|
|
3326
|
-
}));
|
|
3327
|
-
formatTable(rows);
|
|
3328
|
-
blank();
|
|
3329
|
-
info(`${icons.info} ${data.configs.length} configuration(s) found.`);
|
|
3330
|
-
} else {
|
|
3331
|
-
info(`${icons.info} Usage:`);
|
|
3332
|
-
info(` ${colors.bold("vibe config --list")} List all config values`);
|
|
3333
|
-
info(` ${colors.bold("vibe config --get <key>")} Get a config value`);
|
|
3334
|
-
info(` ${colors.bold("vibe config --set <key=value>")} Set a config value`);
|
|
3335
|
-
info(` ${colors.bold("vibe config --delete <key>")} Delete a config value`);
|
|
3336
|
-
}
|
|
3337
|
-
} catch (err) {
|
|
3338
|
-
fail(`Config operation failed: ${err.message}`);
|
|
3339
|
-
}
|
|
3340
|
-
});
|
|
3341
|
-
}
|
|
3342
|
-
// src/cli/commands/gateway-auth.cmd.ts
|
|
3343
|
-
var DEFAULT_AGENT_URL8 = "http://localhost:3005";
|
|
3344
|
-
function register16(program2) {
|
|
3345
|
-
const gatewayAuth = program2.command("gateway-auth").description("Manage gateway authentication for VibeControls agent");
|
|
3346
|
-
gatewayAuth.command("configure").description("Configure gateway authentication credentials").requiredOption("--global-url <url>", "Global gateway URL").requiredOption("--workspace-url <url>", "Workspace gateway URL").requiredOption("--client-id <id>", "OAuth client ID").requiredOption("--client-secret <secret>", "OAuth client secret").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL8).action(async (opts) => {
|
|
3347
|
-
try {
|
|
3348
|
-
const agentUrl = getAgentUrl(opts);
|
|
3349
|
-
header("Configure Gateway Authentication");
|
|
3350
|
-
blank();
|
|
3351
|
-
info(`${icons.info} Sending gateway auth configuration...`);
|
|
3352
|
-
blank();
|
|
3353
|
-
const data = await apiPost(agentUrl, "/api/agent/gateway-auth", {
|
|
3354
|
-
globalUrl: opts.globalUrl,
|
|
3355
|
-
workspaceUrl: opts.workspaceUrl,
|
|
3356
|
-
clientId: opts.clientId,
|
|
3357
|
-
clientSecret: opts.clientSecret
|
|
3358
|
-
});
|
|
3359
|
-
if (data.success) {
|
|
3360
|
-
success(`${icons.success} Gateway authentication configured successfully.`);
|
|
3361
|
-
blank();
|
|
3362
|
-
kv("Global URL", opts.globalUrl);
|
|
3363
|
-
kv("Workspace URL", opts.workspaceUrl);
|
|
3364
|
-
kv("Client ID", opts.clientId);
|
|
3365
|
-
kv("Client Secret", colors.dim("********"));
|
|
3366
|
-
} else {
|
|
3367
|
-
fail(data.message || "Failed to configure gateway authentication.");
|
|
3368
|
-
}
|
|
3369
|
-
blank();
|
|
3370
|
-
} catch (err) {
|
|
3371
|
-
fail(`Failed to configure gateway auth: ${err.message}`);
|
|
3372
|
-
}
|
|
3373
|
-
});
|
|
3374
|
-
gatewayAuth.command("status").description("Check gateway authentication status").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL8).action(async (opts) => {
|
|
3375
|
-
try {
|
|
3376
|
-
const agentUrl = getAgentUrl(opts);
|
|
3377
|
-
header("Gateway Authentication Status");
|
|
3378
|
-
blank();
|
|
3379
|
-
const data = await apiGet(agentUrl, "/api/agent/gateway-auth");
|
|
3380
|
-
kv("Configured", data.configured ? `${icons.success} ${colors.green("Yes")}` : `${icons.error} ${colors.red("No")}`);
|
|
3381
|
-
if (data.configured) {
|
|
3382
|
-
kv("Global URL", data.globalUrl || colors.dim("n/a"));
|
|
3383
|
-
kv("Workspace URL", data.workspaceUrl || colors.dim("n/a"));
|
|
3384
|
-
kv("Client ID", data.clientId || colors.dim("n/a"));
|
|
3385
|
-
kv("Authenticated", data.authenticated ? `${icons.success} ${colors.green("Yes")}` : `${icons.error} ${colors.red("No")}`);
|
|
3386
|
-
if (data.tokenExpiresAt) {
|
|
3387
|
-
kv("Token Expires", data.tokenExpiresAt);
|
|
3388
|
-
}
|
|
3389
|
-
} else {
|
|
3390
|
-
blank();
|
|
3391
|
-
info(`${icons.info} Run ${colors.bold("vibe gateway-auth configure")} to set up gateway authentication.`);
|
|
3392
|
-
}
|
|
3393
|
-
blank();
|
|
3394
|
-
} catch (err) {
|
|
3395
|
-
fail(`Failed to get gateway auth status: ${err.message}`);
|
|
3396
|
-
}
|
|
3397
|
-
});
|
|
3398
|
-
}
|
|
3399
|
-
// src/cli/commands/session.cmd.ts
|
|
3400
|
-
var DEFAULT_AGENT_URL9 = "http://localhost:3005";
|
|
3401
|
-
function register17(program2) {
|
|
3402
|
-
const cmd = program2.command("session").description("Manage terminal sessions");
|
|
3403
|
-
cmd.command("list").description("List all sessions").option("--system", "Show system sessions instead of user sessions").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3404
|
-
try {
|
|
3405
|
-
const url = getAgentUrl(options);
|
|
3406
|
-
const endpoint = options.system ? "/api/sessions?system=true" : "/api/sessions";
|
|
3407
|
-
const sessions = await apiGet(url, endpoint);
|
|
3408
|
-
if (!sessions || sessions.length === 0) {
|
|
3409
|
-
info("No sessions found.");
|
|
3410
|
-
return;
|
|
3411
|
-
}
|
|
3412
|
-
header("Sessions");
|
|
3413
|
-
formatTable(sessions.map((s) => ({
|
|
3414
|
-
ID: shortId(s.id),
|
|
3415
|
-
Name: s.name || "-",
|
|
3416
|
-
Status: formatStatus(s.status),
|
|
3417
|
-
Port: s.port ?? "-",
|
|
3418
|
-
Project: s.project || s.projectId || "-"
|
|
3419
|
-
})));
|
|
3420
|
-
} catch (err) {
|
|
3421
|
-
fail(err.message);
|
|
3422
|
-
}
|
|
3423
|
-
});
|
|
3424
|
-
cmd.command("create").description("Create a new session").requiredOption("--name <name>", "Session name").option("--project <id>", "Project ID", "default").option("--command <cmd>", "Initial command to run").option("--cwd <dir>", "Working directory").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3425
|
-
try {
|
|
3426
|
-
const url = getAgentUrl(options);
|
|
3427
|
-
const body = {
|
|
3428
|
-
name: options.name,
|
|
3429
|
-
project: options.project
|
|
3430
|
-
};
|
|
3431
|
-
if (options.command)
|
|
3432
|
-
body.command = options.command;
|
|
3433
|
-
if (options.cwd)
|
|
3434
|
-
body.cwd = options.cwd;
|
|
3435
|
-
const result = await apiPost(url, "/api/sessions/create", body);
|
|
3436
|
-
success(`Session created: ${shortId(result.id || result.sessionId)}`);
|
|
3437
|
-
kv("Name", options.name);
|
|
3438
|
-
kv("Project", options.project);
|
|
3439
|
-
} catch (err) {
|
|
3440
|
-
fail(err.message);
|
|
3441
|
-
}
|
|
3442
|
-
});
|
|
3443
|
-
cmd.command("kill").description("Kill a session").requiredOption("-i, --id <id>", "Session ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3444
|
-
try {
|
|
3445
|
-
const url = getAgentUrl(options);
|
|
3446
|
-
await apiDelete(url, `/api/sessions/${options.id}`);
|
|
3447
|
-
success(`Session ${shortId(options.id)} killed.`);
|
|
3448
|
-
} catch (err) {
|
|
3449
|
-
fail(err.message);
|
|
3450
|
-
}
|
|
3451
|
-
});
|
|
3452
|
-
cmd.command("exec").description("Execute a command in a session").requiredOption("-i, --id <id>", "Session ID").requiredOption("-c, --command <cmd>", "Command to execute").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3453
|
-
try {
|
|
3454
|
-
const url = getAgentUrl(options);
|
|
3455
|
-
const result = await apiPost(url, `/api/sessions/${options.id}/command`, { command: options.command });
|
|
3456
|
-
success("Command executed.");
|
|
3457
|
-
if (result?.output) {
|
|
3458
|
-
blank();
|
|
3459
|
-
console.log(result.output);
|
|
3460
|
-
}
|
|
3461
|
-
} catch (err) {
|
|
3462
|
-
fail(err.message);
|
|
3463
|
-
}
|
|
3464
|
-
});
|
|
3465
|
-
cmd.command("capture").description("Capture session terminal output").requiredOption("-i, --id <id>", "Session ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3466
|
-
try {
|
|
3467
|
-
const url = getAgentUrl(options);
|
|
3468
|
-
const result = await apiGet(url, `/api/sessions/${options.id}/capture`);
|
|
3469
|
-
if (result?.content || result?.output) {
|
|
3470
|
-
console.log(result.content || result.output);
|
|
3471
|
-
} else {
|
|
3472
|
-
info("No capture data available.");
|
|
3473
|
-
}
|
|
3474
|
-
} catch (err) {
|
|
3475
|
-
fail(err.message);
|
|
3476
|
-
}
|
|
3477
|
-
});
|
|
3478
|
-
cmd.command("keys").description("Send keys to a session").requiredOption("-i, --id <id>", "Session ID").requiredOption("-k, --keys <keys>", "Keys to send").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3479
|
-
try {
|
|
3480
|
-
const url = getAgentUrl(options);
|
|
3481
|
-
await apiPost(url, `/api/sessions/${options.id}/keys`, {
|
|
3482
|
-
keys: options.keys
|
|
3483
|
-
});
|
|
3484
|
-
success("Keys sent.");
|
|
3485
|
-
} catch (err) {
|
|
3486
|
-
fail(err.message);
|
|
3487
|
-
}
|
|
3488
|
-
});
|
|
3489
|
-
cmd.command("interrupt").description("Send interrupt signal to a session").requiredOption("-i, --id <id>", "Session ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3490
|
-
try {
|
|
3491
|
-
const url = getAgentUrl(options);
|
|
3492
|
-
await apiPost(url, `/api/sessions/${options.id}/interrupt`, {});
|
|
3493
|
-
success(`Session ${shortId(options.id)} interrupted.`);
|
|
3494
|
-
} catch (err) {
|
|
3495
|
-
fail(err.message);
|
|
3496
|
-
}
|
|
3497
|
-
});
|
|
3498
|
-
cmd.command("rename").description("Rename a session").requiredOption("-i, --id <id>", "Session ID").requiredOption("--name <name>", "New session name").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3499
|
-
try {
|
|
3500
|
-
const url = getAgentUrl(options);
|
|
3501
|
-
await apiPut(url, `/api/sessions/${options.id}/rename`, {
|
|
3502
|
-
name: options.name
|
|
3503
|
-
});
|
|
3504
|
-
success(`Session ${shortId(options.id)} renamed to "${options.name}".`);
|
|
3505
|
-
} catch (err) {
|
|
3506
|
-
fail(err.message);
|
|
3507
|
-
}
|
|
3508
|
-
});
|
|
3509
|
-
cmd.command("toggle-mouse").description("Toggle mouse support in a session").requiredOption("-i, --id <id>", "Session ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3510
|
-
try {
|
|
3511
|
-
const url = getAgentUrl(options);
|
|
3512
|
-
const result = await apiPost(url, `/api/sessions/${options.id}/toggle-mouse`, {});
|
|
3513
|
-
success(`Mouse support ${result?.mouseEnabled ? "enabled" : "toggled"} for session ${shortId(options.id)}.`);
|
|
3514
|
-
} catch (err) {
|
|
3515
|
-
fail(err.message);
|
|
3516
|
-
}
|
|
3517
|
-
});
|
|
3518
|
-
cmd.command("terminal-start").description("Start terminal for a session").requiredOption("-i, --id <id>", "Session ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3519
|
-
try {
|
|
3520
|
-
const url = getAgentUrl(options);
|
|
3521
|
-
const result = await apiPost(url, `/api/sessions/${options.id}/terminal`, {});
|
|
3522
|
-
success(`Terminal started for session ${shortId(options.id)}.`);
|
|
3523
|
-
if (result?.port)
|
|
3524
|
-
kv("Port", result.port);
|
|
3525
|
-
} catch (err) {
|
|
3526
|
-
fail(err.message);
|
|
3527
|
-
}
|
|
3528
|
-
});
|
|
3529
|
-
cmd.command("terminal-stop").description("Stop terminal for a session").requiredOption("-i, --id <id>", "Session ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3530
|
-
try {
|
|
3531
|
-
const url = getAgentUrl(options);
|
|
3532
|
-
await apiPost(url, `/api/sessions/${options.id}/terminal/stop`, {});
|
|
3533
|
-
success(`Terminal stopped for session ${shortId(options.id)}.`);
|
|
3534
|
-
} catch (err) {
|
|
3535
|
-
fail(err.message);
|
|
3536
|
-
}
|
|
3537
|
-
});
|
|
3538
|
-
cmd.command("health-check").description("Run health check on all sessions").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL9).action(async (options) => {
|
|
3539
|
-
try {
|
|
3540
|
-
const url = getAgentUrl(options);
|
|
3541
|
-
const result = await apiPost(url, "/api/sessions/health-check", {});
|
|
3542
|
-
success("Health check completed.");
|
|
3543
|
-
if (result?.healthy !== undefined)
|
|
3544
|
-
kv("Healthy", result.healthy);
|
|
3545
|
-
if (result?.checked !== undefined)
|
|
3546
|
-
kv("Checked", result.checked);
|
|
3547
|
-
if (result?.fixed !== undefined)
|
|
3548
|
-
kv("Fixed", result.fixed);
|
|
3549
|
-
} catch (err) {
|
|
3550
|
-
fail(err.message);
|
|
3551
|
-
}
|
|
3552
|
-
});
|
|
3553
|
-
}
|
|
3554
|
-
// src/cli/commands/tunnel.cmd.ts
|
|
3555
|
-
var DEFAULT_AGENT_URL10 = "http://localhost:3005";
|
|
3556
|
-
function register18(program2) {
|
|
3557
|
-
const cmd = program2.command("tunnel").description("Manage tunnels for exposing local ports");
|
|
3558
|
-
cmd.command("list").description("List all tunnels").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL10).action(async (options) => {
|
|
3559
|
-
try {
|
|
3560
|
-
const url = getAgentUrl(options);
|
|
3561
|
-
const tunnels = await apiGet(url, "/api/tunnels");
|
|
3562
|
-
if (!tunnels || tunnels.length === 0) {
|
|
3563
|
-
info("No tunnels found.");
|
|
3564
|
-
return;
|
|
3565
|
-
}
|
|
3566
|
-
header("Tunnels");
|
|
3567
|
-
formatTable(tunnels.map((t) => ({
|
|
3568
|
-
ID: shortId(t.id),
|
|
3569
|
-
Port: t.port ?? "-",
|
|
3570
|
-
"Public URL": t.publicUrl || t.url || "-",
|
|
3571
|
-
Status: formatStatus(t.status),
|
|
3572
|
-
PID: t.pid ?? "-"
|
|
3573
|
-
})));
|
|
3574
|
-
} catch (err) {
|
|
3575
|
-
fail(err.message);
|
|
3576
|
-
}
|
|
3577
|
-
});
|
|
3578
|
-
cmd.command("start").description("Start a new tunnel").requiredOption("-p, --port <port>", "Local port to expose").option("-s, --subdomain <subdomain>", "Preferred subdomain").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL10).action(async (options) => {
|
|
3579
|
-
try {
|
|
3580
|
-
const url = getAgentUrl(options);
|
|
3581
|
-
const body = {
|
|
3582
|
-
port: parseInt(options.port, 10)
|
|
3583
|
-
};
|
|
3584
|
-
if (options.subdomain)
|
|
3585
|
-
body.subdomain = options.subdomain;
|
|
3586
|
-
const result = await apiPost(url, "/api/tunnels/start", body);
|
|
3587
|
-
success("Tunnel started.");
|
|
3588
|
-
if (result?.id)
|
|
3589
|
-
kv("ID", shortId(result.id));
|
|
3590
|
-
if (result?.publicUrl || result?.url)
|
|
3591
|
-
kv("Public URL", result.publicUrl || result.url);
|
|
3592
|
-
kv("Port", options.port);
|
|
3593
|
-
} catch (err) {
|
|
3594
|
-
fail(err.message);
|
|
3595
|
-
}
|
|
3596
|
-
});
|
|
3597
|
-
cmd.command("stop").description("Stop a tunnel").requiredOption("-i, --id <id>", "Tunnel ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL10).action(async (options) => {
|
|
3598
|
-
try {
|
|
3599
|
-
const url = getAgentUrl(options);
|
|
3600
|
-
await apiPost(url, `/api/tunnels/${options.id}/stop`, {});
|
|
3601
|
-
success(`Tunnel ${shortId(options.id)} stopped.`);
|
|
3602
|
-
} catch (err) {
|
|
3603
|
-
fail(err.message);
|
|
3604
|
-
}
|
|
3605
|
-
});
|
|
3606
|
-
cmd.command("delete").description("Delete a tunnel").requiredOption("-i, --id <id>", "Tunnel ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL10).action(async (options) => {
|
|
3607
|
-
try {
|
|
3608
|
-
const url = getAgentUrl(options);
|
|
3609
|
-
await apiDelete(url, `/api/tunnels/${options.id}`);
|
|
3610
|
-
success(`Tunnel ${shortId(options.id)} deleted.`);
|
|
3611
|
-
} catch (err) {
|
|
3612
|
-
fail(err.message);
|
|
3613
|
-
}
|
|
3614
|
-
});
|
|
3615
|
-
cmd.command("status").description("Show tunnel status summary").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL10).action(async (options) => {
|
|
3616
|
-
try {
|
|
3617
|
-
const url = getAgentUrl(options);
|
|
3618
|
-
const result = await apiGet(url, "/api/tunnels/status");
|
|
3619
|
-
header("Tunnel Status");
|
|
3620
|
-
kv("Total", result?.total ?? 0);
|
|
3621
|
-
kv("Active", result?.active ?? 0);
|
|
3622
|
-
kv("Inactive", result?.inactive ?? 0);
|
|
3623
|
-
kv("Errored", result?.errored ?? 0);
|
|
3624
|
-
} catch (err) {
|
|
3625
|
-
fail(err.message);
|
|
3626
|
-
}
|
|
3627
|
-
});
|
|
3628
|
-
cmd.command("agent").description("Manage agent tunnel").option("--start", "Start the agent tunnel").option("--stop", "Stop the agent tunnel").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL10).action(async (options) => {
|
|
3629
|
-
try {
|
|
3630
|
-
const url = getAgentUrl(options);
|
|
3631
|
-
if (options.start) {
|
|
3632
|
-
const result = await apiPost(url, "/api/agent/tunnel", {
|
|
3633
|
-
action: "start"
|
|
3634
|
-
});
|
|
3635
|
-
success("Agent tunnel started.");
|
|
3636
|
-
if (result?.publicUrl || result?.url)
|
|
3637
|
-
kv("Public URL", result.publicUrl || result.url);
|
|
3638
|
-
} else if (options.stop) {
|
|
3639
|
-
const result = await apiPost(url, "/api/agent/tunnel", {
|
|
3640
|
-
action: "stop"
|
|
3641
|
-
});
|
|
3642
|
-
success("Agent tunnel stopped.");
|
|
3643
|
-
} else {
|
|
3644
|
-
const result = await apiGet(url, "/api/agent/tunnel");
|
|
3645
|
-
header("Agent Tunnel");
|
|
3646
|
-
kv("Status", formatStatus(result?.status || "unknown"));
|
|
3647
|
-
if (result?.publicUrl || result?.url)
|
|
3648
|
-
kv("Public URL", result.publicUrl || result.url);
|
|
3649
|
-
if (result?.port)
|
|
3650
|
-
kv("Port", result.port);
|
|
3651
|
-
}
|
|
3652
|
-
} catch (err) {
|
|
3653
|
-
fail(err.message);
|
|
3654
|
-
}
|
|
3655
|
-
});
|
|
3656
|
-
}
|
|
3657
|
-
// src/cli/commands/task.cmd.ts
|
|
3658
|
-
var DEFAULT_AGENT_URL11 = "http://localhost:3005";
|
|
3659
|
-
function register19(program2) {
|
|
3660
|
-
const cmd = program2.command("task").description("Manage background tasks");
|
|
3661
|
-
cmd.command("list").description("List tasks").option("--status <status>", "Filter by status").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL11).action(async (options) => {
|
|
3662
|
-
try {
|
|
3663
|
-
const url = getAgentUrl(options);
|
|
3664
|
-
const query = options.status ? `/api/tasks/?status=${encodeURIComponent(options.status)}` : "/api/tasks/";
|
|
3665
|
-
const data = await apiGet(url, query);
|
|
3666
|
-
const tasks = data.tasks || [];
|
|
3667
|
-
if (!tasks || tasks.length === 0) {
|
|
3668
|
-
info("No tasks found.");
|
|
3669
|
-
return;
|
|
3670
|
-
}
|
|
3671
|
-
header("Tasks");
|
|
3672
|
-
formatTable(tasks.map((t) => ({
|
|
3673
|
-
ID: shortId(t.id),
|
|
3674
|
-
Type: t.type || "-",
|
|
3675
|
-
Status: formatStatus(t.status),
|
|
3676
|
-
Created: t.createdAt ? timeAgo(t.createdAt) : "-"
|
|
3677
|
-
})));
|
|
3678
|
-
} catch (err) {
|
|
3679
|
-
fail(err.message);
|
|
3680
|
-
}
|
|
3681
|
-
});
|
|
3682
|
-
cmd.command("run").description("Run a new task").requiredOption("-c, --command <cmd>", "Command to run").option("--cwd <dir>", "Working directory").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL11).action(async (options) => {
|
|
3683
|
-
try {
|
|
3684
|
-
const url = getAgentUrl(options);
|
|
3685
|
-
const payload = { command: options.command };
|
|
3686
|
-
if (options.cwd)
|
|
3687
|
-
payload.cwd = options.cwd;
|
|
3688
|
-
const body = {
|
|
3689
|
-
type: "command",
|
|
3690
|
-
payload: JSON.stringify(payload)
|
|
3691
|
-
};
|
|
3692
|
-
const result = await apiPost(url, "/api/tasks/", body);
|
|
3693
|
-
success(`Task created: ${shortId(result?.id || result?.taskId)}`);
|
|
3694
|
-
} catch (err) {
|
|
3695
|
-
fail(err.message);
|
|
3696
|
-
}
|
|
3697
|
-
});
|
|
3698
|
-
cmd.command("cancel").description("Cancel a running task").requiredOption("-i, --id <id>", "Task ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL11).action(async (options) => {
|
|
3699
|
-
try {
|
|
3700
|
-
const url = getAgentUrl(options);
|
|
3701
|
-
await apiPut(url, `/api/tasks/${options.id}/cancel`, {});
|
|
3702
|
-
success(`Task ${shortId(options.id)} cancelled.`);
|
|
3703
|
-
} catch (err) {
|
|
3704
|
-
fail(err.message);
|
|
3705
|
-
}
|
|
3706
|
-
});
|
|
3707
|
-
}
|
|
3708
|
-
// src/cli/commands/git.cmd.ts
|
|
3709
|
-
var DEFAULT_AGENT_URL12 = "http://localhost:3005";
|
|
3710
|
-
function register20(program2) {
|
|
3711
|
-
const cmd = program2.command("git").description("Manage git repositories");
|
|
3712
|
-
cmd.command("list").description("List discovered git repositories").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL12).action(async (options) => {
|
|
3713
|
-
try {
|
|
3714
|
-
const url = getAgentUrl(options);
|
|
3715
|
-
const data = await apiGet(url, "/api/git");
|
|
3716
|
-
const repos = data.repositories || [];
|
|
3717
|
-
if (!repos || repos.length === 0) {
|
|
3718
|
-
info("No git repositories found.");
|
|
3719
|
-
return;
|
|
3720
|
-
}
|
|
3721
|
-
header("Git Repositories");
|
|
3722
|
-
formatTable(repos.map((r) => ({
|
|
3723
|
-
ID: shortId(r.id),
|
|
3724
|
-
Name: r.name || "-",
|
|
3725
|
-
Path: r.path || "-",
|
|
3726
|
-
Type: r.type || r.projectType || "-",
|
|
3727
|
-
Submodule: r.isSubmodule ? "Yes" : "No",
|
|
3728
|
-
Scanned: r.scannedAt ? timeAgo(r.scannedAt) : "-"
|
|
3729
|
-
})));
|
|
3730
|
-
} catch (err) {
|
|
3731
|
-
fail(err.message);
|
|
3732
|
-
}
|
|
3733
|
-
});
|
|
3734
|
-
cmd.command("scan").description("Scan a directory for git repositories").requiredOption("--dir <directory>", "Directory to scan").option("--depth <depth>", "Scan depth", "3").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL12).action(async (options) => {
|
|
3735
|
-
try {
|
|
3736
|
-
const url = getAgentUrl(options);
|
|
3737
|
-
const result = await apiPost(url, "/api/git/scan", {
|
|
3738
|
-
directory: options.dir,
|
|
3739
|
-
depth: parseInt(options.depth, 10)
|
|
3740
|
-
});
|
|
3741
|
-
success("Git scan completed.");
|
|
3742
|
-
if (result?.found !== undefined)
|
|
3743
|
-
kv("Repositories found", result.found);
|
|
3744
|
-
if (result?.repositories)
|
|
3745
|
-
kv("Repositories found", result.repositories.length);
|
|
3746
|
-
} catch (err) {
|
|
3747
|
-
fail(err.message);
|
|
3748
|
-
}
|
|
3749
|
-
});
|
|
3750
|
-
cmd.command("update").description("Update a git repository entry").requiredOption("-i, --id <id>", "Repository ID").option("--vite-port <port>", "Vite dev server port").option("--project-type <type>", "Project type").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL12).action(async (options) => {
|
|
3751
|
-
try {
|
|
3752
|
-
const url = getAgentUrl(options);
|
|
3753
|
-
const body = {};
|
|
3754
|
-
if (options.vitePort)
|
|
3755
|
-
body.vitePort = parseInt(options.vitePort, 10);
|
|
3756
|
-
if (options.projectType)
|
|
3757
|
-
body.projectType = options.projectType;
|
|
3758
|
-
await apiPut(url, `/api/git/${options.id}`, body);
|
|
3759
|
-
success(`Repository ${shortId(options.id)} updated.`);
|
|
3760
|
-
} catch (err) {
|
|
3761
|
-
fail(err.message);
|
|
3762
|
-
}
|
|
3763
|
-
});
|
|
3764
|
-
cmd.command("delete").description("Delete a git repository entry").requiredOption("-i, --id <id>", "Repository ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL12).action(async (options) => {
|
|
3765
|
-
try {
|
|
3766
|
-
const url = getAgentUrl(options);
|
|
3767
|
-
await apiDelete(url, `/api/git/${options.id}`);
|
|
3768
|
-
success(`Repository ${shortId(options.id)} deleted.`);
|
|
3769
|
-
} catch (err) {
|
|
3770
|
-
fail(err.message);
|
|
3771
|
-
}
|
|
3772
|
-
});
|
|
3773
|
-
cmd.command("fix-hierarchy").description("Fix repository parent-child hierarchy").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL12).action(async (options) => {
|
|
3774
|
-
try {
|
|
3775
|
-
const url = getAgentUrl(options);
|
|
3776
|
-
const result = await apiPost(url, "/api/git/fix-hierarchy", {});
|
|
3777
|
-
success("Hierarchy fix completed.");
|
|
3778
|
-
if (result?.fixed !== undefined)
|
|
3779
|
-
kv("Fixed", result.fixed);
|
|
3780
|
-
} catch (err) {
|
|
3781
|
-
fail(err.message);
|
|
3782
|
-
}
|
|
3783
|
-
});
|
|
3784
|
-
}
|
|
3785
|
-
// src/cli/commands/file.cmd.ts
|
|
3786
|
-
var DEFAULT_AGENT_URL13 = "http://localhost:3005";
|
|
3787
|
-
function register21(program2) {
|
|
3788
|
-
const cmd = program2.command("file").description("File system operations via agent");
|
|
3789
|
-
cmd.command("read").description("Read a file").requiredOption("--path <path>", "File path to read").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL13).action(async (options) => {
|
|
3790
|
-
try {
|
|
3791
|
-
const url = getAgentUrl(options);
|
|
3792
|
-
const result = await apiPost(url, "/api/files/read", {
|
|
3793
|
-
path: options.path
|
|
3794
|
-
});
|
|
3795
|
-
if (result?.content !== undefined) {
|
|
3796
|
-
console.log(result.content);
|
|
3797
|
-
} else {
|
|
3798
|
-
info("File is empty or has no content.");
|
|
3799
|
-
}
|
|
3800
|
-
} catch (err) {
|
|
3801
|
-
fail(err.message);
|
|
3802
|
-
}
|
|
3803
|
-
});
|
|
3804
|
-
cmd.command("write").description("Write content to a file").requiredOption("--path <path>", "File path to write").requiredOption("--content <content>", "Content to write").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL13).action(async (options) => {
|
|
3805
|
-
try {
|
|
3806
|
-
const url = getAgentUrl(options);
|
|
3807
|
-
await apiPost(url, "/api/files/write", {
|
|
3808
|
-
path: options.path,
|
|
3809
|
-
content: options.content
|
|
3810
|
-
});
|
|
3811
|
-
success(`File written: ${options.path}`);
|
|
3812
|
-
} catch (err) {
|
|
3813
|
-
fail(err.message);
|
|
3814
|
-
}
|
|
3815
|
-
});
|
|
3816
|
-
cmd.command("list").description("List files in a directory").requiredOption("--path <path>", "Directory path").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL13).action(async (options) => {
|
|
3817
|
-
try {
|
|
3818
|
-
const url = getAgentUrl(options);
|
|
3819
|
-
const result = await apiPost(url, "/api/files/list", {
|
|
3820
|
-
path: options.path
|
|
3821
|
-
});
|
|
3822
|
-
const files = result?.files || result;
|
|
3823
|
-
if (!files || Array.isArray(files) && files.length === 0) {
|
|
3824
|
-
info("Directory is empty.");
|
|
3825
|
-
return;
|
|
3826
|
-
}
|
|
3827
|
-
header(`Files in ${options.path}`);
|
|
3828
|
-
formatTable((Array.isArray(files) ? files : []).map((f) => ({
|
|
3829
|
-
Name: f.name || f.filename || "-",
|
|
3830
|
-
Type: f.type || (f.isDirectory ? "directory" : "file"),
|
|
3831
|
-
Size: f.size !== undefined ? formatBytes(f.size) : "-"
|
|
3832
|
-
})));
|
|
3833
|
-
} catch (err) {
|
|
3834
|
-
fail(err.message);
|
|
3835
|
-
}
|
|
3836
|
-
});
|
|
3837
|
-
cmd.command("exists").description("Check if a file exists").requiredOption("--path <path>", "File path to check").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL13).action(async (options) => {
|
|
3838
|
-
try {
|
|
3839
|
-
const url = getAgentUrl(options);
|
|
3840
|
-
const result = await apiPost(url, "/api/files/exists", {
|
|
3841
|
-
path: options.path
|
|
3842
|
-
});
|
|
3843
|
-
if (result?.exists) {
|
|
3844
|
-
success(`File exists: ${options.path}`);
|
|
3845
|
-
} else {
|
|
3846
|
-
info(`File does not exist: ${options.path}`);
|
|
3847
|
-
}
|
|
3848
|
-
} catch (err) {
|
|
3849
|
-
fail(err.message);
|
|
3850
|
-
}
|
|
3851
|
-
});
|
|
3852
|
-
cmd.command("delete").description("Delete a file").requiredOption("--path <path>", "File path to delete").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL13).action(async (options) => {
|
|
3853
|
-
try {
|
|
3854
|
-
const url = getAgentUrl(options);
|
|
3855
|
-
await apiPost(url, "/api/files/delete", {
|
|
3856
|
-
path: options.path
|
|
3857
|
-
});
|
|
3858
|
-
success(`File deleted: ${options.path}`);
|
|
3859
|
-
} catch (err) {
|
|
3860
|
-
fail(err.message);
|
|
3861
|
-
}
|
|
3862
|
-
});
|
|
3863
|
-
cmd.command("readme").description("Read the README file from a directory").requiredOption("--path <path>", "Directory path").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL13).action(async (options) => {
|
|
3864
|
-
try {
|
|
3865
|
-
const url = getAgentUrl(options);
|
|
3866
|
-
const result = await apiPost(url, "/api/files/readme", {
|
|
3867
|
-
path: options.path
|
|
3868
|
-
});
|
|
3869
|
-
if (result?.content) {
|
|
3870
|
-
console.log(result.content);
|
|
3871
|
-
} else {
|
|
3872
|
-
info("No README found in the specified directory.");
|
|
3873
|
-
}
|
|
3874
|
-
} catch (err) {
|
|
3875
|
-
fail(err.message);
|
|
3876
|
-
}
|
|
3877
|
-
});
|
|
3878
|
-
}
|
|
3879
|
-
// src/cli/commands/bookmark.cmd.ts
|
|
3880
|
-
var DEFAULT_AGENT_URL14 = "http://localhost:3005";
|
|
3881
|
-
function register22(program2) {
|
|
3882
|
-
const cmd = program2.command("bookmark").description("Manage command bookmarks");
|
|
3883
|
-
cmd.command("list").description("List bookmarks").option("--project <id>", "Filter by project ID").option("--category <cat>", "Filter by category").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL14).action(async (options) => {
|
|
3884
|
-
try {
|
|
3885
|
-
const url = getAgentUrl(options);
|
|
3886
|
-
const params = new URLSearchParams;
|
|
3887
|
-
if (options.project)
|
|
3888
|
-
params.set("project", options.project);
|
|
3889
|
-
if (options.category)
|
|
3890
|
-
params.set("category", options.category);
|
|
3891
|
-
const query = params.toString();
|
|
3892
|
-
const endpoint = query ? `/api/bookmarks?${query}` : "/api/bookmarks";
|
|
3893
|
-
const data = await apiGet(url, endpoint);
|
|
3894
|
-
const bookmarks = data.bookmarks || [];
|
|
3895
|
-
if (!bookmarks || bookmarks.length === 0) {
|
|
3896
|
-
info("No bookmarks found.");
|
|
3897
|
-
return;
|
|
3898
|
-
}
|
|
3899
|
-
header("Bookmarks");
|
|
3900
|
-
formatTable(bookmarks.map((b) => ({
|
|
3901
|
-
ID: shortId(b.id),
|
|
3902
|
-
Command: b.command || "-",
|
|
3903
|
-
Description: b.description || "-",
|
|
3904
|
-
Category: b.category || "-",
|
|
3905
|
-
Project: b.project || b.projectId || "-"
|
|
3906
|
-
})));
|
|
3907
|
-
} catch (err) {
|
|
3908
|
-
fail(err.message);
|
|
3909
|
-
}
|
|
3910
|
-
});
|
|
3911
|
-
cmd.command("create").description("Create a new bookmark").requiredOption("-c, --command <cmd>", "Command to bookmark").option("--description <desc>", "Bookmark description").option("--category <cat>", "Category").option("--project <id>", "Project ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL14).action(async (options) => {
|
|
3912
|
-
try {
|
|
3913
|
-
const url = getAgentUrl(options);
|
|
3914
|
-
const body = { command: options.command };
|
|
3915
|
-
if (options.description)
|
|
3916
|
-
body.description = options.description;
|
|
3917
|
-
if (options.category)
|
|
3918
|
-
body.category = options.category;
|
|
3919
|
-
if (options.project)
|
|
3920
|
-
body.project = options.project;
|
|
3921
|
-
const result = await apiPost(url, "/api/bookmarks", body);
|
|
3922
|
-
success(`Bookmark created: ${shortId(result?.id)}`);
|
|
3923
|
-
} catch (err) {
|
|
3924
|
-
fail(err.message);
|
|
3925
|
-
}
|
|
3926
|
-
});
|
|
3927
|
-
cmd.command("update").description("Update a bookmark").requiredOption("-i, --id <id>", "Bookmark ID").option("-c, --command <cmd>", "New command").option("--description <desc>", "New description").option("--category <cat>", "New category").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL14).action(async (options) => {
|
|
3928
|
-
try {
|
|
3929
|
-
const url = getAgentUrl(options);
|
|
3930
|
-
const body = {};
|
|
3931
|
-
if (options.command)
|
|
3932
|
-
body.command = options.command;
|
|
3933
|
-
if (options.description)
|
|
3934
|
-
body.description = options.description;
|
|
3935
|
-
if (options.category)
|
|
3936
|
-
body.category = options.category;
|
|
3937
|
-
if (Object.keys(body).length === 0) {
|
|
3938
|
-
fail("No fields to update. Provide at least one of --command, --description, or --category.");
|
|
3939
|
-
return;
|
|
3940
|
-
}
|
|
3941
|
-
await apiPut(url, `/api/bookmarks/${options.id}`, body);
|
|
3942
|
-
success(`Bookmark ${shortId(options.id)} updated.`);
|
|
3943
|
-
} catch (err) {
|
|
3944
|
-
fail(err.message);
|
|
3945
|
-
}
|
|
3946
|
-
});
|
|
3947
|
-
cmd.command("delete").description("Delete a bookmark").requiredOption("-i, --id <id>", "Bookmark ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL14).action(async (options) => {
|
|
3948
|
-
try {
|
|
3949
|
-
const url = getAgentUrl(options);
|
|
3950
|
-
await apiDelete(url, `/api/bookmarks/${options.id}`);
|
|
3951
|
-
success(`Bookmark ${shortId(options.id)} deleted.`);
|
|
3952
|
-
} catch (err) {
|
|
3953
|
-
fail(err.message);
|
|
3954
|
-
}
|
|
3955
|
-
});
|
|
3956
|
-
cmd.command("execute").description("Execute a bookmarked command").requiredOption("-i, --id <id>", "Bookmark ID").option("--session <sessionId>", "Session ID to execute in").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL14).action(async (options) => {
|
|
3957
|
-
try {
|
|
3958
|
-
const url = getAgentUrl(options);
|
|
3959
|
-
const body = {};
|
|
3960
|
-
if (options.session)
|
|
3961
|
-
body.sessionId = options.session;
|
|
3962
|
-
const result = await apiPost(url, `/api/bookmarks/${options.id}/execute`, body);
|
|
3963
|
-
success(`Bookmark ${shortId(options.id)} executed.`);
|
|
3964
|
-
if (result?.output) {
|
|
3965
|
-
console.log(result.output);
|
|
3966
|
-
}
|
|
3967
|
-
} catch (err) {
|
|
3968
|
-
fail(err.message);
|
|
3969
|
-
}
|
|
3970
|
-
});
|
|
3971
|
-
}
|
|
3972
|
-
// src/cli/commands/notify.cmd.ts
|
|
3973
|
-
var DEFAULT_AGENT_URL15 = "http://localhost:3005";
|
|
3974
|
-
function register23(program2) {
|
|
3975
|
-
const cmd = program2.command("notify").description("Manage notifications");
|
|
3976
|
-
cmd.command("list").description("List notifications").option("--unread", "Show only unread notifications").option("--project <id>", "Filter by project ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL15).action(async (options) => {
|
|
3977
|
-
try {
|
|
3978
|
-
const url = getAgentUrl(options);
|
|
3979
|
-
const params = new URLSearchParams;
|
|
3980
|
-
if (options.unread)
|
|
3981
|
-
params.set("unread", "true");
|
|
3982
|
-
if (options.project)
|
|
3983
|
-
params.set("project", options.project);
|
|
3984
|
-
const query = params.toString();
|
|
3985
|
-
const endpoint = query ? `/api/notifications?${query}` : "/api/notifications";
|
|
3986
|
-
const data = await apiGet(url, endpoint);
|
|
3987
|
-
const notifications = data.notifications || [];
|
|
3988
|
-
if (!notifications || notifications.length === 0) {
|
|
3989
|
-
info("No notifications found.");
|
|
3990
|
-
return;
|
|
3991
|
-
}
|
|
3992
|
-
header("Notifications");
|
|
3993
|
-
blank();
|
|
3994
|
-
for (const n of notifications) {
|
|
3995
|
-
const icon = formatNotificationType(n.type);
|
|
3996
|
-
const time = n.createdAt ? colors.dim(timeAgo(n.createdAt)) : "";
|
|
3997
|
-
const title = colors.bold(n.title || "Untitled");
|
|
3998
|
-
const id = colors.dim(`[${shortId(n.id)}]`);
|
|
3999
|
-
console.log(` ${icon} ${title} ${id} ${time}`);
|
|
4000
|
-
if (n.message) {
|
|
4001
|
-
console.log(` ${n.message}`);
|
|
4002
|
-
}
|
|
4003
|
-
blank();
|
|
4004
|
-
}
|
|
4005
|
-
} catch (err) {
|
|
4006
|
-
fail(err.message);
|
|
4007
|
-
}
|
|
4008
|
-
});
|
|
4009
|
-
cmd.command("create").description("Create a notification").requiredOption("--title <title>", "Notification title").requiredOption("--message <msg>", "Notification message").option("--type <type>", "Notification type", "info").option("--project <id>", "Project ID").option("--session <name>", "Session name").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL15).action(async (options) => {
|
|
4010
|
-
try {
|
|
4011
|
-
const url = getAgentUrl(options);
|
|
4012
|
-
const body = {
|
|
4013
|
-
title: options.title,
|
|
4014
|
-
message: options.message,
|
|
4015
|
-
type: options.type
|
|
4016
|
-
};
|
|
4017
|
-
if (options.project)
|
|
4018
|
-
body.project = options.project;
|
|
4019
|
-
if (options.session)
|
|
4020
|
-
body.session = options.session;
|
|
4021
|
-
const result = await apiPost(url, "/api/notifications", body);
|
|
4022
|
-
success(`Notification created: ${shortId(result?.id)}`);
|
|
4023
|
-
} catch (err) {
|
|
4024
|
-
fail(err.message);
|
|
4025
|
-
}
|
|
4026
|
-
});
|
|
4027
|
-
cmd.command("delete").description("Delete a notification").requiredOption("-i, --id <id>", "Notification ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL15).action(async (options) => {
|
|
4028
|
-
try {
|
|
4029
|
-
const url = getAgentUrl(options);
|
|
4030
|
-
await apiDelete(url, `/api/notifications/${options.id}`);
|
|
4031
|
-
success(`Notification ${shortId(options.id)} deleted.`);
|
|
4032
|
-
} catch (err) {
|
|
4033
|
-
fail(err.message);
|
|
4034
|
-
}
|
|
4035
|
-
});
|
|
4036
|
-
cmd.command("read-all").description("Mark all notifications as read").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL15).action(async (options) => {
|
|
4037
|
-
try {
|
|
4038
|
-
const url = getAgentUrl(options);
|
|
4039
|
-
await apiPut(url, "/api/notifications/read-all", {});
|
|
4040
|
-
success("All notifications marked as read.");
|
|
4041
|
-
} catch (err) {
|
|
4042
|
-
fail(err.message);
|
|
4043
|
-
}
|
|
4044
|
-
});
|
|
4045
|
-
cmd.command("clear-old").description("Clear old notifications").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL15).action(async (options) => {
|
|
4046
|
-
try {
|
|
4047
|
-
const url = getAgentUrl(options);
|
|
4048
|
-
await apiDelete(url, "/api/notifications/clear/old");
|
|
4049
|
-
success("Old notifications cleared.");
|
|
4050
|
-
} catch (err) {
|
|
4051
|
-
fail(err.message);
|
|
4052
|
-
}
|
|
4053
|
-
});
|
|
4054
|
-
cmd.command("webhook").description("Send a webhook notification to a session").requiredOption("--session <sessionId>", "Target session ID").option("--title <title>", "Notification title").option("--message <msg>", "Notification message").option("--type <type>", "Notification type", "info").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL15).action(async (options) => {
|
|
4055
|
-
try {
|
|
4056
|
-
const url = getAgentUrl(options);
|
|
4057
|
-
const body = {};
|
|
4058
|
-
if (options.title)
|
|
4059
|
-
body.title = options.title;
|
|
4060
|
-
if (options.message)
|
|
4061
|
-
body.message = options.message;
|
|
4062
|
-
if (options.type)
|
|
4063
|
-
body.type = options.type;
|
|
4064
|
-
await apiPost(url, `/api/notifications/webhook/${options.session}`, body);
|
|
4065
|
-
success(`Webhook notification sent to session ${shortId(options.session)}.`);
|
|
4066
|
-
} catch (err) {
|
|
4067
|
-
fail(err.message);
|
|
4068
|
-
}
|
|
4069
|
-
});
|
|
4070
|
-
}
|
|
4071
|
-
// src/cli/commands/project.cmd.ts
|
|
4072
|
-
var DEFAULT_AGENT_URL16 = "http://localhost:3005";
|
|
4073
|
-
function register24(program2) {
|
|
4074
|
-
const cmd = program2.command("project").description("Manage projects");
|
|
4075
|
-
cmd.command("list").description("List all projects").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL16).action(async (options) => {
|
|
4076
|
-
try {
|
|
4077
|
-
const url = getAgentUrl(options);
|
|
4078
|
-
const data = await apiGet(url, "/api/projects");
|
|
4079
|
-
const projects = data.projects || [];
|
|
4080
|
-
if (!projects || projects.length === 0) {
|
|
4081
|
-
info("No projects found.");
|
|
4082
|
-
return;
|
|
4083
|
-
}
|
|
4084
|
-
header("Projects");
|
|
4085
|
-
formatTable(projects.map((p) => ({
|
|
4086
|
-
ID: shortId(p.id),
|
|
4087
|
-
Name: p.name || "-",
|
|
4088
|
-
Path: p.path || "-",
|
|
4089
|
-
Type: p.type || p.projectType || "-",
|
|
4090
|
-
Framework: p.framework || "-",
|
|
4091
|
-
"Git Branch": p.gitBranch || p.branch || "-"
|
|
4092
|
-
})));
|
|
4093
|
-
} catch (err) {
|
|
4094
|
-
fail(err.message);
|
|
4095
|
-
}
|
|
4096
|
-
});
|
|
4097
|
-
cmd.command("scan").description("Scan a directory for projects").requiredOption("--dir <directory>", "Directory to scan").option("--depth <depth>", "Scan depth", "3").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL16).action(async (options) => {
|
|
4098
|
-
try {
|
|
4099
|
-
const url = getAgentUrl(options);
|
|
4100
|
-
const result = await apiPost(url, "/api/projects/scan", {
|
|
4101
|
-
directory: options.dir,
|
|
4102
|
-
depth: parseInt(options.depth, 10)
|
|
4103
|
-
});
|
|
4104
|
-
success("Project scan completed.");
|
|
4105
|
-
if (result?.found !== undefined)
|
|
4106
|
-
kv("Projects found", result.found);
|
|
4107
|
-
if (result?.projects)
|
|
4108
|
-
kv("Projects found", result.projects.length);
|
|
4109
|
-
} catch (err) {
|
|
4110
|
-
fail(err.message);
|
|
4111
|
-
}
|
|
4112
|
-
});
|
|
4113
|
-
cmd.command("scan-remote").description("Scan remote workspace for projects").requiredOption("--workspace-id <id>", "Workspace ID").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL16).action(async (options) => {
|
|
4114
|
-
try {
|
|
4115
|
-
const url = getAgentUrl(options);
|
|
4116
|
-
const result = await apiPost(url, "/api/projects/scan-remote", {
|
|
4117
|
-
workspaceId: options.workspaceId
|
|
4118
|
-
});
|
|
4119
|
-
success("Remote project scan completed.");
|
|
4120
|
-
if (result?.found !== undefined)
|
|
4121
|
-
kv("Projects found", result.found);
|
|
4122
|
-
if (result?.projects)
|
|
4123
|
-
kv("Projects found", result.projects.length);
|
|
4124
|
-
} catch (err) {
|
|
4125
|
-
fail(err.message);
|
|
4126
|
-
}
|
|
4127
|
-
});
|
|
4128
|
-
}
|
|
4129
|
-
// src/cli/commands/plugin.cmd.ts
|
|
4130
|
-
var DEFAULT_AGENT_URL17 = "http://localhost:3005";
|
|
4131
|
-
function register25(program2) {
|
|
4132
|
-
const cmd = program2.command("plugin").description("Manage plugins");
|
|
4133
|
-
cmd.command("list").description("List installed plugins").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL17).action(async (options) => {
|
|
4134
|
-
try {
|
|
4135
|
-
const url = getAgentUrl(options);
|
|
4136
|
-
let plugins;
|
|
4137
|
-
try {
|
|
4138
|
-
const data = await apiGet(url, "/api/plugins");
|
|
4139
|
-
plugins = data.plugins || [];
|
|
4140
|
-
} catch {
|
|
4141
|
-
warn("Agent not reachable. Attempting local plugin registry...");
|
|
4142
|
-
try {
|
|
4143
|
-
const { PluginManager: PluginManager2 } = await import("./plugin-system-bg1pzjj9.js");
|
|
4144
|
-
const pm = new PluginManager2;
|
|
4145
|
-
plugins = pm.getPluginDetails() || [];
|
|
4146
|
-
} catch {
|
|
4147
|
-
fail("Could not list plugins from agent or local registry.");
|
|
4148
|
-
return;
|
|
4149
|
-
}
|
|
4150
|
-
}
|
|
4151
|
-
if (!plugins || plugins.length === 0) {
|
|
4152
|
-
info("No plugins installed.");
|
|
4153
|
-
return;
|
|
4154
|
-
}
|
|
4155
|
-
header("Installed Plugins");
|
|
4156
|
-
formatTable(plugins.map((p) => ({
|
|
4157
|
-
Name: p.name || p.package || "-",
|
|
4158
|
-
Version: p.version || "-",
|
|
4159
|
-
Status: p.status || p.enabled ? "enabled" : "disabled",
|
|
4160
|
-
Description: p.description || "-"
|
|
4161
|
-
})));
|
|
4162
|
-
} catch (err) {
|
|
4163
|
-
fail(err.message);
|
|
4164
|
-
}
|
|
4165
|
-
});
|
|
4166
|
-
cmd.command("install").description("Install a plugin").argument("<package>", "NPM package name to install").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL17).action(async (packageName, options) => {
|
|
4167
|
-
try {
|
|
4168
|
-
const url = getAgentUrl(options);
|
|
4169
|
-
try {
|
|
4170
|
-
const result = await apiPost(url, "/api/plugins/install", {
|
|
4171
|
-
package: packageName
|
|
4172
|
-
});
|
|
4173
|
-
success(`Plugin "${packageName}" installed.`);
|
|
4174
|
-
if (result?.version)
|
|
4175
|
-
kv("Version", result.version);
|
|
4176
|
-
} catch {
|
|
4177
|
-
warn("Agent not reachable. Attempting local install...");
|
|
4178
|
-
try {
|
|
4179
|
-
const { PluginManager: PluginManager2 } = await import("./plugin-system-bg1pzjj9.js");
|
|
4180
|
-
const pm = new PluginManager2;
|
|
4181
|
-
await pm.install(packageName);
|
|
4182
|
-
success(`Plugin "${packageName}" installed locally.`);
|
|
4183
|
-
} catch (localErr) {
|
|
4184
|
-
fail(`Could not install plugin via agent or locally: ${localErr.message}`);
|
|
4185
|
-
}
|
|
4186
|
-
}
|
|
4187
|
-
} catch (err) {
|
|
4188
|
-
fail(err.message);
|
|
4189
|
-
}
|
|
4190
|
-
});
|
|
4191
|
-
cmd.command("remove").description("Remove a plugin").argument("<package>", "NPM package name to remove").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL17).action(async (packageName, options) => {
|
|
4192
|
-
try {
|
|
4193
|
-
const url = getAgentUrl(options);
|
|
4194
|
-
try {
|
|
4195
|
-
await apiPost(url, "/api/plugins/remove", {
|
|
4196
|
-
package: packageName
|
|
4197
|
-
});
|
|
4198
|
-
success(`Plugin "${packageName}" removed.`);
|
|
4199
|
-
} catch {
|
|
4200
|
-
warn("Agent not reachable. Attempting local removal...");
|
|
4201
|
-
try {
|
|
4202
|
-
const { PluginManager: PluginManager2 } = await import("./plugin-system-bg1pzjj9.js");
|
|
4203
|
-
const pm = new PluginManager2;
|
|
4204
|
-
await pm.remove(packageName);
|
|
4205
|
-
success(`Plugin "${packageName}" removed locally.`);
|
|
4206
|
-
} catch (localErr) {
|
|
4207
|
-
fail(`Could not remove plugin via agent or locally: ${localErr.message}`);
|
|
4208
|
-
}
|
|
4209
|
-
}
|
|
4210
|
-
} catch (err) {
|
|
4211
|
-
fail(err.message);
|
|
4212
|
-
}
|
|
4213
|
-
});
|
|
4214
|
-
cmd.command("reload").description("Reload all plugins").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL17).action(async (options) => {
|
|
4215
|
-
try {
|
|
4216
|
-
const url = getAgentUrl(options);
|
|
4217
|
-
await apiPost(url, "/api/plugins/reload", {});
|
|
4218
|
-
success("Plugins reloaded.");
|
|
4219
|
-
} catch (err) {
|
|
4220
|
-
fail(err.message);
|
|
4221
|
-
}
|
|
4222
|
-
});
|
|
4223
|
-
cmd.command("available").description("Show available plugins").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL17).action(async (options) => {
|
|
4224
|
-
try {
|
|
4225
|
-
const url = getAgentUrl(options);
|
|
4226
|
-
const availData = await apiGet(url, "/api/plugins/available");
|
|
4227
|
-
const plugins = availData.plugins || [];
|
|
4228
|
-
if (!plugins || plugins.length === 0) {
|
|
4229
|
-
info("No available plugins found.");
|
|
4230
|
-
return;
|
|
4231
|
-
}
|
|
4232
|
-
header("Available Plugins");
|
|
4233
|
-
formatTable(plugins.map((p) => ({
|
|
4234
|
-
Name: p.name || p.package || "-",
|
|
4235
|
-
Version: p.version || p.latestVersion || "-",
|
|
4236
|
-
Description: p.description || "-"
|
|
4237
|
-
})));
|
|
4238
|
-
} catch (err) {
|
|
4239
|
-
fail(err.message);
|
|
4240
|
-
}
|
|
4241
|
-
});
|
|
4242
|
-
}
|
|
4243
|
-
// src/cli/commands/state.cmd.ts
|
|
4244
|
-
var DEFAULT_AGENT_URL18 = "http://localhost:3005";
|
|
4245
|
-
function register26(program2) {
|
|
4246
|
-
const cmd = program2.command("state").description("Manage plugin key-value state");
|
|
4247
|
-
cmd.command("list").description("List all state entries for a plugin").argument("<plugin>", "Plugin name").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL18).action(async (plugin, options) => {
|
|
4248
|
-
try {
|
|
4249
|
-
const url = getAgentUrl(options);
|
|
4250
|
-
const entries = await apiGet(url, `/api/plugin-state/${encodeURIComponent(plugin)}`);
|
|
4251
|
-
if (!entries || typeof entries === "object" && Object.keys(entries).length === 0) {
|
|
4252
|
-
info(`No state entries for plugin "${plugin}".`);
|
|
4253
|
-
return;
|
|
4254
|
-
}
|
|
4255
|
-
header(`State: ${plugin}`);
|
|
4256
|
-
blank();
|
|
4257
|
-
if (Array.isArray(entries)) {
|
|
4258
|
-
for (const entry of entries) {
|
|
4259
|
-
kv(entry.key, JSON.stringify(entry.value));
|
|
4260
|
-
}
|
|
4261
|
-
} else if (typeof entries === "object") {
|
|
4262
|
-
for (const [key, value] of Object.entries(entries)) {
|
|
4263
|
-
kv(key, JSON.stringify(value));
|
|
4264
|
-
}
|
|
4265
|
-
}
|
|
4266
|
-
} catch (err) {
|
|
4267
|
-
fail(err.message);
|
|
4268
|
-
}
|
|
4269
|
-
});
|
|
4270
|
-
cmd.command("get").description("Get a state value").argument("<plugin>", "Plugin name").argument("<key>", "State key").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL18).action(async (plugin, key, options) => {
|
|
4271
|
-
try {
|
|
4272
|
-
const url = getAgentUrl(options);
|
|
4273
|
-
const result = await apiGet(url, `/api/plugin-state/${encodeURIComponent(plugin)}/${encodeURIComponent(key)}`);
|
|
4274
|
-
if (result?.value !== undefined) {
|
|
4275
|
-
header(`${plugin} / ${key}`);
|
|
4276
|
-
console.log(typeof result.value === "string" ? result.value : JSON.stringify(result.value, null, 2));
|
|
4277
|
-
} else {
|
|
4278
|
-
info(`No value found for key "${key}" in plugin "${plugin}".`);
|
|
4279
|
-
}
|
|
4280
|
-
} catch (err) {
|
|
4281
|
-
fail(err.message);
|
|
4282
|
-
}
|
|
4283
|
-
});
|
|
4284
|
-
cmd.command("set").description("Set a state value").argument("<plugin>", "Plugin name").argument("<key>", "State key").argument("<value>", "Value to set").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL18).action(async (plugin, key, value, options) => {
|
|
4285
|
-
try {
|
|
4286
|
-
const url = getAgentUrl(options);
|
|
4287
|
-
let parsedValue = value;
|
|
4288
|
-
try {
|
|
4289
|
-
parsedValue = JSON.parse(value);
|
|
4290
|
-
} catch {}
|
|
4291
|
-
await apiPut(url, `/api/plugin-state/${encodeURIComponent(plugin)}/${encodeURIComponent(key)}`, { value: parsedValue });
|
|
4292
|
-
success(`State set: ${plugin}/${key}`);
|
|
4293
|
-
} catch (err) {
|
|
4294
|
-
fail(err.message);
|
|
4295
|
-
}
|
|
4296
|
-
});
|
|
4297
|
-
cmd.command("unset").description("Remove a state value").argument("<plugin>", "Plugin name").argument("<key>", "State key").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL18).action(async (plugin, key, options) => {
|
|
4298
|
-
try {
|
|
4299
|
-
const url = getAgentUrl(options);
|
|
4300
|
-
await apiDelete(url, `/api/plugin-state/${encodeURIComponent(plugin)}/${encodeURIComponent(key)}`);
|
|
4301
|
-
success(`State removed: ${plugin}/${key}`);
|
|
4302
|
-
} catch (err) {
|
|
4303
|
-
fail(err.message);
|
|
4304
|
-
}
|
|
4305
|
-
});
|
|
4306
|
-
}
|
|
4307
|
-
// src/cli/commands/log.cmd.ts
|
|
4308
|
-
var DEFAULT_AGENT_URL19 = "http://localhost:3005";
|
|
4309
|
-
function register27(program2) {
|
|
4310
|
-
const cmd = program2.command("log").description("View and stream logs");
|
|
4311
|
-
cmd.command("list").description("List recent log entries").option("--level <level>", "Minimum log level", "info").option("--limit <n>", "Number of entries to show", "50").option("--source <source>", "Filter by source").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL19).action(async (options) => {
|
|
4312
|
-
try {
|
|
4313
|
-
const url = getAgentUrl(options);
|
|
4314
|
-
const params = new URLSearchParams;
|
|
4315
|
-
params.set("level", options.level);
|
|
4316
|
-
params.set("limit", options.limit);
|
|
4317
|
-
if (options.source)
|
|
4318
|
-
params.set("source", options.source);
|
|
4319
|
-
const logs = await apiGet(url, `/api/logs?${params.toString()}`);
|
|
4320
|
-
if (!logs || logs.length === 0) {
|
|
4321
|
-
info("No log entries found.");
|
|
4322
|
-
return;
|
|
4323
|
-
}
|
|
4324
|
-
header("Logs");
|
|
4325
|
-
blank();
|
|
4326
|
-
for (const entry of logs) {
|
|
4327
|
-
const level = formatLogLevel(entry.level);
|
|
4328
|
-
const time = entry.timestamp ? colors.dim(timeAgo(entry.timestamp)) : "";
|
|
4329
|
-
const source = entry.source ? colors.cyan(`[${entry.source}]`) : "";
|
|
4330
|
-
const message = entry.message || "";
|
|
4331
|
-
console.log(` ${level} ${source} ${message} ${time}`);
|
|
4332
|
-
}
|
|
4333
|
-
} catch (err) {
|
|
4334
|
-
fail(err.message);
|
|
4335
|
-
}
|
|
4336
|
-
});
|
|
4337
|
-
cmd.command("stream").description("Stream logs in real-time (SSE)").option("--level <level>", "Minimum log level", "info").option("--agent-url <url>", "Agent URL", DEFAULT_AGENT_URL19).action(async (options) => {
|
|
4338
|
-
try {
|
|
4339
|
-
const url = getAgentUrl(options);
|
|
4340
|
-
const params = new URLSearchParams;
|
|
4341
|
-
params.set("level", options.level);
|
|
4342
|
-
const streamUrl = `${url}/api/logs/stream?${params.toString()}`;
|
|
4343
|
-
info(`Streaming logs from ${url} (level: ${options.level})...`);
|
|
4344
|
-
info(`Press Ctrl+C to stop.
|
|
4345
|
-
`);
|
|
4346
|
-
const response = await fetch(streamUrl, {
|
|
4347
|
-
headers: { Accept: "text/event-stream" }
|
|
4348
|
-
});
|
|
4349
|
-
if (!response.ok) {
|
|
4350
|
-
fail(`Failed to connect to log stream: ${response.status} ${response.statusText}`);
|
|
4351
|
-
return;
|
|
4352
|
-
}
|
|
4353
|
-
if (!response.body) {
|
|
4354
|
-
fail("No response body for SSE stream.");
|
|
4355
|
-
return;
|
|
4356
|
-
}
|
|
4357
|
-
const decoder = new TextDecoder;
|
|
4358
|
-
const reader = response.body.getReader();
|
|
4359
|
-
const cleanup = () => {
|
|
4360
|
-
reader.cancel().catch(() => {});
|
|
4361
|
-
console.log(`
|
|
4362
|
-
Log stream ended.`);
|
|
4363
|
-
process.exit(0);
|
|
4364
|
-
};
|
|
4365
|
-
process.on("SIGINT", cleanup);
|
|
4366
|
-
process.on("SIGTERM", cleanup);
|
|
4367
|
-
let buffer = "";
|
|
4368
|
-
while (true) {
|
|
4369
|
-
const { done, value } = await reader.read();
|
|
4370
|
-
if (done)
|
|
4371
|
-
break;
|
|
4372
|
-
buffer += decoder.decode(value, { stream: true });
|
|
4373
|
-
const lines = buffer.split(`
|
|
4374
|
-
`);
|
|
4375
|
-
buffer = lines.pop() || "";
|
|
4376
|
-
for (const line of lines) {
|
|
4377
|
-
if (line.startsWith("data: ")) {
|
|
4378
|
-
const data = line.slice(6).trim();
|
|
4379
|
-
if (!data || data === "[DONE]")
|
|
4380
|
-
continue;
|
|
4381
|
-
try {
|
|
4382
|
-
const entry = JSON.parse(data);
|
|
4383
|
-
const level = formatLogLevel(entry.level);
|
|
4384
|
-
const source = entry.source ? colors.cyan(`[${entry.source}]`) : "";
|
|
4385
|
-
const message = entry.message || "";
|
|
4386
|
-
const time = entry.timestamp ? colors.dim(new Date(entry.timestamp).toLocaleTimeString()) : "";
|
|
4387
|
-
console.log(`${level} ${source} ${message} ${time}`);
|
|
4388
|
-
} catch {
|
|
4389
|
-
if (data.trim())
|
|
4390
|
-
console.log(data);
|
|
4391
|
-
}
|
|
4392
|
-
}
|
|
4393
|
-
}
|
|
4394
|
-
}
|
|
4395
|
-
} catch (err) {
|
|
4396
|
-
if (err.name === "AbortError")
|
|
4397
|
-
return;
|
|
4398
|
-
fail(err.message);
|
|
4399
|
-
}
|
|
4400
|
-
});
|
|
4401
|
-
}
|
|
4402
|
-
function formatLogLevel(level) {
|
|
4403
|
-
if (!level)
|
|
4404
|
-
return colors.dim("???");
|
|
4405
|
-
switch (level.toLowerCase()) {
|
|
4406
|
-
case "error":
|
|
4407
|
-
return colors.red(colors.bold("ERR"));
|
|
4408
|
-
case "warn":
|
|
4409
|
-
case "warning":
|
|
4410
|
-
return colors.yellow("WRN");
|
|
4411
|
-
case "info":
|
|
4412
|
-
return colors.blue("INF");
|
|
4413
|
-
case "debug":
|
|
4414
|
-
return colors.gray("DBG");
|
|
4415
|
-
case "trace":
|
|
4416
|
-
return colors.dim("TRC");
|
|
4417
|
-
default:
|
|
4418
|
-
return colors.dim(level.toUpperCase().slice(0, 3));
|
|
4419
|
-
}
|
|
4420
|
-
}
|
|
2551
|
+
|
|
4421
2552
|
// src/services/completion.service.ts
|
|
4422
2553
|
import {
|
|
4423
|
-
existsSync as
|
|
4424
|
-
mkdirSync
|
|
4425
|
-
writeFileSync
|
|
2554
|
+
existsSync as existsSync2,
|
|
2555
|
+
mkdirSync,
|
|
2556
|
+
writeFileSync,
|
|
4426
2557
|
unlinkSync,
|
|
4427
|
-
readFileSync
|
|
2558
|
+
readFileSync
|
|
4428
2559
|
} from "fs";
|
|
4429
|
-
import { join as
|
|
4430
|
-
import { homedir as
|
|
2560
|
+
import { join as join2 } from "path";
|
|
2561
|
+
import { homedir as homedir2 } from "os";
|
|
4431
2562
|
function collectCommands(cmd) {
|
|
4432
2563
|
return cmd.commands.map((sub) => ({
|
|
4433
2564
|
name: sub.name(),
|
|
@@ -4603,7 +2734,7 @@ ${MARKER_END}`;
|
|
|
4603
2734
|
return { shell: sh, path: rcFile };
|
|
4604
2735
|
}
|
|
4605
2736
|
case "zsh": {
|
|
4606
|
-
const zshrc =
|
|
2737
|
+
const zshrc = join2(homedir2(), ".zshrc");
|
|
4607
2738
|
const evalLine = `${MARKER_START}
|
|
4608
2739
|
eval "$(vibe completion zsh)"
|
|
4609
2740
|
${MARKER_END}`;
|
|
@@ -4611,11 +2742,11 @@ ${MARKER_END}`;
|
|
|
4611
2742
|
return { shell: sh, path: zshrc };
|
|
4612
2743
|
}
|
|
4613
2744
|
case "fish": {
|
|
4614
|
-
const dir =
|
|
4615
|
-
if (!
|
|
4616
|
-
|
|
4617
|
-
const target =
|
|
4618
|
-
|
|
2745
|
+
const dir = join2(process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config"), "fish", "completions");
|
|
2746
|
+
if (!existsSync2(dir))
|
|
2747
|
+
mkdirSync(dir, { recursive: true });
|
|
2748
|
+
const target = join2(dir, "vibe.fish");
|
|
2749
|
+
writeFileSync(target, generateFish(cmds), "utf8");
|
|
4619
2750
|
return { shell: sh, path: target };
|
|
4620
2751
|
}
|
|
4621
2752
|
}
|
|
@@ -4629,52 +2760,52 @@ function uninstallCompletion(shell) {
|
|
|
4629
2760
|
return { shell: sh, path: rcFile };
|
|
4630
2761
|
}
|
|
4631
2762
|
case "zsh": {
|
|
4632
|
-
const zshrc =
|
|
2763
|
+
const zshrc = join2(homedir2(), ".zshrc");
|
|
4633
2764
|
removeMarkedBlock(zshrc);
|
|
4634
2765
|
return { shell: sh, path: zshrc };
|
|
4635
2766
|
}
|
|
4636
2767
|
case "fish": {
|
|
4637
|
-
const target =
|
|
4638
|
-
if (
|
|
2768
|
+
const target = join2(process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config"), "fish", "completions", "vibe.fish");
|
|
2769
|
+
if (existsSync2(target))
|
|
4639
2770
|
unlinkSync(target);
|
|
4640
2771
|
return { shell: sh, path: target };
|
|
4641
2772
|
}
|
|
4642
2773
|
}
|
|
4643
2774
|
}
|
|
4644
2775
|
function bashrcPath() {
|
|
4645
|
-
const bashrc =
|
|
4646
|
-
if (
|
|
2776
|
+
const bashrc = join2(homedir2(), ".bashrc");
|
|
2777
|
+
if (existsSync2(bashrc))
|
|
4647
2778
|
return bashrc;
|
|
4648
|
-
const profile =
|
|
4649
|
-
if (
|
|
2779
|
+
const profile = join2(homedir2(), ".bash_profile");
|
|
2780
|
+
if (existsSync2(profile))
|
|
4650
2781
|
return profile;
|
|
4651
2782
|
return bashrc;
|
|
4652
2783
|
}
|
|
4653
2784
|
function appendIfMissing(file, marker, block) {
|
|
4654
2785
|
let content = "";
|
|
4655
|
-
if (
|
|
4656
|
-
content =
|
|
2786
|
+
if (existsSync2(file))
|
|
2787
|
+
content = readFileSync(file, "utf8");
|
|
4657
2788
|
if (content.includes(marker)) {
|
|
4658
2789
|
removeMarkedBlock(file);
|
|
4659
|
-
content =
|
|
2790
|
+
content = existsSync2(file) ? readFileSync(file, "utf8") : "";
|
|
4660
2791
|
}
|
|
4661
|
-
|
|
2792
|
+
writeFileSync(file, content + `
|
|
4662
2793
|
` + block + `
|
|
4663
2794
|
`, "utf8");
|
|
4664
2795
|
}
|
|
4665
2796
|
function removeMarkedBlock(file) {
|
|
4666
|
-
if (!
|
|
2797
|
+
if (!existsSync2(file))
|
|
4667
2798
|
return;
|
|
4668
|
-
const content =
|
|
2799
|
+
const content = readFileSync(file, "utf8");
|
|
4669
2800
|
const startIdx = content.indexOf(MARKER_START);
|
|
4670
2801
|
const endIdx = content.indexOf(MARKER_END);
|
|
4671
2802
|
if (startIdx === -1 || endIdx === -1)
|
|
4672
2803
|
return;
|
|
4673
|
-
|
|
2804
|
+
writeFileSync(file, content.substring(0, startIdx) + content.substring(endIdx + MARKER_END.length), "utf8");
|
|
4674
2805
|
}
|
|
4675
2806
|
|
|
4676
2807
|
// src/cli/commands/completion.cmd.ts
|
|
4677
|
-
function
|
|
2808
|
+
function register9(program2) {
|
|
4678
2809
|
const cmd = program2.command("completion").description("Generate shell completion scripts (bash, zsh, fish)");
|
|
4679
2810
|
cmd.command("bash").description("Print Bash completion script").action(() => {
|
|
4680
2811
|
const cmds = collectCommands(program2);
|
|
@@ -4712,6 +2843,7 @@ function register28(program2) {
|
|
|
4712
2843
|
}
|
|
4713
2844
|
});
|
|
4714
2845
|
}
|
|
2846
|
+
|
|
4715
2847
|
// src/cli.ts
|
|
4716
2848
|
if (typeof Bun === "undefined") {
|
|
4717
2849
|
console.error(`\x1B[31mError:\x1B[0m VibeControls Agent requires the Bun runtime.
|
|
@@ -4719,16 +2851,16 @@ if (typeof Bun === "undefined") {
|
|
|
4719
2851
|
` + " Then run: bun run vibe ...");
|
|
4720
2852
|
process.exit(1);
|
|
4721
2853
|
}
|
|
4722
|
-
var
|
|
4723
|
-
var
|
|
2854
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
2855
|
+
var __dirname2 = dirname(__filename2);
|
|
4724
2856
|
var packageVersion = "1.0.0";
|
|
4725
2857
|
try {
|
|
4726
|
-
const packageJsonPath =
|
|
4727
|
-
const packageJson = JSON.parse(
|
|
2858
|
+
const packageJsonPath = join3(__dirname2, "..", "package.json");
|
|
2859
|
+
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
4728
2860
|
packageVersion = packageJson.version;
|
|
4729
2861
|
} catch {}
|
|
4730
2862
|
var program2 = new Command;
|
|
4731
|
-
program2.name("vibe").description("VibeControls Agent CLI \u2014 Remote development environment management").version(packageVersion, "-v, --version");
|
|
2863
|
+
program2.name("vibe").description("VibeControls Agent CLI \u2014 Remote development environment management").version(packageVersion, "-v, --version").option("--provider <name>", "Override the default provider for tunnel/session operations");
|
|
4732
2864
|
register(program2);
|
|
4733
2865
|
register2(program2);
|
|
4734
2866
|
register3(program2);
|
|
@@ -4738,55 +2870,39 @@ register6(program2);
|
|
|
4738
2870
|
register7(program2);
|
|
4739
2871
|
register8(program2);
|
|
4740
2872
|
register9(program2);
|
|
4741
|
-
register10(program2);
|
|
4742
|
-
register11(program2);
|
|
4743
|
-
register12(program2);
|
|
4744
|
-
register13(program2);
|
|
4745
|
-
register14(program2);
|
|
4746
|
-
register15(program2);
|
|
4747
|
-
register16(program2);
|
|
4748
|
-
register17(program2);
|
|
4749
|
-
register18(program2);
|
|
4750
|
-
register19(program2);
|
|
4751
|
-
register20(program2);
|
|
4752
|
-
register21(program2);
|
|
4753
|
-
register22(program2);
|
|
4754
|
-
register23(program2);
|
|
4755
|
-
register24(program2);
|
|
4756
|
-
register25(program2);
|
|
4757
|
-
register26(program2);
|
|
4758
|
-
register27(program2);
|
|
4759
|
-
register28(program2);
|
|
4760
2873
|
async function main() {
|
|
4761
2874
|
const pluginManager = new PluginManager;
|
|
2875
|
+
try {
|
|
2876
|
+
await pluginManager.loadCorePlugins();
|
|
2877
|
+
} catch {}
|
|
4762
2878
|
try {
|
|
4763
2879
|
await pluginManager.loadAll();
|
|
4764
2880
|
} catch {}
|
|
2881
|
+
const serviceRegistry = new ServiceRegistry;
|
|
2882
|
+
const cliStorage = {
|
|
2883
|
+
async get() {
|
|
2884
|
+
return null;
|
|
2885
|
+
},
|
|
2886
|
+
async set() {},
|
|
2887
|
+
async delete() {
|
|
2888
|
+
return false;
|
|
2889
|
+
},
|
|
2890
|
+
async list() {
|
|
2891
|
+
return [];
|
|
2892
|
+
},
|
|
2893
|
+
async deleteAll() {
|
|
2894
|
+
return 0;
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2897
|
+
const hostServices = {
|
|
2898
|
+
storage: cliStorage,
|
|
2899
|
+
logger,
|
|
2900
|
+
serviceRegistry,
|
|
2901
|
+
getProvider: (type) => serviceRegistry.getProvider(type),
|
|
2902
|
+
getAgentBaseUrl: () => process.env.AGENT_URL || "http://localhost:3005",
|
|
2903
|
+
getAgentVersion: () => packageVersion
|
|
2904
|
+
};
|
|
4765
2905
|
try {
|
|
4766
|
-
const serviceRegistry = new ServiceRegistry;
|
|
4767
|
-
const cliStorage = {
|
|
4768
|
-
async get() {
|
|
4769
|
-
return null;
|
|
4770
|
-
},
|
|
4771
|
-
async set() {},
|
|
4772
|
-
async delete() {
|
|
4773
|
-
return false;
|
|
4774
|
-
},
|
|
4775
|
-
async list() {
|
|
4776
|
-
return [];
|
|
4777
|
-
},
|
|
4778
|
-
async deleteAll() {
|
|
4779
|
-
return 0;
|
|
4780
|
-
}
|
|
4781
|
-
};
|
|
4782
|
-
const hostServices = {
|
|
4783
|
-
storage: cliStorage,
|
|
4784
|
-
logger,
|
|
4785
|
-
serviceRegistry,
|
|
4786
|
-
getProvider: (type) => serviceRegistry.getProvider(type),
|
|
4787
|
-
getAgentBaseUrl: () => process.env.AGENT_URL || "http://localhost:3005",
|
|
4788
|
-
getAgentVersion: () => packageVersion
|
|
4789
|
-
};
|
|
4790
2906
|
await pluginManager.dispatchCliSetup(program2, hostServices);
|
|
4791
2907
|
} catch {}
|
|
4792
2908
|
program2.parse();
|
|
@@ -4796,5 +2912,5 @@ main().catch((err) => {
|
|
|
4796
2912
|
process.exit(1);
|
|
4797
2913
|
});
|
|
4798
2914
|
|
|
4799
|
-
//# debugId=
|
|
2915
|
+
//# debugId=8AF41CABD49D71F564756E2164756E21
|
|
4800
2916
|
//# sourceMappingURL=cli.js.map
|