@burdenoff/vibe-agent 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,16 +10,16 @@ Remote development environment management CLI with terminal multiplexing, SSH tu
10
10
  npm install -g @burdenoff/vibe-agent
11
11
  ```
12
12
 
13
- Requires **Node.js >= 18**.
13
+ Requires **Bun >= 1.3**.
14
14
 
15
15
  ## Quick Start
16
16
 
17
17
  ```bash
18
- # Start the agent (auto-detects first run and installs dependencies)
18
+ # Start the agent as a background daemon (default)
19
19
  vibe start
20
20
 
21
- # Or start as a background daemon
22
- vibe start -d
21
+ # Or start in foreground for debugging
22
+ vibe start --foreground
23
23
 
24
24
  # Verify it's running
25
25
  vibe health
@@ -66,8 +66,8 @@ An `.env.example` file is included in the package for reference.
66
66
  ### Core Commands
67
67
 
68
68
  ```bash
69
- vibe start # Start agent (foreground)
70
- vibe start -d # Start as daemon
69
+ vibe start # Start as daemon (default)
70
+ vibe start --foreground # Start in foreground
71
71
  vibe start -p 4000 # Start on custom port
72
72
  vibe start -n myagent # Start with instance name
73
73
  vibe start --db-path ~/my.db # Custom database path
@@ -115,18 +115,25 @@ vibe config --set key=value # Set a config value
115
115
  Extend the agent with plugins that add CLI commands, routes, or both.
116
116
 
117
117
  ```bash
118
- vibe plugin list # List installed plugins
119
- vibe plugin install @burdenoff/vibe-plugin-ssh # Install a plugin
120
- vibe plugin install @burdenoff/vibe-plugin-ai # Install AI tools plugin
121
- vibe plugin remove @burdenoff/vibe-plugin-ssh # Remove a plugin
118
+ vibe plugin list # List installed plugins
119
+ vibe plugin install @burdenoff/vibe-plugin-ssh # Install a plugin
120
+ vibe plugin install @burdenoff/vibe-plugin-ai # Install AI tools plugin
121
+ vibe plugin remove @burdenoff/vibe-plugin-ssh # Remove a plugin
122
+ vibe plugin create my-plugin # Scaffold a new plugin
123
+ vibe plugin create my-plugin --with-ui # Scaffold with React UI
124
+ vibe plugin create my-plugin --tag provider # Set plugin tag
122
125
  ```
123
126
 
124
127
  **Available Plugins:**
125
128
 
126
- | Plugin | Description |
127
- | ---------------------------- | ------------------------------------------------------ |
128
- | `@burdenoff/vibe-plugin-ssh` | SSH connections & port forwarding |
129
- | `@burdenoff/vibe-plugin-ai` | AI tool management (Claude Code, Codex, Copilot, etc.) |
129
+ | Plugin | Description |
130
+ | ------------------------------------------ | ----------------------------------------------------- |
131
+ | `@burdenoff/vibe-plugin-ssh` | SSH connections & port forwarding |
132
+ | `@burdenoff/vibe-plugin-ai` | AI tool detection & prompt management (SQLite + REST) |
133
+ | `@burdenoff/vibe-plugin-session-tmux` | tmux-based session provider |
134
+ | `@burdenoff/vibe-plugin-tunnel-cloudflare` | Cloudflare tunnel provider |
135
+ | `@burdenoff/vibe-plugin-ui-ssh` | Web UI for SSH management |
136
+ | `@burdenoff/vibe-plugin-ui-ai` | Web UI for AI tools & prompt templates |
130
137
 
131
138
  ### Tunnel Management
132
139
 
@@ -227,24 +234,24 @@ vibe tunnel list --agent-url http://localhost:4000
227
234
 
228
235
  ## Architecture
229
236
 
230
- The agent runs as a Fastify HTTP server with:
237
+ The agent runs as a Bun + Elysia HTTP server with:
231
238
 
232
- - **SQLite** database for local state (sessions, connections, tunnels, tasks, config)
239
+ - **bun:sqlite** database for local state (sessions, connections, tunnels, tasks, config)
233
240
  - **tmux** integration for terminal multiplexing
234
241
  - **cloudflared** for secure tunnel management
235
- - **Plugin system** for extensibility (SSH, AI tools, and custom plugins)
242
+ - **Plugin system** for extensibility (SSH, AI tools, UI plugins, and custom plugins)
236
243
  - **WebSocket** proxy for real-time terminal streaming
237
244
  - **API key** authentication on all endpoints
238
- - **Daemon mode** with proper process management (no SIGPIPE crashes)
245
+ - **Daemon mode** by default with proper process management
239
246
 
240
247
  ### System Dependencies
241
248
 
242
249
  | Tool | Purpose | Required |
243
250
  | ----------- | --------------------- | ----------- |
251
+ | Bun >= 1.3 | Runtime | Yes |
244
252
  | tmux | Terminal multiplexing | Yes |
245
253
  | ttyd | Web-based terminal | Recommended |
246
254
  | cloudflared | Tunnel management | For tunnels |
247
- | Node.js 18+ | Runtime | Yes |
248
255
 
249
256
  Run `vibe setup --check` to verify all dependencies.
250
257
 
@@ -264,6 +271,8 @@ When the agent is running, it exposes a REST API at `http://localhost:3005/api/`
264
271
  - `/api/git/*` - Git repository scanning
