mstro-app 0.2.0 → 0.3.1

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.
Files changed (153) hide show
  1. package/PRIVACY.md +126 -0
  2. package/README.md +24 -23
  3. package/bin/commands/login.js +79 -49
  4. package/bin/mstro.js +305 -39
  5. package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
  6. package/dist/server/cli/headless/claude-invoker.js +137 -30
  7. package/dist/server/cli/headless/claude-invoker.js.map +1 -1
  8. package/dist/server/cli/headless/mcp-config.js +2 -2
  9. package/dist/server/cli/headless/mcp-config.js.map +1 -1
  10. package/dist/server/cli/headless/runner.d.ts +6 -1
  11. package/dist/server/cli/headless/runner.d.ts.map +1 -1
  12. package/dist/server/cli/headless/runner.js +59 -4
  13. package/dist/server/cli/headless/runner.js.map +1 -1
  14. package/dist/server/cli/headless/stall-assessor.d.ts +3 -1
  15. package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
  16. package/dist/server/cli/headless/stall-assessor.js +20 -1
  17. package/dist/server/cli/headless/stall-assessor.js.map +1 -1
  18. package/dist/server/cli/headless/tool-watchdog.d.ts +4 -1
  19. package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
  20. package/dist/server/cli/headless/tool-watchdog.js +30 -24
  21. package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
  22. package/dist/server/cli/headless/types.d.ts +20 -2
  23. package/dist/server/cli/headless/types.d.ts.map +1 -1
  24. package/dist/server/cli/improvisation-session-manager.d.ts +30 -3
  25. package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
  26. package/dist/server/cli/improvisation-session-manager.js +224 -31
  27. package/dist/server/cli/improvisation-session-manager.js.map +1 -1
  28. package/dist/server/index.js +6 -4
  29. package/dist/server/index.js.map +1 -1
  30. package/dist/server/mcp/bouncer-cli.js +53 -14
  31. package/dist/server/mcp/bouncer-cli.js.map +1 -1
  32. package/dist/server/mcp/bouncer-integration.d.ts +1 -1
  33. package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
  34. package/dist/server/mcp/bouncer-integration.js +70 -7
  35. package/dist/server/mcp/bouncer-integration.js.map +1 -1
  36. package/dist/server/mcp/security-audit.d.ts +3 -3
  37. package/dist/server/mcp/security-audit.d.ts.map +1 -1
  38. package/dist/server/mcp/security-audit.js.map +1 -1
  39. package/dist/server/mcp/server.js +3 -2
  40. package/dist/server/mcp/server.js.map +1 -1
  41. package/dist/server/services/analytics.d.ts +2 -2
  42. package/dist/server/services/analytics.d.ts.map +1 -1
  43. package/dist/server/services/analytics.js +13 -1
  44. package/dist/server/services/analytics.js.map +1 -1
  45. package/dist/server/services/files.js +7 -7
  46. package/dist/server/services/files.js.map +1 -1
  47. package/dist/server/services/pathUtils.js +1 -1
  48. package/dist/server/services/pathUtils.js.map +1 -1
  49. package/dist/server/services/platform.d.ts +2 -2
  50. package/dist/server/services/platform.d.ts.map +1 -1
  51. package/dist/server/services/platform.js +13 -1
  52. package/dist/server/services/platform.js.map +1 -1
  53. package/dist/server/services/sentry.d.ts +1 -1
  54. package/dist/server/services/sentry.d.ts.map +1 -1
  55. package/dist/server/services/sentry.js.map +1 -1
  56. package/dist/server/services/terminal/pty-manager.d.ts +12 -0
  57. package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
  58. package/dist/server/services/terminal/pty-manager.js +81 -6
  59. package/dist/server/services/terminal/pty-manager.js.map +1 -1
  60. package/dist/server/services/websocket/file-explorer-handlers.d.ts +5 -0
  61. package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -0
  62. package/dist/server/services/websocket/file-explorer-handlers.js +518 -0
  63. package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -0
  64. package/dist/server/services/websocket/file-utils.d.ts +4 -0
  65. package/dist/server/services/websocket/file-utils.d.ts.map +1 -1
  66. package/dist/server/services/websocket/file-utils.js +27 -8
  67. package/dist/server/services/websocket/file-utils.js.map +1 -1
  68. package/dist/server/services/websocket/git-handlers.d.ts +36 -0
  69. package/dist/server/services/websocket/git-handlers.d.ts.map +1 -0
  70. package/dist/server/services/websocket/git-handlers.js +797 -0
  71. package/dist/server/services/websocket/git-handlers.js.map +1 -0
  72. package/dist/server/services/websocket/git-pr-handlers.d.ts +4 -0
  73. package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -0
  74. package/dist/server/services/websocket/git-pr-handlers.js +299 -0
  75. package/dist/server/services/websocket/git-pr-handlers.js.map +1 -0
  76. package/dist/server/services/websocket/git-worktree-handlers.d.ts +4 -0
  77. package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -0
  78. package/dist/server/services/websocket/git-worktree-handlers.js +353 -0
  79. package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -0
  80. package/dist/server/services/websocket/handler-context.d.ts +32 -0
  81. package/dist/server/services/websocket/handler-context.d.ts.map +1 -0
  82. package/dist/server/services/websocket/handler-context.js +4 -0
  83. package/dist/server/services/websocket/handler-context.js.map +1 -0
  84. package/dist/server/services/websocket/handler.d.ts +27 -359
  85. package/dist/server/services/websocket/handler.d.ts.map +1 -1
  86. package/dist/server/services/websocket/handler.js +68 -2329
  87. package/dist/server/services/websocket/handler.js.map +1 -1
  88. package/dist/server/services/websocket/index.d.ts +1 -1
  89. package/dist/server/services/websocket/index.d.ts.map +1 -1
  90. package/dist/server/services/websocket/index.js.map +1 -1
  91. package/dist/server/services/websocket/session-handlers.d.ts +10 -0
  92. package/dist/server/services/websocket/session-handlers.d.ts.map +1 -0
  93. package/dist/server/services/websocket/session-handlers.js +508 -0
  94. package/dist/server/services/websocket/session-handlers.js.map +1 -0
  95. package/dist/server/services/websocket/settings-handlers.d.ts +6 -0
  96. package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -0
  97. package/dist/server/services/websocket/settings-handlers.js +125 -0
  98. package/dist/server/services/websocket/settings-handlers.js.map +1 -0
  99. package/dist/server/services/websocket/tab-handlers.d.ts +10 -0
  100. package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -0
  101. package/dist/server/services/websocket/tab-handlers.js +131 -0
  102. package/dist/server/services/websocket/tab-handlers.js.map +1 -0
  103. package/dist/server/services/websocket/terminal-handlers.d.ts +9 -0
  104. package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -0
  105. package/dist/server/services/websocket/terminal-handlers.js +220 -0
  106. package/dist/server/services/websocket/terminal-handlers.js.map +1 -0
  107. package/dist/server/services/websocket/types.d.ts +63 -2
  108. package/dist/server/services/websocket/types.d.ts.map +1 -1
  109. package/dist/server/utils/agent-manager.d.ts +22 -2
  110. package/dist/server/utils/agent-manager.d.ts.map +1 -1
  111. package/dist/server/utils/agent-manager.js +2 -2
  112. package/dist/server/utils/agent-manager.js.map +1 -1
  113. package/dist/server/utils/port-manager.js.map +1 -1
  114. package/hooks/bouncer.sh +17 -3
  115. package/package.json +7 -3
  116. package/server/README.md +176 -159
  117. package/server/cli/headless/claude-invoker.ts +172 -43
  118. package/server/cli/headless/mcp-config.ts +8 -8
  119. package/server/cli/headless/runner.ts +57 -4
  120. package/server/cli/headless/stall-assessor.ts +25 -0
  121. package/server/cli/headless/tool-watchdog.ts +33 -25
  122. package/server/cli/headless/types.ts +11 -2
  123. package/server/cli/improvisation-session-manager.ts +285 -37
  124. package/server/index.ts +15 -13
  125. package/server/mcp/README.md +59 -67
  126. package/server/mcp/bouncer-cli.ts +73 -20
  127. package/server/mcp/bouncer-integration.ts +99 -16
  128. package/server/mcp/security-audit.ts +4 -4
  129. package/server/mcp/server.ts +6 -5
  130. package/server/services/analytics.ts +16 -4
  131. package/server/services/files.ts +13 -13
  132. package/server/services/pathUtils.ts +2 -2
  133. package/server/services/platform.ts +17 -6
  134. package/server/services/sentry.ts +1 -1
  135. package/server/services/terminal/pty-manager.ts +88 -11
  136. package/server/services/websocket/file-explorer-handlers.ts +587 -0
  137. package/server/services/websocket/file-utils.ts +28 -9
  138. package/server/services/websocket/git-handlers.ts +924 -0
  139. package/server/services/websocket/git-pr-handlers.ts +363 -0
  140. package/server/services/websocket/git-worktree-handlers.ts +403 -0
  141. package/server/services/websocket/handler-context.ts +44 -0
  142. package/server/services/websocket/handler.ts +85 -2680
  143. package/server/services/websocket/index.ts +1 -1
  144. package/server/services/websocket/session-handlers.ts +575 -0
  145. package/server/services/websocket/settings-handlers.ts +150 -0
  146. package/server/services/websocket/tab-handlers.ts +150 -0
  147. package/server/services/websocket/terminal-handlers.ts +277 -0
  148. package/server/services/websocket/types.ts +137 -0
  149. package/server/utils/agent-manager.ts +6 -6
  150. package/server/utils/port-manager.ts +1 -1
  151. package/bin/release.sh +0 -110
  152. package/server/services/platform.test.ts +0 -1304
  153. package/server/services/websocket/handler.test.ts +0 -20
