minivibe 0.2.6 → 0.2.10
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 +31 -0
- package/agent/agent.js +126 -8
- package/package.json +8 -3
- package/vibe.js +972 -33
package/README.md
CHANGED
|
@@ -78,6 +78,14 @@ Get token from MiniVibe iOS app: Settings > Copy Token for CLI.
|
|
|
78
78
|
|
|
79
79
|
## Usage Modes
|
|
80
80
|
|
|
81
|
+
| Mode | Command | Description |
|
|
82
|
+
|------|---------|-------------|
|
|
83
|
+
| Direct | `vibe` | WebSocket to bridge server (default when authenticated) |
|
|
84
|
+
| Direct | `vibe --bridge <url>` | WebSocket to custom relay server |
|
|
85
|
+
| Agent | `vibe --agent` | Through local vibe-agent daemon |
|
|
86
|
+
| Attach | `vibe --attach <id>` | Full terminal via local agent |
|
|
87
|
+
| Remote | `vibe --remote <id>` | Chat-style control, no local Claude needed |
|
|
88
|
+
|
|
81
89
|
### Direct Mode (Default)
|
|
82
90
|
|
|
83
91
|
Just run `vibe` after logging in:
|
|
@@ -109,6 +117,29 @@ vibe --agent --name "Backend Work"
|
|
|
109
117
|
- Sessions survive network hiccups
|
|
110
118
|
- Cleaner process management
|
|
111
119
|
|
|
120
|
+
### Attach Mode
|
|
121
|
+
|
|
122
|
+
Attach to a running session managed by the local agent:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
vibe --attach <session-id>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
This provides full terminal passthrough to the session, useful for debugging or taking over a session started remotely.
|
|
129
|
+
|
|
130
|
+
### Remote Mode
|
|
131
|
+
|
|
132
|
+
Control a session running elsewhere without needing Claude installed locally:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
vibe --remote <session-id>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This is useful for:
|
|
139
|
+
- Monitoring sessions from a different machine
|
|
140
|
+
- Sending messages to Claude from a lightweight client
|
|
141
|
+
- Reviewing and approving permissions remotely
|
|
142
|
+
|
|
112
143
|
## Options
|
|
113
144
|
|
|
114
145
|
### vibe
|
package/agent/agent.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Stop running sessions
|
|
10
10
|
*
|
|
11
11
|
* Usage:
|
|
12
|
-
* vibe-agent
|
|
12
|
+
* vibe-agent login Sign in (one-time)
|
|
13
13
|
* vibe-agent Start agent daemon
|
|
14
14
|
*/
|
|
15
15
|
|
|
@@ -38,6 +38,8 @@ const RECONNECT_DELAY_MS = 5000;
|
|
|
38
38
|
const HEARTBEAT_INTERVAL_MS = 30000;
|
|
39
39
|
const LOCAL_SERVER_PORT = 9999;
|
|
40
40
|
const PORT_FILE = path.join(os.homedir(), '.vibe-agent', 'port');
|
|
41
|
+
const PID_FILE = path.join(os.homedir(), '.vibe-agent', 'pid');
|
|
42
|
+
const START_TIME_FILE = path.join(os.homedir(), '.vibe-agent', 'start_time');
|
|
41
43
|
const MAX_SESSION_HISTORY_AGE_DAYS = 30;
|
|
42
44
|
const DEFAULT_BRIDGE_URL = 'wss://ws.minivibeapp.com';
|
|
43
45
|
const PAIRING_URL = 'https://minivibeapp.com/pair';
|
|
@@ -358,6 +360,13 @@ function startLocalServer() {
|
|
|
358
360
|
} catch (err) {
|
|
359
361
|
// Ignore
|
|
360
362
|
}
|
|
363
|
+
// Write PID and start time for status command
|
|
364
|
+
try {
|
|
365
|
+
fs.writeFileSync(PID_FILE, process.pid.toString(), 'utf8');
|
|
366
|
+
fs.writeFileSync(START_TIME_FILE, Date.now().toString(), 'utf8');
|
|
367
|
+
} catch (err) {
|
|
368
|
+
// Ignore
|
|
369
|
+
}
|
|
361
370
|
});
|
|
362
371
|
|
|
363
372
|
localServer.on('connection', (clientWs) => {
|
|
@@ -450,11 +459,17 @@ function stopLocalServer() {
|
|
|
450
459
|
localServer.close();
|
|
451
460
|
localServer = null;
|
|
452
461
|
}
|
|
453
|
-
// Remove port
|
|
462
|
+
// Remove port, PID, and start time files
|
|
454
463
|
try {
|
|
455
464
|
if (fs.existsSync(PORT_FILE)) {
|
|
456
465
|
fs.unlinkSync(PORT_FILE);
|
|
457
466
|
}
|
|
467
|
+
if (fs.existsSync(PID_FILE)) {
|
|
468
|
+
fs.unlinkSync(PID_FILE);
|
|
469
|
+
}
|
|
470
|
+
if (fs.existsSync(START_TIME_FILE)) {
|
|
471
|
+
fs.unlinkSync(START_TIME_FILE);
|
|
472
|
+
}
|
|
458
473
|
} catch (err) {
|
|
459
474
|
// Ignore
|
|
460
475
|
}
|
|
@@ -736,7 +751,7 @@ function handleMessage(msg) {
|
|
|
736
751
|
authToken = newToken;
|
|
737
752
|
send({ type: 'authenticate', token: newToken });
|
|
738
753
|
} else {
|
|
739
|
-
log('Please re-login: vibe-agent
|
|
754
|
+
log('Please re-login: vibe-agent login', colors.red);
|
|
740
755
|
}
|
|
741
756
|
})();
|
|
742
757
|
break;
|
|
@@ -1345,7 +1360,7 @@ ${colors.cyan}${colors.bold}vibe-agent${colors.reset} - Persistent daemon for re
|
|
|
1345
1360
|
|
|
1346
1361
|
${colors.bold}Usage:${colors.reset}
|
|
1347
1362
|
vibe-agent Start agent daemon
|
|
1348
|
-
vibe-agent login Sign in
|
|
1363
|
+
vibe-agent login Sign in (one-time)
|
|
1349
1364
|
vibe-agent logout Sign out and clear credentials
|
|
1350
1365
|
vibe-agent status Show agent status
|
|
1351
1366
|
|
|
@@ -1462,10 +1477,113 @@ async function main() {
|
|
|
1462
1477
|
|
|
1463
1478
|
// Status check
|
|
1464
1479
|
if (options.status) {
|
|
1465
|
-
console.log(
|
|
1466
|
-
console.log(
|
|
1467
|
-
|
|
1468
|
-
|
|
1480
|
+
console.log(`${colors.cyan}${colors.bold}vibe-agent${colors.reset}`);
|
|
1481
|
+
console.log();
|
|
1482
|
+
|
|
1483
|
+
// Check if agent is running
|
|
1484
|
+
let isRunning = false;
|
|
1485
|
+
let pid = null;
|
|
1486
|
+
let uptime = null;
|
|
1487
|
+
|
|
1488
|
+
try {
|
|
1489
|
+
if (fs.existsSync(PID_FILE)) {
|
|
1490
|
+
pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
|
|
1491
|
+
// Check if process is actually running
|
|
1492
|
+
try {
|
|
1493
|
+
process.kill(pid, 0); // Signal 0 just checks if process exists
|
|
1494
|
+
isRunning = true;
|
|
1495
|
+
|
|
1496
|
+
// Calculate uptime
|
|
1497
|
+
if (fs.existsSync(START_TIME_FILE)) {
|
|
1498
|
+
const startTime = parseInt(fs.readFileSync(START_TIME_FILE, 'utf8').trim(), 10);
|
|
1499
|
+
const uptimeMs = Date.now() - startTime;
|
|
1500
|
+
// Only show uptime if it's positive and reasonable
|
|
1501
|
+
if (uptimeMs > 0 && !isNaN(startTime)) {
|
|
1502
|
+
const hours = Math.floor(uptimeMs / (1000 * 60 * 60));
|
|
1503
|
+
const minutes = Math.floor((uptimeMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
1504
|
+
uptime = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
} catch (err) {
|
|
1508
|
+
// Process not running, stale PID file
|
|
1509
|
+
isRunning = false;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
// Ignore
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// Get active session count by connecting to local server
|
|
1517
|
+
let sessionCount = null;
|
|
1518
|
+
if (isRunning && fs.existsSync(PORT_FILE)) {
|
|
1519
|
+
try {
|
|
1520
|
+
const portStr = fs.readFileSync(PORT_FILE, 'utf8').trim();
|
|
1521
|
+
const port = parseInt(portStr, 10);
|
|
1522
|
+
|
|
1523
|
+
if (!isNaN(port) && port > 0) {
|
|
1524
|
+
// Quick check via local WebSocket
|
|
1525
|
+
const checkPromise = new Promise((resolve) => {
|
|
1526
|
+
const checkWs = new WebSocket(`ws://localhost:${port}`);
|
|
1527
|
+
const timeout = setTimeout(() => {
|
|
1528
|
+
try { checkWs.close(); } catch {}
|
|
1529
|
+
resolve(null);
|
|
1530
|
+
}, 1000);
|
|
1531
|
+
|
|
1532
|
+
checkWs.on('open', () => {
|
|
1533
|
+
checkWs.send(JSON.stringify({ type: 'list_sessions' }));
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
checkWs.on('message', (data) => {
|
|
1537
|
+
try {
|
|
1538
|
+
const msg = JSON.parse(data.toString());
|
|
1539
|
+
if (msg.type === 'sessions_list') {
|
|
1540
|
+
clearTimeout(timeout);
|
|
1541
|
+
resolve(msg.sessions?.length || 0);
|
|
1542
|
+
try { checkWs.close(); } catch {}
|
|
1543
|
+
}
|
|
1544
|
+
} catch (err) {
|
|
1545
|
+
// Ignore
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
checkWs.on('error', () => {
|
|
1550
|
+
clearTimeout(timeout);
|
|
1551
|
+
resolve(null);
|
|
1552
|
+
});
|
|
1553
|
+
|
|
1554
|
+
checkWs.on('close', () => {
|
|
1555
|
+
clearTimeout(timeout);
|
|
1556
|
+
});
|
|
1557
|
+
});
|
|
1558
|
+
|
|
1559
|
+
sessionCount = await checkPromise;
|
|
1560
|
+
}
|
|
1561
|
+
} catch (err) {
|
|
1562
|
+
// Ignore
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// Display status
|
|
1567
|
+
if (isRunning) {
|
|
1568
|
+
console.log(`Status: ${colors.green}running${colors.reset} (pid ${pid})`);
|
|
1569
|
+
if (uptime) {
|
|
1570
|
+
console.log(`Uptime: ${uptime}`);
|
|
1571
|
+
}
|
|
1572
|
+
} else {
|
|
1573
|
+
console.log(`Status: ${colors.dim}not running${colors.reset}`);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
console.log(`Host: ${hostName}`);
|
|
1577
|
+
console.log(`Bridge: ${bridgeUrl}`);
|
|
1578
|
+
|
|
1579
|
+
if (sessionCount !== null) {
|
|
1580
|
+
console.log(`Sessions: ${sessionCount} active`);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
console.log();
|
|
1584
|
+
console.log(`Auth: ${authToken ? colors.green + 'configured' + colors.reset : colors.yellow + 'not configured' + colors.reset}`);
|
|
1585
|
+
console.log(`Agent ID: ${agentId || colors.dim + 'will be assigned on first connect' + colors.reset}`);
|
|
1586
|
+
|
|
1469
1587
|
process.exit(0);
|
|
1470
1588
|
}
|
|
1471
1589
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minivibe",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
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",
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"start": "node vibe.js",
|
|
33
|
-
"agent": "node agent/agent.js"
|
|
33
|
+
"agent": "node agent/agent.js",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"uuid": "^9.0.0",
|
|
@@ -50,5 +52,8 @@
|
|
|
50
52
|
"minivibe",
|
|
51
53
|
"ios"
|
|
52
54
|
],
|
|
53
|
-
"license": "MIT"
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"vitest": "^4.0.17"
|
|
58
|
+
}
|
|
54
59
|
}
|