minivibe 0.2.2 → 0.2.6

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
@@ -20,7 +20,7 @@ CLI wrapper for Claude Code with mobile remote control via MiniVibe iOS app.
20
20
  npm install -g minivibe
21
21
 
22
22
  # Login (one-time)
23
- vibe --login
23
+ vibe login
24
24
 
25
25
  # Start coding with remote control!
26
26
  vibe
@@ -55,7 +55,7 @@ npm link
55
55
  ### Browser Login (Desktop)
56
56
 
57
57
  ```bash
58
- vibe --login
58
+ vibe login
59
59
  ```
60
60
 
61
61
  Opens browser for Google sign-in. Token is saved to `~/.vibe/auth.json`.
@@ -63,7 +63,7 @@ Opens browser for Google sign-in. Token is saved to `~/.vibe/auth.json`.
63
63
  ### Headless Login (Servers/EC2)
64
64
 
65
65
  ```bash
66
- vibe --login --headless
66
+ vibe login --headless
67
67
  ```
68
68
 
69
69
  Displays a device code. Visit the URL on any device to authenticate.
@@ -94,7 +94,7 @@ Use a local agent to manage multiple sessions:
94
94
 
95
95
  ```bash
96
96
  # Terminal 1: Start the agent (runs continuously)
97
- vibe-agent --login # First time only
97
+ vibe-agent login # First time only
98
98
  vibe-agent # Start daemon
99
99
 
100
100
  # Terminal 2+: Create sessions via agent
package/agent/agent.js CHANGED
@@ -25,9 +25,13 @@ const os = require('os');
25
25
  // Configuration
26
26
  // ====================
27
27
 
28
+ // Shared auth directory (same as vibe CLI)
29
+ const SHARED_AUTH_DIR = path.join(os.homedir(), '.vibe');
30
+ const AUTH_FILE = path.join(SHARED_AUTH_DIR, 'auth.json');
31
+
32
+ // Agent-specific config directory
28
33
  const CONFIG_DIR = path.join(os.homedir(), '.vibe-agent');
29
34
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
30
- const AUTH_FILE = path.join(CONFIG_DIR, 'auth.json');
31
35
  const SESSION_HISTORY_FILE = path.join(CONFIG_DIR, 'session-history.json');
32
36
 
33
37
  const RECONNECT_DELAY_MS = 5000;
@@ -36,6 +40,7 @@ const LOCAL_SERVER_PORT = 9999;
36
40
  const PORT_FILE = path.join(os.homedir(), '.vibe-agent', 'port');
37
41
  const MAX_SESSION_HISTORY_AGE_DAYS = 30;
38
42
  const DEFAULT_BRIDGE_URL = 'wss://ws.minivibeapp.com';
43
+ const PAIRING_URL = 'https://minivibeapp.com/pair';
39
44
 
40
45
  // Show welcome message for first-time users (no auth)
41
46
  function showWelcomeMessage() {
@@ -46,9 +51,10 @@ vibe-agent lets you manage Claude Code sessions from your iPhone.
46
51
 
47
52
  To get started:
48
53
  1. Download MiniVibe from the App Store
49
- 2. Run: vibe-agent --login
54
+ 2. Run: vibe-agent login
55
+ (or 'vibe login' - auth is shared between vibe and vibe-agent)
50
56
 
51
- For help: vibe-agent --help
57
+ For help: vibe-agent help
52
58
  `);
53
59
  }
54
60
 