package/bin/mstro.js CHANGED
@@ -8,8 +8,8 @@
8
8
  * Main entry point for the Mstro AI assistant.
9
9
  *
10
10
  * Usage:
11
- * mstro # Start Mstro (auto-finds available port)
12
- * mstro login # Authenticate this device
11
+ * mstro # Start Mstro (logs in automatically if needed)
12
+ * mstro login # Re-authenticate this device
13
13
  * mstro logout # Sign out
14
14
  * mstro whoami # Show current user
15
15
  * mstro status # Show connection status
@@ -35,10 +35,27 @@ const CLIENT_ROOT = resolve(__dirname, '..');
35
35
  const pkg = JSON.parse(readFileSync(join(CLIENT_ROOT, 'package.json'), 'utf-8'));
36
36
 
37
37
  // Check for updates (runs async in background, notifies on next run)
38
+ // update-notifier initializes lastUpdateCheck to Date.now(), which means the
39
+ // first check won't happen until 24h after install. We detect first-run by
40
+ // checking if the configstore has never stored an update result, and if so
41
+ // reset the timestamp to force an immediate background check.
38
42
  const notifier = updateNotifier({
39
43
  pkg,
40
44
  updateCheckInterval: 1000 * 60 * 60 * 24 // Check daily
41
45
  });
