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.
- package/PRIVACY.md +126 -0
- package/README.md +24 -23
- package/bin/commands/login.js +79 -49
- package/bin/mstro.js +305 -39
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +137 -30
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/mcp-config.js +2 -2
- package/dist/server/cli/headless/mcp-config.js.map +1 -1
- package/dist/server/cli/headless/runner.d.ts +6 -1
- package/dist/server/cli/headless/runner.d.ts.map +1 -1
- package/dist/server/cli/headless/runner.js +59 -4
- package/dist/server/cli/headless/runner.js.map +1 -1
- package/dist/server/cli/headless/stall-assessor.d.ts +3 -1
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +20 -1
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts +4 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.js +30 -24
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
- package/dist/server/cli/headless/types.d.ts +20 -2
- package/dist/server/cli/headless/types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +30 -3
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +224 -31
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/index.js +6 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-cli.js +53 -14
- package/dist/server/mcp/bouncer-cli.js.map +1 -1
- package/dist/server/mcp/bouncer-integration.d.ts +1 -1
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-integration.js +70 -7
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/security-audit.d.ts +3 -3
- package/dist/server/mcp/security-audit.d.ts.map +1 -1
- package/dist/server/mcp/security-audit.js.map +1 -1
- package/dist/server/mcp/server.js +3 -2
- package/dist/server/mcp/server.js.map +1 -1
- package/dist/server/services/analytics.d.ts +2 -2
- package/dist/server/services/analytics.d.ts.map +1 -1
- package/dist/server/services/analytics.js +13 -1
- package/dist/server/services/analytics.js.map +1 -1
- package/dist/server/services/files.js +7 -7
- package/dist/server/services/files.js.map +1 -1
- package/dist/server/services/pathUtils.js +1 -1
- package/dist/server/services/pathUtils.js.map +1 -1
- package/dist/server/services/platform.d.ts +2 -2
- package/dist/server/services/platform.d.ts.map +1 -1
- package/dist/server/services/platform.js +13 -1
- package/dist/server/services/platform.js.map +1 -1
- package/dist/server/services/sentry.d.ts +1 -1
- package/dist/server/services/sentry.d.ts.map +1 -1
- package/dist/server/services/sentry.js.map +1 -1
- package/dist/server/services/terminal/pty-manager.d.ts +12 -0
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-manager.js +81 -6
- package/dist/server/services/terminal/pty-manager.js.map +1 -1
- package/dist/server/services/websocket/file-explorer-handlers.d.ts +5 -0
- package/dist/server/services/websocket/file-explorer-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/file-explorer-handlers.js +518 -0
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -0
- package/dist/server/services/websocket/file-utils.d.ts +4 -0
- package/dist/server/services/websocket/file-utils.d.ts.map +1 -1
- package/dist/server/services/websocket/file-utils.js +27 -8
- package/dist/server/services/websocket/file-utils.js.map +1 -1
- package/dist/server/services/websocket/git-handlers.d.ts +36 -0
- package/dist/server/services/websocket/git-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-handlers.js +797 -0
- package/dist/server/services/websocket/git-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-pr-handlers.d.ts +4 -0
- package/dist/server/services/websocket/git-pr-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-pr-handlers.js +299 -0
- package/dist/server/services/websocket/git-pr-handlers.js.map +1 -0
- package/dist/server/services/websocket/git-worktree-handlers.d.ts +4 -0
- package/dist/server/services/websocket/git-worktree-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/git-worktree-handlers.js +353 -0
- package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -0
- package/dist/server/services/websocket/handler-context.d.ts +32 -0
- package/dist/server/services/websocket/handler-context.d.ts.map +1 -0
- package/dist/server/services/websocket/handler-context.js +4 -0
- package/dist/server/services/websocket/handler-context.js.map +1 -0
- package/dist/server/services/websocket/handler.d.ts +27 -359
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +68 -2329
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/index.d.ts +1 -1
- package/dist/server/services/websocket/index.d.ts.map +1 -1
- package/dist/server/services/websocket/index.js.map +1 -1
- package/dist/server/services/websocket/session-handlers.d.ts +10 -0
- package/dist/server/services/websocket/session-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/session-handlers.js +508 -0
- package/dist/server/services/websocket/session-handlers.js.map +1 -0
- package/dist/server/services/websocket/settings-handlers.d.ts +6 -0
- package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/settings-handlers.js +125 -0
- package/dist/server/services/websocket/settings-handlers.js.map +1 -0
- package/dist/server/services/websocket/tab-handlers.d.ts +10 -0
- package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/tab-handlers.js +131 -0
- package/dist/server/services/websocket/tab-handlers.js.map +1 -0
- package/dist/server/services/websocket/terminal-handlers.d.ts +9 -0
- package/dist/server/services/websocket/terminal-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/terminal-handlers.js +220 -0
- package/dist/server/services/websocket/terminal-handlers.js.map +1 -0
- package/dist/server/services/websocket/types.d.ts +63 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/dist/server/utils/agent-manager.d.ts +22 -2
- package/dist/server/utils/agent-manager.d.ts.map +1 -1
- package/dist/server/utils/agent-manager.js +2 -2
- package/dist/server/utils/agent-manager.js.map +1 -1
- package/dist/server/utils/port-manager.js.map +1 -1
- package/hooks/bouncer.sh +17 -3
- package/package.json +7 -3
- package/server/README.md +176 -159
- package/server/cli/headless/claude-invoker.ts +172 -43
- package/server/cli/headless/mcp-config.ts +8 -8
- package/server/cli/headless/runner.ts +57 -4
- package/server/cli/headless/stall-assessor.ts +25 -0
- package/server/cli/headless/tool-watchdog.ts +33 -25
- package/server/cli/headless/types.ts +11 -2
- package/server/cli/improvisation-session-manager.ts +285 -37
- package/server/index.ts +15 -13
- package/server/mcp/README.md +59 -67
- package/server/mcp/bouncer-cli.ts +73 -20
- package/server/mcp/bouncer-integration.ts +99 -16
- package/server/mcp/security-audit.ts +4 -4
- package/server/mcp/server.ts +6 -5
- package/server/services/analytics.ts +16 -4
- package/server/services/files.ts +13 -13
- package/server/services/pathUtils.ts +2 -2
- package/server/services/platform.ts +17 -6
- package/server/services/sentry.ts +1 -1
- package/server/services/terminal/pty-manager.ts +88 -11
- package/server/services/websocket/file-explorer-handlers.ts +587 -0
- package/server/services/websocket/file-utils.ts +28 -9
- package/server/services/websocket/git-handlers.ts +924 -0
- package/server/services/websocket/git-pr-handlers.ts +363 -0
- package/server/services/websocket/git-worktree-handlers.ts +403 -0
- package/server/services/websocket/handler-context.ts +44 -0
- package/server/services/websocket/handler.ts +85 -2680
- package/server/services/websocket/index.ts +1 -1
- package/server/services/websocket/session-handlers.ts +575 -0
- package/server/services/websocket/settings-handlers.ts +150 -0
- package/server/services/websocket/tab-handlers.ts +150 -0
- package/server/services/websocket/terminal-handlers.ts +277 -0
- package/server/services/websocket/types.ts +137 -0
- package/server/utils/agent-manager.ts +6 -6
- package/server/utils/port-manager.ts +1 -1
- package/bin/release.sh +0 -110
- package/server/services/platform.test.ts +0 -1304
- 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 (
|
|
12
|
-
* mstro login #
|
|
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 -
|
|
198
|
-
log('
|
|
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 (
|
|
201
|
-
log(' mstro login
|
|
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('
|
|
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,
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
*
|
|
578
|
+
* Auto-login if not authenticated. Exits on failure.
|
|
353
579
|
*/
|
|
354
|
-
function
|
|
355
|
-
|
|
356
|
-
log('');
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
-
*
|
|
594
|
+
* Prompt for bouncer setup if not configured
|
|
595
|
+
* Returns true if runConfigureHooks was called (async exit path)
|
|
364
596
|
*/
|
|
365
|
-
async function
|
|
366
|
-
if (
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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;
|
|
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"}
|