mstro-app 0.1.58 → 0.3.0
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 +85 -42
- package/bin/commands/logout.js +35 -1
- package/bin/commands/status.js +1 -1
- package/bin/mstro.js +231 -131
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +550 -115
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/index.d.ts +2 -1
- package/dist/server/cli/headless/index.d.ts.map +1 -1
- package/dist/server/cli/headless/index.js +2 -0
- package/dist/server/cli/headless/index.js.map +1 -1
- package/dist/server/cli/headless/prompt-utils.d.ts +5 -8
- package/dist/server/cli/headless/prompt-utils.d.ts.map +1 -1
- package/dist/server/cli/headless/prompt-utils.js +40 -5
- package/dist/server/cli/headless/prompt-utils.js.map +1 -1
- package/dist/server/cli/headless/runner.d.ts +1 -1
- package/dist/server/cli/headless/runner.d.ts.map +1 -1
- package/dist/server/cli/headless/runner.js +52 -7
- package/dist/server/cli/headless/runner.js.map +1 -1
- package/dist/server/cli/headless/stall-assessor.d.ts +79 -1
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +355 -20
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts +70 -0
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -0
- package/dist/server/cli/headless/tool-watchdog.js +302 -0
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -0
- package/dist/server/cli/headless/types.d.ts +98 -1
- package/dist/server/cli/headless/types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +136 -2
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +929 -132
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/index.js +5 -13
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-integration.js +18 -0
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/security-audit.d.ts +2 -2
- package/dist/server/mcp/security-audit.d.ts.map +1 -1
- package/dist/server/mcp/security-audit.js +12 -8
- package/dist/server/mcp/security-audit.js.map +1 -1
- package/dist/server/mcp/security-patterns.d.ts.map +1 -1
- package/dist/server/mcp/security-patterns.js +9 -4
- package/dist/server/mcp/security-patterns.js.map +1 -1
- package/dist/server/routes/improvise.js +6 -6
- package/dist/server/routes/improvise.js.map +1 -1
- package/dist/server/services/analytics.d.ts +2 -0
- package/dist/server/services/analytics.d.ts.map +1 -1
- package/dist/server/services/analytics.js +26 -4
- package/dist/server/services/analytics.js.map +1 -1
- package/dist/server/services/platform.d.ts.map +1 -1
- package/dist/server/services/platform.js +17 -10
- package/dist/server/services/platform.js.map +1 -1
- package/dist/server/services/sandbox-utils.d.ts +6 -0
- package/dist/server/services/sandbox-utils.d.ts.map +1 -0
- package/dist/server/services/sandbox-utils.js +72 -0
- package/dist/server/services/sandbox-utils.js.map +1 -0
- package/dist/server/services/settings.d.ts +6 -0
- package/dist/server/services/settings.d.ts.map +1 -1
- package/dist/server/services/settings.js +21 -0
- package/dist/server/services/settings.js.map +1 -1
- package/dist/server/services/terminal/pty-manager.d.ts +5 -51
- package/dist/server/services/terminal/pty-manager.d.ts.map +1 -1
- package/dist/server/services/terminal/pty-manager.js +63 -102
- 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/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 -338
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +74 -2106
- 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 +507 -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 +67 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/hooks/bouncer.sh +11 -4
- package/package.json +7 -2
- package/server/README.md +176 -159
- package/server/cli/headless/claude-invoker.ts +740 -133
- package/server/cli/headless/index.ts +7 -1
- package/server/cli/headless/output-utils.test.ts +225 -0
- package/server/cli/headless/prompt-utils.ts +37 -5
- package/server/cli/headless/runner.ts +55 -8
- package/server/cli/headless/stall-assessor.test.ts +165 -0
- package/server/cli/headless/stall-assessor.ts +478 -22
- package/server/cli/headless/tool-watchdog.test.ts +429 -0
- package/server/cli/headless/tool-watchdog.ts +398 -0
- package/server/cli/headless/types.ts +93 -1
- package/server/cli/improvisation-session-manager.ts +1133 -145
- package/server/index.ts +5 -14
- package/server/mcp/README.md +59 -67
- package/server/mcp/bouncer-integration.test.ts +161 -0
- package/server/mcp/bouncer-integration.ts +28 -0
- package/server/mcp/security-audit.ts +12 -8
- package/server/mcp/security-patterns.test.ts +258 -0
- package/server/mcp/security-patterns.ts +8 -2
- package/server/routes/improvise.ts +6 -6
- package/server/services/analytics.ts +26 -4
- package/server/services/platform.test.ts +0 -10
- package/server/services/platform.ts +16 -11
- package/server/services/sandbox-utils.ts +78 -0
- package/server/services/settings.ts +25 -0
- package/server/services/terminal/pty-manager.ts +68 -129
- package/server/services/websocket/autocomplete.test.ts +194 -0
- package/server/services/websocket/file-explorer-handlers.ts +587 -0
- 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.test.ts +1 -1
- package/server/services/websocket/handler.ts +90 -2421
- package/server/services/websocket/index.ts +1 -1
- package/server/services/websocket/session-handlers.ts +574 -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 +145 -4
- package/bin/release.sh +0 -110
- package/dist/server/services/terminal/tmux-manager.d.ts +0 -82
- package/dist/server/services/terminal/tmux-manager.d.ts.map +0 -1
- package/dist/server/services/terminal/tmux-manager.js +0 -352
- package/dist/server/services/terminal/tmux-manager.js.map +0 -1
- package/server/services/terminal/tmux-manager.ts +0 -426
package/PRIVACY.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Mstro Privacy Policy
|
|
2
|
+
|
|
3
|
+
**Effective Date:** February 2026
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Mstro, Inc. ("we", "us", "our") is committed to protecting your privacy. This Privacy Policy explains how we collect, use, and safeguard information when you use the Mstro CLI and related services.
|
|
8
|
+
|
|
9
|
+
## Information We Collect
|
|
10
|
+
|
|
11
|
+
### 1. Account Information
|
|
12
|
+
When you create an account, we collect:
|
|
13
|
+
- Email address
|
|
14
|
+
- Name (optional)
|
|
15
|
+
- Device identifiers (for authentication)
|
|
16
|
+
|
|
17
|
+
### 2. Telemetry Data (Anonymous)
|
|
18
|
+
By default, Mstro collects anonymous telemetry to improve the software:
|
|
19
|
+
|
|
20
|
+
**Error Reporting (via Sentry):**
|
|
21
|
+
- Stack traces and error messages
|
|
22
|
+
- Mstro version and environment
|
|
23
|
+
- Operating system and architecture
|
|
24
|
+
- Node.js version
|
|
25
|
+
|
|
26
|
+
**Usage Analytics (via PostHog):**
|
|
27
|
+
- Feature usage patterns
|
|
28
|
+
- Session duration
|
|
29
|
+
- Command frequency
|
|
30
|
+
|
|
31
|
+
**What we DO NOT collect:**
|
|
32
|
+
- File contents or source code
|
|
33
|
+
- API keys or credentials
|
|
34
|
+
- Personal identifying information in error reports
|
|
35
|
+
- IP addresses (stripped before storage)
|
|
36
|
+
|
|
37
|
+
### 3. Session Data
|
|
38
|
+
When using mstro.app:
|
|
39
|
+
- Orchestra configurations
|
|
40
|
+
- Session metadata
|
|
41
|
+
- Connection timestamps
|
|
42
|
+
|
|
43
|
+
## How to Opt Out of Telemetry
|
|
44
|
+
|
|
45
|
+
You can disable all telemetry at any time:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
mstro telemetry off
|
|
49
|
+
|
|
50
|
+
# Or via environment variable
|
|
51
|
+
export MSTRO_TELEMETRY=0
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
When telemetry is disabled:
|
|
55
|
+
- No error reports are sent to Sentry
|
|
56
|
+
- No usage analytics are sent to PostHog
|
|
57
|
+
- Core functionality remains unchanged
|
|
58
|
+
|
|
59
|
+
## How We Use Your Information
|
|
60
|
+
|
|
61
|
+
We use collected information to:
|
|
62
|
+
- Provide and maintain the Mstro service
|
|
63
|
+
- Identify and fix bugs and crashes
|
|
64
|
+
- Improve software performance and features
|
|
65
|
+
- Communicate service updates and changes
|
|
66
|
+
- Ensure security and prevent abuse
|
|
67
|
+
|
|
68
|
+
## Data Sharing
|
|
69
|
+
|
|
70
|
+
We do not sell your personal information. We may share data with:
|
|
71
|
+
|
|
72
|
+
- **Service Providers:** Third-party services that help operate Mstro (e.g., Sentry for error tracking, PostHog for analytics)
|
|
73
|
+
- **Legal Requirements:** When required by law or to protect our rights
|
|
74
|
+
- **Business Transfers:** In connection with a merger or acquisition
|
|
75
|
+
|
|
76
|
+
## Data Retention
|
|
77
|
+
|
|
78
|
+
- **Account Data:** Retained while your account is active
|
|
79
|
+
- **Telemetry Data:** Retained for up to 90 days
|
|
80
|
+
- **Error Reports:** Retained for up to 30 days
|
|
81
|
+
|
|
82
|
+
## Data Security
|
|
83
|
+
|
|
84
|
+
We implement appropriate security measures including:
|
|
85
|
+
- Encryption in transit (TLS/HTTPS)
|
|
86
|
+
- Secure credential storage (chmod 600)
|
|
87
|
+
- Regular security audits
|
|
88
|
+
- Minimal data collection principles
|
|
89
|
+
|
|
90
|
+
## Your Rights
|
|
91
|
+
|
|
92
|
+
Depending on your jurisdiction, you may have rights to:
|
|
93
|
+
- Access your personal data
|
|
94
|
+
- Correct inaccurate data
|
|
95
|
+
- Delete your data
|
|
96
|
+
- Export your data
|
|
97
|
+
- Opt out of data collection
|
|
98
|
+
|
|
99
|
+
To exercise these rights, contact us at the information below.
|
|
100
|
+
|
|
101
|
+
## Children's Privacy
|
|
102
|
+
|
|
103
|
+
Mstro is not intended for users under 13 years of age. We do not knowingly collect information from children.
|
|
104
|
+
|
|
105
|
+
## International Users
|
|
106
|
+
|
|
107
|
+
Mstro is operated from the United States. By using the service, you consent to the transfer of your information to the United States.
|
|
108
|
+
|
|
109
|
+
## Changes to This Policy
|
|
110
|
+
|
|
111
|
+
We may update this Privacy Policy periodically. We will notify users of significant changes through the CLI or our website.
|
|
112
|
+
|
|
113
|
+
## Open Source
|
|
114
|
+
|
|
115
|
+
Mstro CLI is open source under the MIT License. You can review the code at:
|
|
116
|
+
https://github.com/mstro-app/mstro
|
|
117
|
+
|
|
118
|
+
## Contact Us
|
|
119
|
+
|
|
120
|
+
For privacy-related questions or concerns:
|
|
121
|
+
- Website: https://mstro.app
|
|
122
|
+
- GitHub: https://github.com/mstro-app/mstro/issues
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
package/README.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# mstro
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Run [Claude Code](https://docs.anthropic.com/en/docs/claude-code) from any browser. The CLI runs locally on your machine and streams live sessions to [mstro.app](https://mstro.app) via a secure WebSocket relay.
|
|
4
4
|
|
|
5
|
-
**mstro**
|
|
6
|
-
|
|
7
|
-
**Get started at [mstro.app](https://mstro.app)** — create an account, then install this CLI to connect your machine.
|
|
5
|
+
**mstro** runs on your laptop, cloud VM, or CI server and connects to the mstro.app web interface. You write prompts in the browser, Claude Code runs in your terminal.
|
|
8
6
|
|
|
9
7
|
## How It Works
|
|
10
8
|
|
|
@@ -14,7 +12,7 @@ Browser (mstro.app) <--WebSocket--> Platform Server (relay) <--WebSocket-->
|
|
|
14
12
|
Claude Code CLI
|
|
15
13
|
```
|
|
16
14
|
|
|
17
|
-
1. `mstro` starts a local server and connects to the mstro.app platform
|
|
15
|
+
1. `mstro` starts a local server and connects to the mstro.app platform
|
|
18
16
|
2. You open [mstro.app](https://mstro.app) in any browser and see your connected machine
|
|
19
17
|
3. Prompts you send in the browser are relayed to your machine
|
|
20
18
|
4. Claude Code runs locally with full access to your project files
|
|
@@ -33,19 +31,25 @@ Requires [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed
|
|
|
33
31
|
## Quick Start
|
|
34
32
|
|
|
35
33
|
```bash
|
|
36
|
-
mstro
|
|
37
|
-
mstro # Start mstro in your project directory
|
|
34
|
+
mstro # Logs in automatically on first run, then starts the server
|
|
38
35
|
```
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
Or without installing globally:
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
```bash
|
|
40
|
+
npx mstro-app # Same thing — login + launch in one command
|
|
41
|
+
```
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
On first run, mstro will:
|
|
44
|
+
1. Open your browser to authenticate with your mstro.app account
|
|
45
|
+
2. Offer to set up the **Security Bouncer** — say yes
|
|
46
|
+
3. Connect to the platform
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
Then open [mstro.app](https://mstro.app) in your browser. Your machine appears as a connected workspace. Start prompting.
|
|
47
49
|
|
|
48
|
-
|
|
50
|
+
## Security Bouncer
|
|
51
|
+
|
|
52
|
+
The Bouncer automatically approves or blocks Claude Code tool calls so you don't have to. It installs as a hook at `~/.claude/hooks/bouncer.sh` and applies to all Claude Code sessions.
|
|
49
53
|
|
|
50
54
|
**Mstro sessions (headless)** get the full 2-layer system:
|
|
51
55
|
|
|
@@ -64,22 +68,19 @@ The bouncer is set up automatically on first run. To reconfigure or install manu
|
|
|
64
68
|
mstro configure-hooks
|
|
65
69
|
```
|
|
66
70
|
|
|
67
|
-
This installs a hook at `~/.claude/hooks/bouncer.sh` and registers it in `~/.claude/settings.json`.
|
|
68
|
-
|
|
69
|
-
Set `BOUNCER_USE_AI=false` to disable the AI analysis layer (pattern matching only).
|
|
70
|
-
|
|
71
71
|
## CLI Reference
|
|
72
72
|
|
|
73
73
|
### Commands
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
mstro # Start
|
|
77
|
-
mstro login #
|
|
76
|
+
mstro # Start mstro (logs in automatically if needed)
|
|
77
|
+
mstro login # Re-authenticate or switch accounts
|
|
78
78
|
mstro logout # Sign out
|
|
79
79
|
mstro whoami # Show current user and device info
|
|
80
80
|
mstro status # Show connection and auth status
|
|
81
81
|
mstro setup-terminal # Enable web terminal (compiles native module)
|
|
82
82
|
mstro configure-hooks # Install/reconfigure Security Bouncer
|
|
83
|
+
mstro telemetry [on|off] # Show/toggle anonymous telemetry
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
### Options
|
|
@@ -89,7 +90,6 @@ mstro configure-hooks # Install/reconfigure Security Bouncer
|
|
|
89
90
|
| `-p, --port <port>` | Start on a specific port (default: 4101, auto-increments if busy) |
|
|
90
91
|
| `-w, --working-dir <dir>` | Set working directory |
|
|
91
92
|
| `-v, --verbose` | Verbose output |
|
|
92
|
-
| `--dev` | Connect to local platform at localhost:4102 |
|
|
93
93
|
| `--version` | Show version |
|
|
94
94
|
| `--help` | Show help |
|
|
95
95
|
|
|
@@ -98,11 +98,11 @@ mstro configure-hooks # Install/reconfigure Security Bouncer
|
|
|
98
98
|
Run multiple mstro instances for different projects. Each auto-selects an available port:
|
|
99
99
|
|
|
100
100
|
```
|
|
101
|
-
$ mstro # Project A
|
|
102
|
-
$ mstro # Project B
|
|
101
|
+
$ mstro # Project A
|
|
102
|
+
$ mstro # Project B
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
Each instance appears as a separate
|
|
105
|
+
Each instance appears as a separate workspace in the web interface.
|
|
106
106
|
|
|
107
107
|
## Environment Variables
|
|
108
108
|
|
|
@@ -110,6 +110,7 @@ Each instance appears as a separate orchestra in the web interface.
|
|
|
110
110
|
|----------|-------------|
|
|
111
111
|
| `PORT` | Override server port |
|
|
112
112
|
| `BOUNCER_USE_AI` | Set to `false` to disable AI analysis layer |
|
|
113
|
+
| `MSTRO_TELEMETRY` | Set to `0` to disable telemetry |
|
|
113
114
|
| `PLATFORM_URL` | Platform server URL (default: `https://api.mstro.app`) |
|
|
114
115
|
|
|
115
116
|
## Config Files
|
|
@@ -129,7 +130,7 @@ mstro stores config in `~/.mstro/`:
|
|
|
129
130
|
|
|
130
131
|
### Optional: Web Terminal
|
|
131
132
|
|
|
132
|
-
The web terminal feature requires a native module (`node-pty`). mstro works without it
|
|
133
|
+
The web terminal feature requires a native module (`node-pty`). mstro works without it — you just won't have the terminal tab in the browser.
|
|
133
134
|
|
|
134
135
|
On first run, mstro will automatically attempt to compile `node-pty`. If your system has build tools installed, it just works. If not, mstro will let you know what to install:
|
|
135
136
|
|
package/bin/commands/login.js
CHANGED
|
@@ -143,7 +143,7 @@ function openBrowser(url) {
|
|
|
143
143
|
/**
|
|
144
144
|
* Request device code from platform
|
|
145
145
|
*/
|
|
146
|
-
async function requestDeviceCode(clientId, platformUrl) {
|
|
146
|
+
async function requestDeviceCode(clientId, platformUrl, force = false) {
|
|
147
147
|
const machineHostname = hostname();
|
|
148
148
|
const osType = type().toLowerCase();
|
|
149
149
|
const cpuArch = arch();
|
|
@@ -158,6 +158,7 @@ async function requestDeviceCode(clientId, platformUrl) {
|
|
|
158
158
|
osType,
|
|
159
159
|
cpuArch,
|
|
160
160
|
nodeVersion,
|
|
161
|
+
...(force ? { force: true } : {}),
|
|
161
162
|
}),
|
|
162
163
|
});
|
|
163
164
|
|
|
@@ -235,22 +236,78 @@ async function pollForAuth(deviceCode, interval, platformUrl, maxAttempts = 180)
|
|
|
235
236
|
throw new Error('Authorization timed out. Please try again.');
|
|
236
237
|
}
|
|
237
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Deregister old device before force re-auth
|
|
241
|
+
*/
|
|
242
|
+
async function deregisterOldDevice(platformUrl) {
|
|
243
|
+
const existingCreds = getCredentials();
|
|
244
|
+
if (!existingCreds?.token) return;
|
|
245
|
+
try {
|
|
246
|
+
await fetch(`${platformUrl}/api/auth/device/deregister`, {
|
|
247
|
+
method: 'POST',
|
|
248
|
+
headers: {
|
|
249
|
+
'Content-Type': 'application/json',
|
|
250
|
+
'Authorization': `Bearer ${existingCreds.token}`,
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
} catch {
|
|
254
|
+
// Deregister failed (e.g. network issue), force flag on request will handle it
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Run the device code authorization flow. Throws on failure.
|
|
260
|
+
*/
|
|
261
|
+
async function runDeviceCodeFlow(clientId, platformUrl, forceReauth) {
|
|
262
|
+
const { deviceCode, userCode, verificationUrlComplete, interval } = await requestDeviceCode(clientId, platformUrl, forceReauth);
|
|
263
|
+
|
|
264
|
+
log(`Your authorization code: ${userCode}`, colors.bold);
|
|
265
|
+
log('');
|
|
266
|
+
log('Opening browser to complete login...', colors.dim);
|
|
267
|
+
log(` If browser doesn't open, visit: ${verificationUrlComplete}`, colors.dim);
|
|
268
|
+
log('');
|
|
269
|
+
|
|
270
|
+
openBrowser(verificationUrlComplete);
|
|
271
|
+
|
|
272
|
+
log(' Waiting for authorization', colors.dim);
|
|
273
|
+
process.stdout.write(' ');
|
|
274
|
+
|
|
275
|
+
const result = await pollForAuth(deviceCode, interval, platformUrl);
|
|
276
|
+
|
|
277
|
+
const credentials = {
|
|
278
|
+
token: result.accessToken,
|
|
279
|
+
userId: result.user.id,
|
|
280
|
+
email: result.user.email,
|
|
281
|
+
name: result.user.name,
|
|
282
|
+
clientId,
|
|
283
|
+
createdAt: new Date().toISOString(),
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
saveCredentials(credentials);
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
|
|
238
290
|
/**
|
|
239
291
|
* Main login command
|
|
292
|
+
*
|
|
293
|
+
* @param {string[]} args - CLI arguments
|
|
294
|
+
* @param {object} options
|
|
295
|
+
* @param {boolean} options.inline - When true, called from startServer() auto-login:
|
|
296
|
+
* skips "already logged in" check, omits post-login tips, and throws on failure
|
|
297
|
+
* instead of calling process.exit(1).
|
|
240
298
|
*/
|
|
241
|
-
export async function login(args = []) {
|
|
299
|
+
export async function login(args = [], options = {}) {
|
|
300
|
+
const { inline = false } = options;
|
|
242
301
|
const forceReauth = args.includes('--force') || args.includes('-f');
|
|
243
302
|
const devMode = args.includes('--dev');
|
|
244
303
|
const platformUrl = devMode ? DEV_PLATFORM_URL : PROD_PLATFORM_URL;
|
|
245
304
|
|
|
246
|
-
log('\n Mstro Login\n', colors.bold + colors.cyan);
|
|
247
|
-
|
|
248
305
|
if (devMode) {
|
|
249
|
-
log(`
|
|
306
|
+
log(`[DEV MODE] Using ${platformUrl}\n`, colors.yellow);
|
|
250
307
|
}
|
|
251
308
|
|
|
252
|
-
// Check if already logged in
|
|
253
|
-
if (isLoggedIn() && !forceReauth) {
|
|
309
|
+
// Check if already logged in (skip when called inline — caller already checked)
|
|
310
|
+
if (!inline && isLoggedIn() && !forceReauth) {
|
|
254
311
|
const creds = getCredentials();
|
|
255
312
|
log(` Already logged in as ${creds.email}`, colors.green);
|
|
256
313
|
log(` Use "mstro logout" to sign out, or "mstro login --force" to re-authenticate.\n`, colors.dim);
|
|
@@ -259,50 +316,36 @@ export async function login(args = []) {
|
|
|
259
316
|
|
|
260
317
|
const clientId = getClientId();
|
|
261
318
|
|
|
262
|
-
|
|
319
|
+
if (forceReauth) {
|
|
320
|
+
await deregisterOldDevice(platformUrl);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
log('Requesting authorization...', colors.dim);
|
|
263
324
|
|
|
264
325
|
try {
|
|
265
|
-
|
|
266
|
-
const { deviceCode, userCode, verificationUrlComplete, interval } = await requestDeviceCode(clientId, platformUrl);
|
|
326
|
+
const result = await runDeviceCodeFlow(clientId, platformUrl, forceReauth);
|
|
267
327
|
|
|
268
|
-
// Step 2: Show code and open browser
|
|
269
328
|
log('');
|
|
270
|
-
log(` Your authorization code: ${userCode}`, colors.bold);
|
|
271
329
|
log('');
|
|
272
|
-
log(
|
|
273
|
-
log(` If browser doesn't open, visit: ${verificationUrlComplete}`, colors.dim);
|
|
330
|
+
log(` Logged in as ${result.user.email}`, colors.bold + colors.green);
|
|
274
331
|
log('');
|
|
275
332
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
log(' Waiting for authorization', colors.dim);
|
|
280
|
-
process.stdout.write(' ');
|
|
281
|
-
|
|
282
|
-
const result = await pollForAuth(deviceCode, interval, platformUrl);
|
|
333
|
+
if (!inline) {
|
|
334
|
+
log(' Run "mstro" to start a machine.', colors.cyan);
|
|
335
|
+
log('');
|
|
283
336
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
saveCredentials(credentials);
|
|
295
|
-
|
|
296
|
-
log('');
|
|
297
|
-
log('');
|
|
298
|
-
log(` Logged in as ${result.user.email}`, colors.bold + colors.green);
|
|
299
|
-
log('');
|
|
300
|
-
log(' This device is now connected to your mstro.app account.', colors.dim);
|
|
301
|
-
log(' Any "mstro" commands will sync with your web dashboard.', colors.dim);
|
|
302
|
-
log('');
|
|
303
|
-
log(' Run "mstro" to start an orchestra.', colors.cyan);
|
|
304
|
-
log('');
|
|
337
|
+
// Check if node-pty is available, show tip if not
|
|
338
|
+
try {
|
|
339
|
+
await import('node-pty');
|
|
340
|
+
} catch {
|
|
341
|
+
log(' Tip: Terminal support requires native compilation.', colors.dim);
|
|
342
|
+
log(' Run "mstro setup-terminal" to enable web terminal.\n', colors.dim);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
305
345
|
} catch (err) {
|
|
346
|
+
if (inline) {
|
|
347
|
+
throw err;
|
|
348
|
+
}
|
|
306
349
|
log('');
|
|
307
350
|
log(` Login failed: ${err.message}`, colors.red);
|
|
308
351
|
log('');
|
package/bin/commands/logout.js
CHANGED
|
@@ -8,6 +8,9 @@ import { existsSync, readFileSync, unlinkSync } from 'node:fs';
|
|
|
8
8
|
import { homedir } from 'node:os';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
|
|
11
|
+
const PROD_PLATFORM_URL = 'https://api.mstro.app';
|
|
12
|
+
const DEV_PLATFORM_URL = 'http://localhost:4102';
|
|
13
|
+
|
|
11
14
|
const colors = {
|
|
12
15
|
reset: '\x1b[0m',
|
|
13
16
|
bold: '\x1b[1m',
|
|
@@ -39,10 +42,36 @@ function getCredentials() {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Deregister device from the platform server
|
|
47
|
+
*/
|
|
48
|
+
async function deregisterDevice(token, platformUrl) {
|
|
49
|
+
try {
|
|
50
|
+
const response = await fetch(`${platformUrl}/api/auth/device/deregister`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
'Authorization': `Bearer ${token}`,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
const data = await response.json().catch(() => ({}));
|
|
60
|
+
log(` Warning: Could not deregister device from server: ${data.error || response.statusText}`, colors.yellow);
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
// Network error - proceed with local logout anyway
|
|
64
|
+
log(' Warning: Could not reach server to deregister device. Local credentials will still be removed.', colors.yellow);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
42
68
|
/**
|
|
43
69
|
* Main logout command
|
|
44
70
|
*/
|
|
45
|
-
export async function logout() {
|
|
71
|
+
export async function logout(args = []) {
|
|
72
|
+
const devMode = Array.isArray(args) && args.includes('--dev');
|
|
73
|
+
const platformUrl = devMode ? DEV_PLATFORM_URL : PROD_PLATFORM_URL;
|
|
74
|
+
|
|
46
75
|
log('\n Mstro Logout\n', colors.bold + colors.cyan);
|
|
47
76
|
|
|
48
77
|
const creds = getCredentials();
|
|
@@ -56,6 +85,11 @@ export async function logout() {
|
|
|
56
85
|
const email = creds.email;
|
|
57
86
|
|
|
58
87
|
try {
|
|
88
|
+
// Deregister device from server so it can be re-registered later
|
|
89
|
+
if (creds.token) {
|
|
90
|
+
await deregisterDevice(creds.token, platformUrl);
|
|
91
|
+
}
|
|
92
|
+
|
|
59
93
|
// Delete credentials file
|
|
60
94
|
if (existsSync(CREDENTIALS_FILE)) {
|
|
61
95
|
unlinkSync(CREDENTIALS_FILE);
|
package/bin/commands/status.js
CHANGED
|
@@ -187,7 +187,7 @@ export async function status() {
|
|
|
187
187
|
|
|
188
188
|
// Quick commands
|
|
189
189
|
log(' Commands', colors.bold);
|
|
190
|
-
log(' mstro Start
|
|
190
|
+
log(' mstro Start a machine', colors.dim);
|
|
191
191
|
log(' mstro login Sign in to your account', colors.dim);
|
|
192
192
|
log(' mstro logout Sign out', colors.dim);
|
|
193
193
|
log(' mstro whoami Show account details', colors.dim);
|