46
+ try {
47
+ if (notifier.config && !notifier.config.has('update') && !notifier.update) {
48
+ const lastCheck = notifier.config.get('lastUpdateCheck');
49
+ // If lastUpdateCheck was just set (within the last 30s), this is a fresh
50
+ // configstore — reset it to 0 so the library spawns a check immediately.
51
+ if (lastCheck && (Date.now() - lastCheck) < 30_000) {
52
+ notifier.config.set('lastUpdateCheck', 0);
53
+ notifier.check();
54
+ }
55
+ }
56
+ } catch {
57
+ // Non-critical — don't let update check logic crash the CLI
58
+ }
42
59
 
43
60
  // Capture the user's original working directory before any cwd changes
44
61
  const USER_CWD = process.cwd();
@@ -49,6 +66,7 @@ const MSTRO_FIRST_RUN_FLAG = join(MSTRO_CONFIG_DIR, '.configured');
49
66
  const CLAUDE_SETTINGS_FILE = join(homedir(), '.claude', 'settings.json');
50
67
  const CLAUDE_HOOKS_DIR = join(homedir(), '.claude', 'hooks');
51
68
  const BOUNCER_HOOK_FILE = join(CLAUDE_HOOKS_DIR, 'bouncer.sh');
69
+ const PTY_SETUP_DISMISSED_FLAG = join(MSTRO_CONFIG_DIR, '.pty-setup-dismissed');
52
70
 
