minivibe 0.2.14 → 0.2.16

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/agent/agent.js CHANGED
@@ -681,7 +681,7 @@ function handleLocalMessage(clientWs, msg) {
681
681
  // Log important message types from CLI
682
682
  const sessionPrefix = msg.sessionId ? `[${msg.sessionId.slice(0, 8)}]` : '';
683
683
  if (msg.type === 'claude_message') {
684
- // Content is nested in msg.message.content (not msg.content)
684
+ // Content is nested in msg.message.content
685
685
  const rawContent = msg.message?.content || msg.content;
686
686
  const sender = msg.message?.sender || 'claude';
687
687
  // Handle both string and object content (e.g., encrypted)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minivibe",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
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
@@ -200,6 +200,36 @@ async function refreshIdToken() {
200
200
  }
201
201
  }
202
202
 
203
+ // Check if JWT token is expired or will expire within given seconds
204
+ function isTokenExpired(token, bufferSeconds = 60) {
205
+ if (!token) return true;
206
+ try {
207
+ // Decode JWT payload (middle part)
208
+ const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
209
+ const now = Math.floor(Date.now() / 1000);
210
+ return payload.exp <= (now + bufferSeconds);
211
+ } catch (err) {
212
+ return true; // Treat invalid tokens as expired
213
+ }
214
+ }
215
+
216
+ // Proactively refresh token if expired or close to expiry
217
+ async function ensureValidToken() {
218
+ const auth = getStoredAuth();
219
+ if (!auth?.idToken) return null;
220
+
221
+ // If token is expired or will expire in next 5 minutes, refresh it
222
+ if (isTokenExpired(auth.idToken, 300)) {
223
+ if (auth.refreshToken) {
224
+ logStatus('Token expired or expiring soon, refreshing...');
225
+ return await refreshIdToken();
226
+ }
227
+ return null;
228
+ }
229
+
230
+ return auth.idToken;
231
+ }
232
+
203
233
  // Browser-based login - uses device code flow with public URL
204
234
  async function startLoginFlow(openBrowser = true) {
205
235
  // Convert WebSocket URL to HTTP for API calls
@@ -3189,7 +3219,27 @@ function startClaudeAndTerminal() {
3189
3219
  }
3190
3220
  }
3191
3221
 
3192
- function main() {
3222
+ async function main() {
3223
+ // Proactively refresh token if expired before connecting
3224
+ if (bridgeUrl && authToken) {
3225
+ const validToken = await ensureValidToken();
3226
+ if (validToken) {
3227
+ authToken = validToken;
3228
+ } else if (!validToken && getStoredAuth()?.refreshToken) {
3229
+ // Had refresh token but refresh failed - show error
3230
+ log('', colors.red);
3231
+ log('╔════════════════════════════════════════════╗', colors.red);
3232
+ log('║ Token refresh failed ║', colors.red);
3233
+ log('║ ║', colors.red);
3234
+ log('║ Please re-login: ║', colors.red);
3235
+ log('║ vibe login ║', colors.red);
3236
+ log('║ ║', colors.red);
3237
+ log('╚════════════════════════════════════════════╝', colors.red);
3238
+ log('', colors.red);
3239
+ process.exit(1);
3240
+ }
3241
+ }
3242
+
3193
3243
  console.log('');
3194
3244
  log('🎵 vibe-cli', colors.bright + colors.magenta);
3195
3245
  log('══════════════════════════════════════', colors.dim);