265
272
  - `/api/bookmarks/*` - Command bookmarks
266
273
  - `/api/projects/*` - Project scanning
274
+ - `/api/ai/tools` - AI tool detection
275
+ - `/api/ai/prompts/*` - Prompt template CRUD (via AI plugin)
267
276
 
268
277
  Authentication: Include `x-agent-api-key` header with your API key.
269
278
 
@@ -272,8 +281,8 @@ Authentication: Include `x-agent-api-key` header with your API key.
272
281
  ### Development Workflow
273
282
 
274
283
  ```bash
275
- # Start agent in the background
276
- vibe start -d
284
+ # Start agent (daemon mode is the default)
285
+ vibe start
277
286
 
278
287
  # Set up a dev session
279
288
  vibe session create --name frontend --cwd ~/app --command "npm run dev"
@@ -17,7 +17,7 @@ import {
17
17
  } from "./index-g8dczzvv.js";
18
18
  import {
19
19
  PluginManager
20
- } from "./plugin-system-x4tbwzyq.js";
20
+ } from "./plugin-system-sm1qhmj0.js";
21
21
 
22
22
  // node_modules/@elysiajs/cors/dist/index.mjs
23
23
  var isBun = typeof new Headers()?.toJSON === "function";
@@ -1162,4 +1162,4 @@ async function getPackageVersion() {
1162
1162
  export { createApp };
1163
1163
 
1164
1164
  //# debugId=09014DBE5BA56E4964756E2164756E21
1165
- //# sourceMappingURL=app-6d1xq46v.js.map
1165
+ //# sourceMappingURL=app-xz1nde08.js.map
package/dist/cli.js CHANGED
@@ -33,7 +33,7 @@ import {
33
33
  } from "./index-g8dczzvv.js";
34
34
  import {
35
35
  PluginManager
36
- } from "./plugin-system-x4tbwzyq.js";
36
+ } from "./plugin-system-sm1qhmj0.js";
37
37
 
38
38
  // node_modules/commander/lib/error.js
39
39
  var require_error = __commonJS((exports) => {
@@ -2145,7 +2145,7 @@ var {
2145
2145
  } = import__.default;
2146
2146
 
2147
2147
  // src/cli.ts
2148
- import { join as join3 } from "path";
2148
+ import { join as join4 } from "path";
2149
2149
 
2150
2150
  // src/cli/commands/start.cmd.ts
2151
2151
  import { existsSync } from "fs";
@@ -2228,7 +2228,7 @@ function register(program2) {
2228
2228
  kv("Host", host);
2229
2229
  kv("Database", dbPath);
2230
2230
  blank();
2231
- const { createApp } = await import("./app-6d1xq46v.js");
2231
+ const { createApp } = await import("./app-xz1nde08.js");
2232
2232
  const appInstance = await createApp({
2233
2233
  port,
2234
2234
  host,
@@ -2502,7 +2502,7 @@ function register8(program2) {
2502
2502
  blank();
2503
2503
  let currentVersion;
2504
2504
  try {
2505
- const pkg = await import("./package-1bz5z415.js", {
2505
+ const pkg = await import("./package-ah6tacg6.js", {
2506
2506
  with: { type: "json" }
2507
2507
  });
2508
2508
  currentVersion = pkg.default.version || pkg.version;
@@ -2847,6 +2847,310 @@ function register9(program2) {
2847
2847
  });
2848
2848
  }
2849
2849
 
2850
+ // src/cli/commands/autostart.cmd.ts
2851
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
2852
+ import { join as join3 } from "path";
2853
+ import { homedir as homedir3, platform } from "os";
2854
+ function getConfigDir() {
2855
+ return join3(homedir3(), ".vibecontrols");
2856
+ }
2857
+ function getLogsDir() {
2858
+ return join3(getConfigDir(), "logs");
2859
+ }
2860
+ function resolveBunPath() {
2861
+ if (process.execPath && process.execPath.includes("bun")) {
2862
+ return process.execPath;
2863
+ }
2864
+ const result = Bun.spawnSync(["which", "bun"]);
2865
+ const path = result.stdout.toString().trim();
2866
+ if (path)
2867
+ return path;
2868
+ throw new Error("Could not find bun binary. Ensure bun is installed and in PATH.");
2869
+ }
2870
+ function resolveAgentEntryPoint() {
2871
+ return join3(import.meta.dir, "..", "index.js");
2872
+ }
2873
+ function getSystemdUnitPath(name) {
2874
+ const dir = join3(homedir3(), ".config", "systemd", "user");
2875
+ mkdirSync2(dir, { recursive: true });
2876
+ return join3(dir, `vibecontrols-agent-${name}.service`);
2877
+ }
2878
+ function generateSystemdUnit(opts) {
2879
+ return `[Unit]
2880
+ Description=VibeControls Agent (${opts.name})
2881
+ After=network.target
2882
+
2883
+ [Service]
2884
+ Type=simple
2885
+ ExecStart=${opts.bunPath} run ${opts.entryPoint}
2886
+ Environment=PORT=${opts.port}
2887
+ Environment=DB_PATH=${opts.dbPath}
2888
+ Environment=NODE_ENV=production
2889
+ Environment=HOME=${homedir3()}
2890
+ Environment=PATH=${process.env.PATH}
2891
+ WorkingDirectory=${homedir3()}
2892
+ Restart=always
2893
+ RestartSec=5
2894
+ StandardOutput=append:${opts.logFile}
2895
+ StandardError=append:${opts.logFile}
2896
+
2897
+ [Install]
2898
+ WantedBy=default.target
2899
+ `;
2900
+ }
2901
+ async function installSystemd(name, port, dbPath) {
2902
+ const bunPath = resolveBunPath();
2903
+ const entryPoint = resolveAgentEntryPoint();
2904
+ const logFile = join3(getLogsDir(), `${name}.log`);
2905
+ const unitPath = getSystemdUnitPath(name);
2906
+ const serviceName = `vibecontrols-agent-${name}.service`;
2907
+ mkdirSync2(getLogsDir(), { recursive: true });
2908
+ const unit = generateSystemdUnit({
2909
+ name,
2910
+ port,
2911
+ dbPath,
2912
+ bunPath,
2913
+ entryPoint,
2914
+ logFile
2915
+ });
2916
+ writeFileSync2(unitPath, unit);
2917
+ info(`Wrote systemd unit: ${unitPath}`);
2918
+ const cmds = [
2919
+ ["systemctl", "--user", "daemon-reload"],
2920
+ ["systemctl", "--user", "enable", serviceName],
2921
+ ["systemctl", "--user", "start", serviceName]
2922
+ ];
2923
+ for (const cmd of cmds) {
2924
+ const result = Bun.spawnSync(cmd);
2925
+ if (result.exitCode !== 0) {
2926
+ const stderr = result.stderr.toString().trim();
2927
+ warn(`Command failed: ${cmd.join(" ")}${stderr ? ` \u2014 ${stderr}` : ""}`);
2928
+ }
2929
+ }
2930
+ const lingerResult = Bun.spawnSync([
2931
+ "loginctl",
2932
+ "enable-linger",
2933
+ process.env.USER || ""
2934
+ ]);
2935
+ if (lingerResult.exitCode === 0) {
2936
+ info("Enabled user linger (service survives logout)");
2937
+ }
2938
+ success(`Autostart installed for agent '${name}' on port ${port}`);
2939
+ kv("Service", serviceName);
2940
+ kv("Unit file", unitPath);
2941
+ kv("Log file", logFile);
2942
+ blank();
2943
+ info(`Check status: systemctl --user status ${serviceName}`);
2944
+ }
2945
+ async function uninstallSystemd(name) {
2946
+ const serviceName = `vibecontrols-agent-${name}.service`;
2947
+ const unitPath = getSystemdUnitPath(name);
2948
+ const cmds = [
2949
+ ["systemctl", "--user", "stop", serviceName],
2950
+ ["systemctl", "--user", "disable", serviceName]
2951
+ ];
2952
+ for (const cmd of cmds) {
2953
+ Bun.spawnSync(cmd);
2954
+ }
2955
+ if (existsSync3(unitPath)) {
2956
+ unlinkSync2(unitPath);
2957
+ info(`Removed unit file: ${unitPath}`);
2958
+ }
2959
+ Bun.spawnSync(["systemctl", "--user", "daemon-reload"]);
2960
+ success(`Autostart removed for agent '${name}'`);
2961
+ }
2962
+ async function statusSystemd(name) {
2963
+ const serviceName = `vibecontrols-agent-${name}.service`;
2964
+ const unitPath = getSystemdUnitPath(name);
2965
+ if (!existsSync3(unitPath)) {
2966
+ info(`Autostart is NOT configured for agent '${name}'`);
2967
+ kv("Expected unit", unitPath);
2968
+ return;
2969
+ }
2970
+ header(`Autostart Status \u2014 ${name}`);
2971
+ kv("Unit file", unitPath);
2972
+ kv("Service", serviceName);
2973
+ blank();
2974
+ const result = Bun.spawnSync(["systemctl", "--user", "status", serviceName]);
2975
+ const output = result.stdout.toString().trim();
2976
+ if (output) {
2977
+ console.log(output);
2978
+ } else {
2979
+ info("Service status unavailable");
2980
+ }
2981
+ }
2982
+ function getLaunchdPlistPath(name) {
2983
+ const dir = join3(homedir3(), "Library", "LaunchAgents");
2984
+ mkdirSync2(dir, { recursive: true });
2985
+ return join3(dir, `com.vibecontrols.agent.${name}.plist`);
2986
+ }
2987
+ function generateLaunchdPlist(opts) {
2988
+ return `<?xml version="1.0" encoding="UTF-8"?>
2989
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2990
+ <plist version="1.0">
2991
+ <dict>
2992
+ <key>Label</key>
2993
+ <string>com.vibecontrols.agent.${opts.name}</string>
2994
+ <key>ProgramArguments</key>
2995
+ <array>
2996
+ <string>${opts.bunPath}</string>
2997
+ <string>run</string>
2998
+ <string>${opts.entryPoint}</string>
2999
+ </array>
3000
+ <key>EnvironmentVariables</key>
3001
+ <dict>
3002
+ <key>PORT</key>
3003
+ <string>${opts.port}</string>
3004
+ <key>DB_PATH</key>
3005
+ <string>${opts.dbPath}</string>
3006
+ <key>NODE_ENV</key>
3007
+ <string>production</string>
3008
+ <key>HOME</key>
3009
+ <string>${homedir3()}</string>
3010
+ <key>PATH</key>
3011
+ <string>${process.env.PATH}</string>
3012
+ </dict>
3013
+ <key>WorkingDirectory</key>
3014
+ <string>${homedir3()}</string>
3015
+ <key>RunAtLoad</key>
3016
+ <true/>
3017
+ <key>KeepAlive</key>
3018
+ <dict>
3019
+ <key>SuccessfulExit</key>
3020
+ <false/>
3021
+ </dict>
3022
+ <key>StandardOutPath</key>
3023
+ <string>${opts.logFile}</string>
3024
+ <key>StandardErrorPath</key>
3025
+ <string>${opts.logFile}</string>
3026
+ <key>ProcessType</key>
3027
+ <string>Background</string>
3028
+ </dict>
3029
+ </plist>
3030
+ `;
3031
+ }
3032
+ async function installLaunchd(name, port, dbPath) {
3033
+ const bunPath = resolveBunPath();
3034
+ const entryPoint = resolveAgentEntryPoint();
3035
+ const logFile = join3(getLogsDir(), `${name}.log`);
3036
+ const plistPath = getLaunchdPlistPath(name);
3037
+ mkdirSync2(getLogsDir(), { recursive: true });
3038
+ const plist = generateLaunchdPlist({
3039
+ name,
3040
+ port,
3041
+ dbPath,
3042
+ bunPath,
3043
+ entryPoint,
3044
+ logFile
3045
+ });
3046
+ writeFileSync2(plistPath, plist);
3047
+ info(`Wrote launchd plist: ${plistPath}`);
3048
+ const result = Bun.spawnSync(["launchctl", "load", plistPath]);
3049
+ if (result.exitCode !== 0) {
3050
+ const stderr = result.stderr.toString().trim();
3051
+ warn(`launchctl load failed: ${stderr}`);
3052
+ info("Trying bootstrap method...");
3053
+ const uid = Bun.spawnSync(["id", "-u"]).stdout.toString().trim();
3054
+ Bun.spawnSync(["launchctl", "bootstrap", `gui/${uid}`, plistPath]);
3055
+ }
3056
+ success(`Autostart installed for agent '${name}' on port ${port}`);
3057
+ kv("Plist", plistPath);
3058
+ kv("Log file", logFile);
3059
+ }
3060
+ async function uninstallLaunchd(name) {
3061
+ const plistPath = getLaunchdPlistPath(name);
3062
+ const label = `com.vibecontrols.agent.${name}`;
3063
+ Bun.spawnSync(["launchctl", "unload", plistPath]);
3064
+ const uid = Bun.spawnSync(["id", "-u"]).stdout.toString().trim();
3065
+ Bun.spawnSync(["launchctl", "bootout", `gui/${uid}/${label}`]);
3066
+ if (existsSync3(plistPath)) {
3067
+ unlinkSync2(plistPath);
3068
+ info(`Removed plist: ${plistPath}`);
3069
+ }
3070
+ success(`Autostart removed for agent '${name}'`);
3071
+ }
3072
+ async function statusLaunchd(name) {
3073
+ const plistPath = getLaunchdPlistPath(name);
3074
+ const label = `com.vibecontrols.agent.${name}`;
3075
+ if (!existsSync3(plistPath)) {
3076
+ info(`Autostart is NOT configured for agent '${name}'`);
3077
+ kv("Expected plist", plistPath);
3078
+ return;
3079
+ }
3080
+ header(`Autostart Status \u2014 ${name}`);
3081
+ kv("Plist", plistPath);
3082
+ kv("Label", label);
3083
+ blank();
3084
+ const result = Bun.spawnSync(["launchctl", "list"]);
3085
+ const output = result.stdout.toString();
3086
+ const lines = output.split(`
3087
+ `).filter((l) => l.includes("vibecontrols"));
3088
+ if (lines.length > 0) {
3089
+ console.log(lines.join(`
3090
+ `));
3091
+ } else {
3092
+ info("Service not currently loaded");
3093
+ }
3094
+ }
3095
+ function register10(program2) {
3096
+ const autostart = program2.command("autostart").description("Configure agent to auto-start on system boot");
3097
+ autostart.command("install").description("Generate and enable system service for auto-start on reboot").option("-n, --name <name>", "Agent instance name", "default").option("-p, --port <port>", "Port to listen on", "3005").option("--db-path <path>", "SQLite database path", "./vibecontrols-agent.db").action(async (opts) => {
3098
+ const os = platform();
3099
+ const port = parseInt(opts.port, 10);
3100
+ header("Installing Autostart");
3101
+ kv("Platform", os);
3102
+ kv("Agent", opts.name);
3103
+ kv("Port", String(port));
3104
+ blank();
3105
+ try {
3106
+ if (os === "linux") {
3107
+ await installSystemd(opts.name, port, opts.dbPath);
3108
+ } else if (os === "darwin") {
3109
+ await installLaunchd(opts.name, port, opts.dbPath);
3110
+ } else {
3111
+ fail(`Autostart is not supported on ${os}. Supported: linux, darwin (macOS).`);
3112
+ process.exit(1);
3113
+ }
3114
+ } catch (err) {
3115
+ fail(`Failed to install autostart: ${err}`);
3116
+ process.exit(1);
3117
+ }
3118
+ });
3119
+ autostart.command("uninstall").description("Stop and remove the system service").option("-n, --name <name>", "Agent instance name", "default").action(async (opts) => {
3120
+ const os = platform();
3121
+ header("Removing Autostart");
3122
+ try {
3123
+ if (os === "linux") {
3124
+ await uninstallSystemd(opts.name);
3125
+ } else if (os === "darwin") {
3126
+ await uninstallLaunchd(opts.name);
3127
+ } else {
3128
+ fail(`Autostart is not supported on ${os}.`);
3129
+ process.exit(1);
3130
+ }
3131
+ } catch (err) {
3132
+ fail(`Failed to uninstall autostart: ${err}`);
3133
+ process.exit(1);
3134
+ }
3135
+ });
3136
+ autostart.command("status").description("Check if autostart is configured and running").option("-n, --name <name>", "Agent instance name", "default").action(async (opts) => {
3137
+ const os = platform();
3138
+ try {
3139
+ if (os === "linux") {
3140
+ await statusSystemd(opts.name);
3141
+ } else if (os === "darwin") {
3142
+ await statusLaunchd(opts.name);
3143
+ } else {
3144
+ fail(`Autostart is not supported on ${os}.`);
3145
+ process.exit(1);
3146
+ }
3147
+ } catch (err) {
3148
+ fail(`Failed to check autostart status: ${err}`);
3149
+ process.exit(1);
3150
+ }
3151
+ });
3152
+ }
3153
+
2850
3154
  // src/cli.ts
2851
3155
  if (typeof Bun === "undefined") {
2852
3156
  console.error(`\x1B[31mError:\x1B[0m VibeControls Agent requires the Bun runtime.
@@ -2856,7 +3160,7 @@ if (typeof Bun === "undefined") {
2856
3160
  }
2857
3161
  var packageVersion = "1.0.0";
2858
3162
  try {
2859
- const packageJsonPath = join3(import.meta.dir, "..", "package.json");
3163
+ const packageJsonPath = join4(import.meta.dir, "..", "package.json");
2860
3164
  const packageJson = await Bun.file(packageJsonPath).json();
2861
3165
  packageVersion = packageJson.version;
2862
3166
  } catch {}
@@ -2871,6 +3175,7 @@ register6(program2);
2871
3175
  register7(program2);
2872
3176
  register8(program2);
2873
3177
  register9(program2);
3178
+ register10(program2);
2874
3179
  async function main() {
2875
3180
  const pluginManager = new PluginManager;
2876
3181
  try {
@@ -2913,5 +3218,5 @@ main().catch((err) => {
2913
3218
  process.exit(1);
2914
3219
  });
2915
3220
 
2916
- //# debugId=B3B10A5CB7971CB864756E2164756E21
3221
+ //# debugId=E4B4C6E0AF4D6D3B64756E2164756E21
2917
3222
  //# sourceMappingURL=cli.js.map