53
71
  /**
54
72
  * Mark Mstro as configured by writing the first-run flag file
@@ -193,18 +211,221 @@ async function promptBouncerSetup() {
193
211
  }
194
212
  }
195
213
 
214
+ /**
215
+ * Check if node-pty native module is loadable
216
+ */
217
+ async function isNodePtyAvailable() {
218
+ try {
219
+ await import('node-pty');
220
+ return true;
221
+ } catch {
222
+ return false;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Check if user has dismissed the pty setup prompt
228
+ */
229
+ function hasUserDismissedPtySetup() {
230
+ return existsSync(PTY_SETUP_DISMISSED_FLAG);
231
+ }
232
+
233
+ /**
234
+ * Mark pty setup prompt as dismissed
235
+ */
236
+ function markPtySetupDismissed() {
237
+ if (!existsSync(MSTRO_CONFIG_DIR)) {
238
+ mkdirSync(MSTRO_CONFIG_DIR, { recursive: true, mode: 0o700 });
239
+ }
240
+ writeFileSync(PTY_SETUP_DISMISSED_FLAG, new Date().toISOString());
241
+ }
242
+
243
+ /**
244
+ * Show a one-line warning that node-pty is not available
245
+ */
246
+ function showPtyWarning() {
247
+ log(' Terminal support not available. Run: mstro setup-terminal', colors.dim);
248
+ }
249
+
250
+ /**
251
+ * Get platform-specific build tool instructions
252
+ */
253
+ function getPtyBuildInstructions() {
254
+ const os = process.platform;
255
+ if (os === 'darwin') {
256
+ return ' Install Xcode Command Line Tools: xcode-select --install';
257
+ }
258
+ if (os === 'win32') {
259
+ return ' Install Windows Build Tools: npm install -g windows-build-tools';
260
+ }
261
+ return ' Debian/Ubuntu: sudo apt install build-essential python3\n' +
262
+ ' Fedora/RHEL: sudo dnf install gcc-c++ make python3\n' +
263
+ ' Arch: sudo pacman -S base-devel python';
264
+ }
265
+
266
+ /**
267
+ * Attempt to rebuild/install node-pty from CLIENT_ROOT
268
+ * Returns true if npm command succeeded, false otherwise
269
+ */
270
+ function attemptPtyRebuild() {
271
+ return new Promise((resolve) => {
272
+ const nodePtyDir = join(CLIENT_ROOT, 'node_modules', 'node-pty');
273
+ const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
274
+ const command = existsSync(nodePtyDir) ? 'rebuild' : 'install';
275
+ const args = command === 'rebuild'
276
+ ? ['rebuild', 'node-pty']
277
+ : ['install', 'node-pty', '--no-save'];
278
+
279
+ log(`\n ${command === 'rebuild' ? 'Rebuilding' : 'Installing'} node-pty...`, colors.dim);
280
+
281
+ const child = spawn(npmCmd, args, {
282
+ cwd: CLIENT_ROOT,
283
+ stdio: 'inherit',
284
+ });
285
+
286
+ child.on('error', (err) => {
287
+ log(` Error: ${err.message}`, colors.red);
288
+ resolve(false);
289
+ });
290
+
291
+ child.on('exit', (code) => {
292
+ resolve(code === 0);
293
+ });
294
+ });
295
+ }
296
+
297
+ /**
298
+ * Prompt user to set up node-pty for terminal support
299
+ * Returns: 'configure' | 'skip' | 'never'
300
+ */
301
+ async function promptPtySetup() {
302
+ log('\n Terminal Support\n', colors.bold + colors.cyan);
303
+ log(' Mstro includes a web terminal that lets you open a shell', colors.dim);
304
+ log(' directly in your browser. This requires compiling a native module (node-pty).\n', colors.dim);
305
+
306
+ const isInteractive = process.stdin.isTTY;
307
+
308
+ if (!isInteractive) {
309
+ log(' Non-interactive mode: skipping terminal setup.', colors.yellow);
310
+ log(' Run "mstro setup-terminal" to enable terminal support.\n', colors.dim);
311
+ return 'skip';
312
+ }
313
+
314
+ log(' Set up terminal support now?', colors.bold);
315
+ log(' [Y] Yes, compile now (requires build tools)', colors.dim);
316
+ log(' [n] Not now (ask again next time)', colors.dim);
317
+ log(' [d] Don\'t show this again\n', colors.dim);
318
+
319
+ const answer = await prompt(' Your choice [Y/n/d]: ');
320
+ const choice = answer.toLowerCase();
321
+
322
+ if (choice === '' || choice === 'y' || choice === 'yes') {
323
+ return 'configure';
324
+ }
325
+ if (choice === 'd' || choice === 'dont' || choice === "don't") {
326
+ log('\n Got it! You can set up later with: mstro setup-terminal\n', colors.dim);
327
+ markPtySetupDismissed();
328
+ return 'never';
329
+ }
330
+ log('\n Skipping for now. Will ask again next time.', colors.yellow);
331
+ log(' You can also set up with: mstro setup-terminal\n', colors.dim);
332
+ return 'skip';
333
+ }
334
+
335
+ /**
336
+ * Run the pty rebuild and show results
337
+ */
338
+ async function runPtySetup() {
339
+ const success = await attemptPtyRebuild();
340
+
341
+ if (success) {
342
+ const available = await isNodePtyAvailable();
343
+ if (available) {
344
+ log('\n Terminal support enabled successfully!\n', colors.bold + colors.green);
345
+ return true;
346
+ }
347
+ log('\n node-pty installed but failed to load.', colors.red);
348
+ }
349
+
350
+ log('\n Could not compile node-pty automatically.\n', colors.yellow);
351
+ log(' You may need to install build tools first:\n', colors.bold);
352
+ log(getPtyBuildInstructions(), colors.dim);
353
+ log('');
354
+ log(' After installing build tools, run: mstro setup-terminal\n', colors.dim);
355
+ return false;
356
+ }
357
+
358
+ /**
359
+ * Read alive mstro instances and session token for server communication.
360
+ * Returns null if no running servers can be reached.
361
+ */
362
+ function getAliveInstances() {
363
+ const mstroDir = join(homedir(), '.mstro');
364
+ const instancesPath = join(mstroDir, 'instances.json');
365
+ const tokenPath = join(mstroDir, 'session-token');
366
+
367
+ if (!existsSync(instancesPath) || !existsSync(tokenPath)) return null;
368
+
369
+ try {
370
+ const instances = JSON.parse(readFileSync(instancesPath, 'utf-8'));
371
+ const token = readFileSync(tokenPath, 'utf-8').trim();
372
+ if (!Array.isArray(instances) || !token) return null;
373
+
374
+ const now = Date.now();
375
+ const alive = instances.filter(i => now - i.lastHeartbeat < 2 * 60 * 1000);
376
+ return alive.length > 0 ? { alive, token } : null;
377
+ } catch {
378
+ return null;
379
+ }
380
+ }
381
+
382
+ /**
383
+ * Notify running mstro servers to reload node-pty.
384
+ * Reads instances from ~/.mstro/instances.json and POSTs to /api/reload-pty.
385
+ */
386
+ async function notifyRunningServers() {
387
+ const result = getAliveInstances();
388
+ if (!result) {
389
+ log(' Restart mstro to enable terminal support.\n', colors.dim);
390
+ return;
391
+ }
392
+
393
+ let reloaded = 0;
394
+ for (const instance of result.alive) {
395
+ try {
396
+ const res = await fetch(`http://localhost:${instance.port}/api/reload-pty`, {
397
+ method: 'POST',
398
+ headers: { 'x-session-token': result.token },
399
+ });
400
+ if (res.ok) {
401
+ const data = await res.json();
402
+ if (data.success) reloaded++;
403
+ }
404
+ } catch {
405
+ // Server not reachable — stale instance
406
+ }
407
+ }
408
+
409
+ if (reloaded > 0) {
410
+ log(` Notified ${reloaded} running mstro server${reloaded > 1 ? 's' : ''} — terminal is ready!\n`, colors.green);
411
+ } else {
412
+ log(' Restart mstro to enable terminal support.\n', colors.dim);
413
+ }
414
+ }
415
+
196
416
  function showHelp() {
197
- log('\n Mstro - No-code AI Workspace\n', colors.bold + colors.cyan);
198
- log(' Run Claude Code workflows from your laptop, cloud VM, or any machine.\n', colors.dim);
417
+ log('\n Mstro - Run Claude Code from any browser\n', colors.bold + colors.cyan);
418
+ log(' Streams live Claude Code sessions from your machine to mstro.app.\n', colors.dim);
199
419
  log(' Usage:', colors.bold);
200
- log(' mstro Start Mstro (auto-finds available port)', colors.dim);
201
- log(' mstro login Authenticate this device with mstro.app', colors.dim);
420
+ log(' mstro Start Mstro (logs in automatically if needed)', colors.dim);
421
+ log(' mstro login Re-authenticate this device with mstro.app', colors.dim);
202
422
  log(' mstro logout Sign out of mstro.app', colors.dim);
203
423
  log(' mstro whoami Show current user and device info', colors.dim);
204
424
  log(' mstro status Show connection and auth status', colors.dim);
205
425
  log(' mstro telemetry [on|off] Enable/disable anonymous telemetry', colors.dim);
206
426
  log(' mstro -p 4105 Start on specific port (overrides auto port)', colors.dim);
207
427
  log(' mstro configure-hooks Configure Claude Code security hooks', colors.dim);
428
+ log(' mstro setup-terminal Enable web terminal (compiles native module)', colors.dim);
208
429
  log(' mstro --version Show version number', colors.dim);
209
430
  log(' mstro --help Show this help message', colors.dim);
210
431
  log('');
@@ -214,7 +435,7 @@ function showHelp() {
214
435
  log(' --verbose, -v Enable verbose output', colors.dim);
215
436
  log('');
216
437
  log(' Authentication:', colors.bold);
217
- log(' Run "mstro login" to connect this device to your mstro.app account.', colors.dim);
438
+ log(' Running "mstro" will prompt you to log in automatically if needed.', colors.dim);
218
439
  log(' Once logged in, machines sync automatically with your web dashboard.', colors.dim);
219
440
  log('');
220
441
  log(' Security:', colors.bold);
@@ -283,11 +504,12 @@ function runConfigureHooks(andThenStart = false) {
283
504
  process.exit(1);
284
505
  });
285
506
 
286
- child.on('exit', (code) => {
507
+ child.on('exit', async (code) => {
287
508
  if (code === 0) {
288
509
  markConfigured();
289
510
  if (andThenStart) {
290
- // After configuring, start the server
511
+ // After configuring bouncer, prompt for terminal setup before starting
512
+ await ensurePtySetup();
291
513
  const requestedPort = parsePort(process.argv.slice(2));
292
514
  const envOverrides = requestedPort ? { PORT: String(requestedPort) } : {};
293
515
  runNpmScript('start', [], envOverrides);
@@ -321,14 +543,18 @@ function parsePort(args) {
321
543
  * Show update notification if available
322
544
  */
323
545
  function showUpdateNotification() {
324
- if (notifier.update && semverGt(notifier.update.latest, notifier.update.current)) {
325
- const { current, latest, type } = notifier.update;
326
- const updateCmd = 'npm i -g mstro@latest';
327
-
328
- log('');
329
- log(` ${colors.yellow}Update available:${colors.reset} ${colors.dim}${current}${colors.reset} → ${colors.green}${latest}${colors.reset} ${colors.dim}(${type})${colors.reset}`);
330
- log(` Run: ${colors.cyan}${updateCmd}${colors.reset}`);
331
- log('');
546
+ try {
547
+ if (notifier.update && semverGt(notifier.update.latest, notifier.update.current)) {
548
+ const { current, latest, type } = notifier.update;
549
+ const updateCmd = `npm i -g ${pkg.name}`;
550
+
551
+ log('');
552
+ log(` ${colors.yellow}Update available:${colors.reset} ${colors.dim}${current}${colors.reset} → ${colors.green}${latest}${colors.reset} ${colors.dim}(${type})${colors.reset}`);
553
+ log(` Run: ${colors.cyan}${updateCmd}${colors.reset}`);
554
+ log('');
555
+ }
556
+ } catch {
557
+ // Don't let a corrupted cache or invalid semver crash the CLI
332
558
  }
333
559
  }
334
560
 
@@ -349,36 +575,61 @@ function isLoggedIn() {
349
575
  }
350
576
 
351
577
  /**
352
- * Show login required message
578
+ * Auto-login if not authenticated. Exits on failure.
353
579
  */
354
- function showLoginRequired() {
355
- log('\n Authentication required', colors.bold + colors.yellow);
356
- log('');
357
- log(' You must be logged in to use mstro.', colors.dim);
358
- log(' Run "mstro login" to authenticate this device.', colors.dim);
359
- log('');
580
+ async function ensureLoggedIn() {
581
+ if (isLoggedIn()) return;
582
+ log('\n Not logged in — starting authentication...\n', colors.bold + colors.cyan);
583
+ try {
584
+ const { login } = await import('./commands/login.js');
585
+ await login(args, { inline: true });
586
+ } catch (err) {
587
+ log(`\n Login failed: ${err.message}`, colors.red);
588
+ log(' Run "mstro login" to try again.\n', colors.dim);
589
+ process.exit(1);
590
+ }
360
591
  }
361
592
 
362
593
  /**
363
- * Check if node-pty is loadable (native module compiled correctly)
594
+ * Prompt for bouncer setup if not configured
595
+ * Returns true if runConfigureHooks was called (async exit path)
364
596
  */
365
- async function startServer(envOverrides) {
366
- if (!isLoggedIn()) {
367
- showLoginRequired();
368
- process.exit(1);
597
+ async function ensureBouncerSetup() {
598
+ if (isBouncerConfigured()) return false;
599
+ if (hasUserDismissedSetup()) {
600
+ showBouncerWarning();
601
+ return false;
369
602
  }
603
+ const choice = await promptBouncerSetup();
604
+ if (choice === 'configure') {
605
+ runConfigureHooks(true);
606
+ return true;
607
+ }
608
+ return false;
609
+ }
370
610
 
371
- if (!isBouncerConfigured()) {
372
- if (hasUserDismissedSetup()) {
373
- showBouncerWarning();
374
- } else {
375
- const choice = await promptBouncerSetup();
376
- if (choice === 'configure') {
377
- runConfigureHooks(true);
378
- return;
379
- }
380
- }
611
+ /**
612
+ * Prompt for node-pty setup if not available
613
+ */
614
+ async function ensurePtySetup() {
615
+ const ptyAvailable = await isNodePtyAvailable();
616
+ if (ptyAvailable) return;
617
+ if (hasUserDismissedPtySetup()) {
618
+ showPtyWarning();
619
+ return;
620
+ }
621
+ const choice = await promptPtySetup();
622
+ if (choice === 'configure') {
623
+ await runPtySetup();
381
624
  }
625
+ }
626
+
627
+ async function startServer(envOverrides) {
628
+ await ensureLoggedIn();
629
+
630
+ if (await ensureBouncerSetup()) return;
631
+
632
+ await ensurePtySetup();
382
633
 
383
634
  showUpdateNotification();
384
635
  runNpmScript('start', [], envOverrides);
@@ -417,6 +668,20 @@ async function main() {
417
668
  await telemetry(args.slice(args.indexOf('telemetry') + 1));
418
669
  }],
419
670
  ['configure-hooks', () => runConfigureHooks(false)],
671
+ ['setup-terminal', async () => {
672
+ log('\n Mstro Terminal Setup\n', colors.bold + colors.cyan);
673
+ const alreadyAvailable = await isNodePtyAvailable();
674
+ if (alreadyAvailable) {
675
+ log(' node-pty is already available. Terminal support is enabled!\n', colors.green);
676
+ await notifyRunningServers();
677
+ return;
678
+ }
679
+ const success = await runPtySetup();
680
+ if (success) {
681
+ await notifyRunningServers();
682
+ }
683
+ process.exit(success ? 0 : 1);
684
+ }],
420
685
  ]);
421
686
 
422
687
  // Flag-based commands
@@ -441,6 +706,7 @@ async function main() {
441
706
  const handler = subcommand ? commands.get(subcommand) : undefined;
442
707
  if (handler) {
443
708
  await handler();
709
+ showUpdateNotification();
444
710
  return;
445
711
  }
446
712
 
@@ -1 +1 @@
1
- {"version":3,"file":"claude-invoker.d.ts","sourceRoot":"","sources":["../../../../server/cli/headless/claude-invoker.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,oBAAoB,CAAC;AAO9D,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EAGvB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC7C;AAm5BD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC,CA0I1B"}
1
+ {"version":3,"file":"claude-invoker.d.ts","sourceRoot":"","sources":["../../../../server/cli/headless/claude-invoker.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,oBAAoB,CAAC;AAO9D,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EAGvB,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC7C;AAogCD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC,CA0H1B"}