vibora 4.7.2 → 4.8.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
@@ -29,11 +29,29 @@ The Vibe Engineer's Cockpit. Orchestrate Claude Code across parallel workstreams
29
29
 
30
30
  ## Quick Start
31
31
 
32
- Requires [Bun](https://bun.sh/) and [Claude Code](https://claude.ai/code).
32
+ ```bash
33
+ npx vibora@latest up
34
+ ```
35
+
36
+ That's it! Vibora will:
37
+ - Check for required dependencies (bun, dtach, Claude Code, uv)
38
+ - Offer to install any that are missing
39
+ - Start the server on http://localhost:7777
40
+ - Show getting started tips
41
+
42
+ Open http://localhost:7777 in your browser.
33
43
 
34
- ### Desktop App (Recommended)
44
+ ### Check Your Setup
35
45
 
36
- Download the latest release:
46
+ ```bash
47
+ vibora doctor
48
+ ```
49
+
50
+ Shows the status of all dependencies with versions.
51
+
52
+ ### Desktop App
53
+
54
+ Download the desktop app for a bundled experience:
37
55
 
38
56
  | Platform | Download |
39
57
  |----------|----------|
@@ -43,47 +61,32 @@ Download the latest release:
43
61
  The desktop app bundles everything—just install and run. It will start the server, install the Claude Code plugin, and check for updates automatically.
44
62
 
45
63
  <details>
46
- <summary>👉 <strong>macOS Installation</strong></summary>
47
-
48
- 1. Open the DMG and drag Vibora to Applications:
64
+ <summary>macOS Installation Notes</summary>
49
65
 
50
- ![DMG Installer](./screenshots/macos-dmg-installer.png)
51
-
52
- 2. On first launch, macOS will block the app:
53
-
54
- ![Gatekeeper Blocked](./screenshots/macos-gatekeeper-blocked.png)
55
-
56
- 3. Open **System Settings → Privacy & Security**, scroll down, and click **Open Anyway**:
57
-
58
- ![Privacy & Security](./screenshots/macos-privacy-security-open-anyway.png)
59
-
60
- 4. Confirm by clicking **Open Anyway** in the dialog:
61
-
62
- ![Open Anyway](./screenshots/macos-gatekeeper-open-anyway.png)
66
+ 1. Open the DMG and drag Vibora to Applications
67
+ 2. On first launch, macOS will block the app
68
+ 3. Open **System Settings → Privacy & Security**, scroll down, and click **Open Anyway**
69
+ 4. Confirm by clicking **Open Anyway** in the dialog
63
70
 
64
71
  </details>
65
72
 
66
- ### Web Application
73
+ ### Install Script
67
74
 
68
- Run Vibora as a web server for browser access or remote deployment.
75
+ For automated installation (useful for remote servers):
69
76
 
70
77
  ```bash
71
- # Install and start with curl
72
78
  curl -fsSL https://raw.githubusercontent.com/knowsuchagency/vibora/main/install.sh | bash
73
-
74
- # Or install via npm
75
- npx vibora@latest up
76
79
  ```
77
80
 
78
- If using npm, install the Claude Code plugin separately:
81
+ ### Claude Code Plugin
82
+
83
+ Install the plugin for automatic status sync and task management:
79
84
 
80
85
  ```bash
81
86
  claude plugin marketplace add knowsuchagency/vibora
82
87
  claude plugin install vibora@vibora --scope user
83
88
  ```
84
89
 
85
- Open http://localhost:7777 in your browser.
86
-
87
90
  ## Features
88
91
 
89
92
  ### Kanban Board
@@ -244,8 +247,10 @@ The CLI lets AI agents working inside task worktrees query and update task statu
244
247
 
245
248
  ```bash
246
249
  vibora up # Start server daemon
250
+ vibora up -y # Start with auto-install (no prompts)
247
251
  vibora down # Stop server
248
252
  vibora status # Check server status
253
+ vibora doctor # Check all dependencies
249
254
  vibora health # Check server health
250
255
  vibora mcp # Start MCP server (stdio)
251
256
  ```
package/bin/vibora.js CHANGED
@@ -29881,6 +29881,9 @@ var prettyOutput = false;
29881
29881
  function setPrettyOutput(value) {
29882
29882
  prettyOutput = value;
29883
29883
  }
29884
+ function isPrettyOutput() {
29885
+ return prettyOutput;
29886
+ }
29884
29887
  function output(data) {
29885
29888
  const response = {
29886
29889
  success: true,
@@ -30157,45 +30160,183 @@ async function confirm(message) {
30157
30160
  // cli/src/commands/up.ts
30158
30161
  init_server();
30159
30162
 
30160
- // cli/src/utils/install.ts
30163
+ // cli/src/utils/dependencies.ts
30161
30164
  import { execSync, spawnSync } from "child_process";
30162
- function isBrewInstalled() {
30163
- try {
30164
- execSync("which brew", { stdio: "ignore" });
30165
- return true;
30166
- } catch {
30167
- return false;
30165
+ var DEPENDENCIES = [
30166
+ {
30167
+ name: "bun",
30168
+ command: "bun",
30169
+ description: "Runtime for Vibora server",
30170
+ required: true,
30171
+ install: {
30172
+ brew: "brew install oven-sh/bun/bun",
30173
+ curl: "curl -fsSL https://bun.sh/install | bash"
30174
+ }
30175
+ },
30176
+ {
30177
+ name: "dtach",
30178
+ command: "dtach",
30179
+ description: "Terminal session persistence",
30180
+ required: true,
30181
+ install: {
30182
+ brew: "brew install dtach",
30183
+ apt: "sudo apt install -y dtach",
30184
+ dnf: "sudo dnf install -y dtach",
30185
+ pacman: "sudo pacman -S --noconfirm dtach"
30186
+ }
30187
+ },
30188
+ {
30189
+ name: "claude",
30190
+ command: "claude",
30191
+ description: "Claude Code CLI for AI agents",
30192
+ required: true,
30193
+ install: {
30194
+ npm: "npm install -g @anthropic-ai/claude-code"
30195
+ }
30196
+ },
30197
+ {
30198
+ name: "uv",
30199
+ command: "uv",
30200
+ description: "Fast Python package manager",
30201
+ required: true,
30202
+ install: {
30203
+ brew: "brew install uv",
30204
+ curl: "curl -LsSf https://astral.sh/uv/install.sh | sh"
30205
+ }
30206
+ },
30207
+ {
30208
+ name: "gh",
30209
+ command: "gh",
30210
+ description: "GitHub CLI for PR creation",
30211
+ required: false,
30212
+ install: {
30213
+ brew: "brew install gh",
30214
+ apt: "sudo apt install -y gh",
30215
+ dnf: "sudo dnf install -y gh",
30216
+ pacman: "sudo pacman -S --noconfirm github-cli"
30217
+ }
30218
+ }
30219
+ ];
30220
+ function detectPackageManager() {
30221
+ const managers = ["brew", "apt", "dnf", "pacman"];
30222
+ for (const pm of managers) {
30223
+ try {
30224
+ execSync(`which ${pm}`, { stdio: "ignore" });
30225
+ return pm;
30226
+ } catch {}
30168
30227
  }
30228
+ return null;
30169
30229
  }
30170
- function isBunInstalled() {
30230
+ function isCommandInstalled(command) {
30171
30231
  try {
30172
- execSync("which bun", { stdio: "ignore" });
30232
+ execSync(`which ${command}`, { stdio: "ignore" });
30173
30233
  return true;
30174
30234
  } catch {
30175
30235
  return false;
30176
30236
  }
30177
30237
  }
30178
- function isDtachInstalled() {
30238
+ function getCommandVersion(command) {
30179
30239
  try {
30180
- execSync("which dtach", { stdio: "ignore" });
30181
- return true;
30240
+ const output2 = execSync(`${command} --version`, { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] });
30241
+ return output2.trim().split(`
30242
+ `)[0];
30182
30243
  } catch {
30183
- return false;
30244
+ return null;
30184
30245
  }
30185
30246
  }
30186
- function installDtach() {
30187
- const hasBrew = isBrewInstalled();
30188
- const cmd = hasBrew ? "brew install dtach" : "sudo apt install -y dtach";
30247
+ function checkDependency(dep) {
30248
+ const installed = isCommandInstalled(dep.command);
30249
+ return {
30250
+ name: dep.name,
30251
+ command: dep.command,
30252
+ description: dep.description,
30253
+ required: dep.required,
30254
+ installed,
30255
+ version: installed ? getCommandVersion(dep.command) : null
30256
+ };
30257
+ }
30258
+ function checkAllDependencies() {
30259
+ return DEPENDENCIES.map(checkDependency);
30260
+ }
30261
+ function getInstallCommand(dep) {
30262
+ const pm = detectPackageManager();
30263
+ if (pm && dep.install[pm]) {
30264
+ return dep.install[pm];
30265
+ }
30266
+ if (dep.install.npm) {
30267
+ return dep.install.npm;
30268
+ }
30269
+ if (dep.install.curl) {
30270
+ return dep.install.curl;
30271
+ }
30272
+ const available = Object.values(dep.install).filter(Boolean);
30273
+ return available[0] || `Please install ${dep.name} manually`;
30274
+ }
30275
+ function getInstallMethod(dep) {
30276
+ const pm = detectPackageManager();
30277
+ if (pm && dep.install[pm]) {
30278
+ const methodNames = {
30279
+ brew: "Homebrew",
30280
+ apt: "apt",
30281
+ dnf: "dnf",
30282
+ pacman: "pacman"
30283
+ };
30284
+ return methodNames[pm] || pm;
30285
+ }
30286
+ if (dep.install.npm) {
30287
+ return "npm";
30288
+ }
30289
+ if (dep.install.curl) {
30290
+ return "curl script";
30291
+ }
30292
+ return "manual installation";
30293
+ }
30294
+ function installDependency(dep) {
30295
+ const cmd = getInstallCommand(dep);
30189
30296
  console.error(`Running: ${cmd}`);
30190
30297
  const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
30191
30298
  return result.status === 0;
30192
30299
  }
30300
+ function getDependency(name) {
30301
+ return DEPENDENCIES.find((d) => d.name === name);
30302
+ }
30303
+
30304
+ // cli/src/utils/install.ts
30305
+ function isBunInstalled() {
30306
+ return isCommandInstalled("bun");
30307
+ }
30308
+ function isDtachInstalled() {
30309
+ return isCommandInstalled("dtach");
30310
+ }
30311
+ function isClaudeInstalled() {
30312
+ return isCommandInstalled("claude");
30313
+ }
30314
+ function isUvInstalled() {
30315
+ return isCommandInstalled("uv");
30316
+ }
30317
+ function installDtach() {
30318
+ const dep = getDependency("dtach");
30319
+ if (!dep)
30320
+ return false;
30321
+ return installDependency(dep);
30322
+ }
30193
30323
  function installBun() {
30194
- const hasBrew = isBrewInstalled();
30195
- const cmd = hasBrew ? "brew install oven-sh/bun/bun" : "curl -fsSL https://bun.sh/install | bash";
30196
- console.error(`Running: ${cmd}`);
30197
- const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
30198
- return result.status === 0;
30324
+ const dep = getDependency("bun");
30325
+ if (!dep)
30326
+ return false;
30327
+ return installDependency(dep);
30328
+ }
30329
+ function installClaude() {
30330
+ const dep = getDependency("claude");
30331
+ if (!dep)
30332
+ return false;
30333
+ return installDependency(dep);
30334
+ }
30335
+ function installUv() {
30336
+ const dep = getDependency("uv");
30337
+ if (!dep)
30338
+ return false;
30339
+ return installDependency(dep);
30199
30340
  }
30200
30341
 
30201
30342
  // cli/src/commands/up.ts
@@ -30211,11 +30352,13 @@ function getPackageRoot() {
30211
30352
  return dirname2(dirname2(dirname2(currentFile)));
30212
30353
  }
30213
30354
  async function handleUpCommand(flags) {
30355
+ const autoYes = flags.yes === "true" || flags.y === "true";
30214
30356
  if (!isBunInstalled()) {
30215
- const hasBrew = isBrewInstalled();
30216
- const method = hasBrew ? "Homebrew" : "curl script";
30357
+ const bunDep = getDependency("bun");
30358
+ const method = getInstallMethod(bunDep);
30217
30359
  console.error("Bun is required to run Vibora but is not installed.");
30218
- const shouldInstall = await confirm(`Would you like to install bun via ${method}?`);
30360
+ console.error(" Bun is the JavaScript runtime that powers Vibora.");
30361
+ const shouldInstall = autoYes || await confirm(`Would you like to install bun via ${method}?`);
30219
30362
  if (shouldInstall) {
30220
30363
  const success = installBun();
30221
30364
  if (!success) {
@@ -30223,14 +30366,15 @@ async function handleUpCommand(flags) {
30223
30366
  }
30224
30367
  console.error("Bun installed successfully!");
30225
30368
  } else {
30226
- throw new CliError("MISSING_DEPENDENCY", "Bun is required. Install manually: brew install oven-sh/bun/bun (macOS) or curl -fsSL https://bun.sh/install | bash", ExitCodes.ERROR);
30369
+ throw new CliError("MISSING_DEPENDENCY", `Bun is required. Install manually: ${getInstallCommand(bunDep)}`, ExitCodes.ERROR);
30227
30370
  }
30228
30371
  }
30229
30372
  if (!isDtachInstalled()) {
30230
- const hasBrew = isBrewInstalled();
30231
- const method = hasBrew ? "Homebrew" : "apt";
30373
+ const dtachDep = getDependency("dtach");
30374
+ const method = getInstallMethod(dtachDep);
30232
30375
  console.error("dtach is required for terminal persistence but is not installed.");
30233
- const shouldInstall = await confirm(`Would you like to install dtach via ${method}?`);
30376
+ console.error(" dtach enables persistent terminal sessions that survive disconnects.");
30377
+ const shouldInstall = autoYes || await confirm(`Would you like to install dtach via ${method}?`);
30234
30378
  if (shouldInstall) {
30235
30379
  const success = installDtach();
30236
30380
  if (!success) {
@@ -30238,13 +30382,45 @@ async function handleUpCommand(flags) {
30238
30382
  }
30239
30383
  console.error("dtach installed successfully!");
30240
30384
  } else {
30241
- throw new CliError("MISSING_DEPENDENCY", "dtach is required. Install manually: brew install dtach (macOS) or apt install dtach (Linux)", ExitCodes.ERROR);
30385
+ throw new CliError("MISSING_DEPENDENCY", `dtach is required. Install manually: ${getInstallCommand(dtachDep)}`, ExitCodes.ERROR);
30386
+ }
30387
+ }
30388
+ if (!isClaudeInstalled()) {
30389
+ const claudeDep = getDependency("claude");
30390
+ const method = getInstallMethod(claudeDep);
30391
+ console.error("Claude Code CLI is required but is not installed.");
30392
+ console.error(" Claude Code is the AI coding agent that Vibora orchestrates.");
30393
+ const shouldInstall = autoYes || await confirm(`Would you like to install Claude Code via ${method}?`);
30394
+ if (shouldInstall) {
30395
+ const success = installClaude();
30396
+ if (!success) {
30397
+ throw new CliError("INSTALL_FAILED", "Failed to install Claude Code", ExitCodes.ERROR);
30398
+ }
30399
+ console.error("Claude Code installed successfully!");
30400
+ } else {
30401
+ throw new CliError("MISSING_DEPENDENCY", `Claude Code is required. Install manually: ${getInstallCommand(claudeDep)}`, ExitCodes.ERROR);
30402
+ }
30403
+ }
30404
+ if (!isUvInstalled()) {
30405
+ const uvDep = getDependency("uv");
30406
+ const method = getInstallMethod(uvDep);
30407
+ console.error("uv is required but is not installed.");
30408
+ console.error(" uv is a fast Python package manager used by Claude Code.");
30409
+ const shouldInstall = autoYes || await confirm(`Would you like to install uv via ${method}?`);
30410
+ if (shouldInstall) {
30411
+ const success = installUv();
30412
+ if (!success) {
30413
+ throw new CliError("INSTALL_FAILED", "Failed to install uv", ExitCodes.ERROR);
30414
+ }
30415
+ console.error("uv installed successfully!");
30416
+ } else {
30417
+ throw new CliError("MISSING_DEPENDENCY", `uv is required. Install manually: ${getInstallCommand(uvDep)}`, ExitCodes.ERROR);
30242
30418
  }
30243
30419
  }
30244
30420
  const existingPid = readPid();
30245
30421
  if (existingPid && isProcessRunning(existingPid)) {
30246
30422
  console.error(`Vibora server is already running (PID: ${existingPid})`);
30247
- const shouldReplace = await confirm("Would you like to stop it and start a new instance?");
30423
+ const shouldReplace = autoYes || await confirm("Would you like to stop it and start a new instance?");
30248
30424
  if (shouldReplace) {
30249
30425
  console.error("Stopping existing instance...");
30250
30426
  process.kill(existingPid, "SIGTERM");
@@ -30309,6 +30485,23 @@ async function handleUpCommand(flags) {
30309
30485
  port,
30310
30486
  url: `http://localhost:${port}`
30311
30487
  });
30488
+ showGettingStartedTips(port);
30489
+ }
30490
+ function showGettingStartedTips(port) {
30491
+ console.error(`
30492
+ Vibora is running at http://localhost:${port}
30493
+
30494
+ Getting Started:
30495
+ 1. Open http://localhost:${port} in your browser
30496
+ 2. Add a repository to get started
30497
+ 3. Create a task to spin up an isolated worktree
30498
+ 4. Run Claude Code in the task terminal
30499
+
30500
+ Commands:
30501
+ vibora status Check server status
30502
+ vibora doctor Check all dependencies
30503
+ vibora down Stop the server
30504
+ `);
30312
30505
  }
30313
30506
 
30314
30507
  // cli/src/commands/down.ts
@@ -30587,9 +30780,71 @@ async function handleDevCommand(action, flags) {
30587
30780
  }
30588
30781
  }
30589
30782
 
30783
+ // cli/src/commands/doctor.ts
30784
+ async function handleDoctorCommand(flags) {
30785
+ const deps = checkAllDependencies();
30786
+ const showJson = !isPrettyOutput() && flags.pretty !== "true";
30787
+ if (showJson) {
30788
+ output(deps);
30789
+ return;
30790
+ }
30791
+ console.log(`
30792
+ Vibora Doctor`);
30793
+ console.log(`=============
30794
+ `);
30795
+ console.log("Required:");
30796
+ for (const dep of deps.filter((d) => d.required)) {
30797
+ const icon = dep.installed ? "\u2713" : "\u2717";
30798
+ const version2 = dep.version || "-";
30799
+ console.log(` ${icon} ${dep.name.padEnd(10)} ${version2.padEnd(20)} ${dep.description}`);
30800
+ }
30801
+ console.log(`
30802
+ Optional:`);
30803
+ for (const dep of deps.filter((d) => !d.required)) {
30804
+ const icon = dep.installed ? "\u2713" : "\u25CB";
30805
+ const version2 = dep.version || "-";
30806
+ console.log(` ${icon} ${dep.name.padEnd(10)} ${version2.padEnd(20)} ${dep.description}`);
30807
+ }
30808
+ const requiredDeps = deps.filter((d) => d.required);
30809
+ const requiredInstalled = requiredDeps.filter((d) => d.installed).length;
30810
+ const requiredTotal = requiredDeps.length;
30811
+ console.log(`
30812
+ Status: ${requiredInstalled} of ${requiredTotal} required dependencies installed`);
30813
+ const requiredMissing = requiredDeps.filter((d) => !d.installed);
30814
+ if (requiredMissing.length > 0) {
30815
+ console.log(`
30816
+ Missing required dependencies:`);
30817
+ for (const dep of requiredMissing) {
30818
+ const fullDep = getDependency(dep.name);
30819
+ if (fullDep) {
30820
+ console.log(` ${dep.name}: ${getInstallCommand(fullDep)}`);
30821
+ }
30822
+ }
30823
+ console.log("\nRun `vibora up` to install missing dependencies.");
30824
+ } else {
30825
+ console.log(`
30826
+ \u2713 All required dependencies installed!`);
30827
+ }
30828
+ const optionalMissing = deps.filter((d) => !d.required && !d.installed);
30829
+ if (optionalMissing.length > 0) {
30830
+ console.log(`
30831
+ Optional dependencies not installed:`);
30832
+ for (const dep of optionalMissing) {
30833
+ const fullDep = getDependency(dep.name);
30834
+ if (fullDep) {
30835
+ console.log(` ${dep.name}: ${getInstallCommand(fullDep)}`);
30836
+ }
30837
+ }
30838
+ }
30839
+ console.log("");
30840
+ }
30841
+
30590
30842
  // cli/src/index.ts
30591
30843
  init_errors();
30592
30844
  var VERSION = "0.1.0";
30845
+ var FLAG_ALIASES = {
30846
+ y: "yes"
30847
+ };
30593
30848
  function parseArgs(args) {
30594
30849
  const positional = [];
30595
30850
  const flags = {};
@@ -30604,13 +30859,17 @@ function parseArgs(args) {
30604
30859
  } else {
30605
30860
  const key = arg.slice(2);
30606
30861
  const nextArg = args[i + 1];
30607
- if (nextArg && !nextArg.startsWith("--")) {
30862
+ if (nextArg && !nextArg.startsWith("-")) {
30608
30863
  flags[key] = nextArg;
30609
30864
  i++;
30610
30865
  } else {
30611
30866
  flags[key] = "true";
30612
30867
  }
30613
30868
  }
30869
+ } else if (arg.startsWith("-") && arg.length === 2) {
30870
+ const shortKey = arg.slice(1);
30871
+ const longKey = FLAG_ALIASES[shortKey] || shortKey;
30872
+ flags[longKey] = "true";
30614
30873
  } else {
30615
30874
  positional.push(arg);
30616
30875
  }
@@ -30649,9 +30908,12 @@ Commands:
30649
30908
  tasks move <id> Move task to different status
30650
30909
  tasks delete <id> Delete a task
30651
30910
 
30652
- up [--host] [--debug] Start Vibora server (daemon)
30911
+ up [-y] [--host] [--debug]
30912
+ Start Vibora server (daemon)
30913
+ Checks/installs dependencies: bun, dtach, claude, uv
30653
30914
  down Stop Vibora server
30654
30915
  status Check if server is running
30916
+ doctor Check all dependencies and show versions
30655
30917
 
30656
30918
  git status Get git status for worktree
30657
30919
  git diff Get git diff for worktree
@@ -30683,6 +30945,7 @@ Global Options:
30683
30945
  --port=<port> Server port (default: 7777)
30684
30946
  --url=<url> Override full server URL
30685
30947
  --pretty Pretty-print JSON output
30948
+ -y, --yes Auto-confirm prompts (for CI/automation)
30686
30949
  --version Show version
30687
30950
  --help Show this help
30688
30951
 
@@ -30737,6 +31000,10 @@ Examples:
30737
31000
  await handleHealthCommand(flags);
30738
31001
  break;
30739
31002
  }
31003
+ case "doctor": {
31004
+ await handleDoctorCommand(flags);
31005
+ break;
31006
+ }
30740
31007
  case "notifications": {
30741
31008
  const [action, ...notificationsRest] = rest;
30742
31009
  await handleNotificationsCommand(action, notificationsRest, flags);