@@ -111,8 +117,8 @@ function loadAuth() {
111
117
 
112
118
  function saveAuth(idToken, refreshToken = null) {
113
119
  try {
114
- if (!fs.existsSync(CONFIG_DIR)) {
115
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
120
+ if (!fs.existsSync(SHARED_AUTH_DIR)) {
121
+ fs.mkdirSync(SHARED_AUTH_DIR, { recursive: true });
116
122
  }
117
123
  const data = { idToken, refreshToken, updatedAt: new Date().toISOString() };
118
124
  fs.writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2), 'utf8');
@@ -1282,7 +1288,7 @@ ${'='.repeat(40)}
1282
1288
 
1283
1289
  const { deviceId, code, expiresIn } = await codeRes.json();
1284
1290
 
1285
- console.log(` Visit: ${bridgeHttpUrl}/device`);
1291
+ console.log(` Visit: ${PAIRING_URL}`);
1286
1292
  console.log(` Code: ${colors.bold}${code}${colors.reset}`);
1287
1293
  console.log('');
1288
1294
  console.log(` Code expires in ${Math.floor(expiresIn / 60)} minutes.`);
@@ -1339,32 +1345,49 @@ ${colors.cyan}${colors.bold}vibe-agent${colors.reset} - Persistent daemon for re
1339
1345
 
1340
1346
  ${colors.bold}Usage:${colors.reset}
1341
1347
  vibe-agent Start agent daemon
1342
- vibe-agent --login Sign in with Google (one-time)
1343
- vibe-agent --status Show agent status
1348
+ vibe-agent login Sign in with Google (one-time)
1349
+ vibe-agent logout Sign out and clear credentials
1350
+ vibe-agent status Show agent status
1351
+
1352
+ ${colors.bold}Commands:${colors.reset}
1353
+ login Sign in via device code flow
1354
+ logout Sign out and clear saved credentials
1355
+ status Show current status and exit
1356
+ help Show this help
1344
1357
 
1345
1358
  ${colors.bold}Options:${colors.reset}
1346
- --login Sign in via device code flow
1347
1359
  --name <name> Set host display name
1348
- --status Show current status and exit
1349
- --help, -h Show this help
1350
-
1351
- ${colors.bold}Advanced:${colors.reset}
1352
1360
  --bridge <url> Override bridge URL (default: wss://ws.minivibeapp.com)
1353
1361
  --token <token> Use specific Firebase token
1354
1362
 
1355
1363
  ${colors.bold}Examples:${colors.reset}
1356
- vibe-agent --login Sign in (one-time setup)
1364
+ vibe-agent login Sign in (one-time setup)
1357
1365
  vibe-agent Start agent
1358
1366
  vibe-agent --name "EC2" Start with custom name
1359
1367
  `);
1360
1368
  }
1361
1369
 
1362
1370
  function parseArgs() {
1363
- const args = process.argv.slice(2);
1371
+ const rawArgs = process.argv.slice(2);
1372
+
1373
+ // Support subcommand style (vibe-agent login) alongside flag style (vibe-agent --login)
1374
+ const subcommands = {
1375
+ 'login': '--login',
1376
+ 'logout': '--logout',
1377
+ 'status': '--status',
1378
+ 'help': '--help'
1379
+ };
1380
+
1381
+ // Transform first arg if it's a subcommand
1382
+ const args = rawArgs.length > 0 && subcommands[rawArgs[0]]
1383
+ ? [subcommands[rawArgs[0]], ...rawArgs.slice(1)]
1384
+ : rawArgs;
1385
+
1364
1386
  const options = {
1365
1387
  bridge: null,
1366
1388
  token: null,
1367
1389
  login: false,
1390
+ logout: false,
1368
1391
  name: null,
1369
1392
  status: false,
1370
1393
  help: false
@@ -1382,6 +1405,9 @@ function parseArgs() {
1382
1405
  case '--login':
1383
1406
  options.login = true;
1384
1407
  break;
1408
+ case '--logout':
1409
+ options.logout = true;
1410
+ break;
1385
1411
  case '--name':
1386
1412
  options.name = args[++i];
1387
1413
  break;
@@ -1443,6 +1469,21 @@ async function main() {
1443
1469
  process.exit(0);
1444
1470
  }
1445
1471
 
1472
+ // Logout flow
1473
+ if (options.logout) {
1474
+ try {
1475
+ if (fs.existsSync(AUTH_FILE)) {
1476
+ fs.unlinkSync(AUTH_FILE);
1477
+ log('Logged out successfully', colors.green);
1478
+ } else {
1479
+ log('Not logged in', colors.yellow);
1480
+ }
1481
+ } catch (err) {
1482
+ log(`Logout failed: ${err.message}`, colors.red);
1483
+ }
1484
+ process.exit(0);
1485
+ }
1486
+
1446
1487
  // Login flow
1447
1488
  if (options.login) {
1448
1489
  const httpUrl = bridgeUrl.replace('wss://', 'https://').replace('ws://', 'http://');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minivibe",
3
- "version": "0.2.2",
3
+ "version": "0.2.6",
4
4
  "description": "CLI wrapper for Claude Code with mobile remote control via MiniVibe iOS app",
5
5
  "author": "MiniVibe <hello@minivibeapp.com>",
6
6
  "homepage": "https://github.com/minivibeapp/minivibe",
package/vibe.js CHANGED
@@ -326,7 +326,21 @@ async function startHeadlessLogin() {
326
326
  }
327
327
 
328
328
  // Parse arguments
329
- const args = process.argv.slice(2);
329
+ const rawArgs = process.argv.slice(2);
330
+
331
+ // Support subcommand style (vibe login) alongside flag style (vibe --login)
332
+ const subcommands = {
333
+ 'login': '--login',
334
+ 'logout': '--logout',
335
+ 'status': '--status',
336
+ 'help': '--help'
337
+ };
338
+
339
+ // Transform first arg if it's a subcommand
340
+ const args = rawArgs.length > 0 && subcommands[rawArgs[0]]
341
+ ? [subcommands[rawArgs[0]], ...rawArgs.slice(1)]
342
+ : rawArgs;
343
+
330
344
  let initialPrompt = null;
331
345
  let resumeSessionId = null;
332
346
  let bridgeUrl = null;
@@ -348,11 +362,15 @@ vibe - Claude Code with mobile remote control
348
362
  Usage:
349
363
  vibe Start session (connects to bridge)
350
364
  vibe "prompt" Start with initial prompt
351
- vibe --login Sign in with Google
352
- vibe --agent Connect via local vibe-agent
365
+ vibe login Sign in with Google
366
+ vibe logout Sign out
367
+
368
+ Commands:
369
+ login Sign in via minivibeapp.com (opens browser)
370
+ logout Sign out and remove stored auth
371
+ help Show this help message
353
372
 
354
373
  Options:
355
- --login Sign in via minivibeapp.com (opens browser)
356
374
  --headless Use device code flow for servers (no browser)
357
375
  --agent [url] Connect via local vibe-agent (default: auto-discover)
358
376
  --name <name> Name this session (shown in mobile app)
@@ -365,13 +383,12 @@ Advanced:
365
383
  --remote <id> Remote control session via bridge (no local Claude needed)
366
384
  --list List running sessions on local agent
367
385
  --token <token> Set Firebase auth token manually
368
- --logout Remove stored auth token
369
386
  --node-pty Use Node.js PTY wrapper (required for Windows)
370
387
  --dangerously-skip-permissions Auto-approve all tool executions
371
388
  --help, -h Show this help message
372
389
 
373
390
  Examples:
374
- vibe --login Sign in (one-time setup)
391
+ vibe login Sign in (one-time setup)
375
392
  vibe Start session
376
393
  vibe "Fix the bug" Start with prompt
377
394
  vibe --e2e Enable encryption
@@ -428,15 +445,35 @@ For local-only use without remote control, run 'claude' directly.
428
445
  console.log('Token stored successfully');
429
446
  i++;
430
447
  } else if (args[i] === '--logout') {
431
- try {
432
- if (fs.existsSync(TOKEN_FILE)) {
448
+ let loggedOut = false;
449
+ let errors = [];
450
+
451
+ // Try to delete AUTH_FILE
452
+ if (fs.existsSync(AUTH_FILE)) {
453
+ try {
454
+ fs.unlinkSync(AUTH_FILE);
455
+ loggedOut = true;
456
+ } catch (err) {
457
+ errors.push(`auth.json: ${err.message}`);
458
+ }
459
+ }
460
+
461
+ // Try to delete TOKEN_FILE regardless of first result
462
+ if (fs.existsSync(TOKEN_FILE)) {
463
+ try {
433
464
  fs.unlinkSync(TOKEN_FILE);
434
- console.log('Logged out successfully');
435
- } else {
436
- console.log('Not logged in');
465
+ loggedOut = true;
466
+ } catch (err) {
467
+ errors.push(`token: ${err.message}`);
437
468
  }
438
- } catch (err) {
439
- console.error('Logout failed:', err.message);
469
+ }
470
+
471
+ if (errors.length > 0) {
472
+ console.error('Logout partially failed:', errors.join(', '));
473
+ } else if (loggedOut) {
474
+ console.log('Logged out successfully');
475
+ } else {
476
+ console.log('Not logged in');
440
477
  }
441
478
  process.exit(0);
442
479
  } else if (args[i] === '--node-pty') {